AI API
Every AI action (86) and data model (29): endpoints, scopes, input, preconditions, events and examples.
Era, your assistant, and the AI agents you save — they work across every module.
Module code ai · 86 actions · 29 data models · 76 events. A key or token never does more here than the person behind it can; row-level security applies exactly as in the app. Scopes: ai (everything), ai:read (read only) or ai:<capability>.
Resources
| Resource | Table | List and read | POST | PATCH | DELETE |
|---|---|---|---|---|---|
ai_agents | ai_agent | /api/v1/ai_agents | |||
ai_budgets | ai_budget | /api/v1/ai_budgets | |||
ai_conversations | ai_conversation | /api/v1/ai_conversations | |||
ai_messages | ai_message | /api/v1/ai_messages | |||
ai_model_policies | ai_model_policy | /api/v1/ai_model_policies | |||
ai_providers | ai_provider | /api/v1/ai_providers | |||
ai_runs | ai_run | /api/v1/ai_runs | |||
ai_skill_releases | ai_skill_release | /api/v1/ai_skill_releases | |||
ai_skill_runs | ai_skill_run | /api/v1/ai_skill_runs | |||
ai_skill_versions | ai_skill_version | /api/v1/ai_skill_versions | |||
ai_source_choices | ai_source_choice | /api/v1/ai_source_choices | |||
ai_tasks | ai_task | /api/v1/ai_tasks | |||
ai_template_installs | ai_template_install | /api/v1/ai_template_installs | |||
ai_usages | ai_usage | /api/v1/ai_usages | |||
brain_bindings | brain_binding | /api/v1/brain_bindings | |||
brain_erasures | brain_erasure | /api/v1/brain_erasures | |||
brain_fact_reviews | brain_fact_review | /api/v1/brain_fact_reviews | |||
brain_insights | brain_insight | /api/v1/brain_insights | |||
brains | brain | /api/v1/brains | ai.create_brain | ||
computer_folders | computer_folder | /api/v1/computer_folders | |||
computer_machines | computer_machine | /api/v1/computer_machines | |||
computer_policies | computer_policy | /api/v1/computer_policies | |||
decide_decisions | decide_decision | /api/v1/decide_decisions | |||
era_action_caps | era_action_cap | /api/v1/era_action_caps | |||
era_chat_members | era_chat_member | /api/v1/era_chat_members | |||
era_chat_seens | era_chat_seen | /api/v1/era_chat_seens | |||
era_chat_shares | era_chat_share | /api/v1/era_chat_shares | |||
era_learnings | era_learning | /api/v1/era_learnings | |||
knowledge_bases | knowledge_base | /api/v1/knowledge_bases | ai.create_knowledge_base |
Lists take limit (up to 200), cursor, order (e.g. -created_at), fields and q; every other query parameter is a column filter: ?status=paid, ?total[gte]=100, ?id[in]=a,b, ?x=null.
Actions
| Action | Needs | What it does |
|---|---|---|
ai.archive_brain | ai:manage | Archive a brain |
ai.archive_knowledge_base | ai:manage | Archive a knowledge space |
ai.assign_task | ai:write | Hand a task over |
ai.bind_brain | ai:manage | Give a brain to an Era, workflow or voice agent |
ai.check_budget | ai:read | Check the AI budget |
ai.clear_budget | ai:manage | Remove an AI budget |
ai.close_code_session | ai:handle | Close the coding session |
ai.complete_task | ai:write | Complete a task |
ai.connect_subscription | ai:write | Connect my own AI subscription |
ai.create_agent | ai:manage | Create an agent |
ai.create_brain | ai:manage | Create a brain |
ai.create_knowledge_base | ai:manage | Add a knowledge space |
ai.create_task | ai:write | Create a task |
ai.decide_computer_step | ai:handle | Approve or refuse a computer step |
ai.decide_learning | ai:write | Answer what Era asked to keep |
ai.delete_agent | ai:delete | Delete an agent |
ai.delete_computer | ai:handle | Delete my cloud computer |
ai.delete_conversation | ai:delete | Delete a conversation |
ai.delete_task | ai:delete | Delete a task |
ai.disconnect_subscription | ai:write | Disconnect my subscription |
ai.erase_brain_fact | ai:manage | Permanently erase something Era learned |
ai.erase_brain_person | ai:manage | Erase everything Era learned about a person |
ai.escalate_approval | ai:read | Escalate a waiting approval |
ai.evaluate_skill | ai:write | Record a skill evaluation |
ai.forget_computer_folder | ai:handle | Forget a folder |
ai.forget_learning | ai:write | Forget something ("bunu unut") |
ai.link_engine_agent | ai:manage | Link an agent to an assistant |
ai.mark_chat_seen | ai:read | Open a shared chat |
ai.open_code_session | ai:handle | Start a coding session |
ai.pause_computer | ai:handle | Turn off my cloud computer |
ai.pause_computer_session | ai:handle | Pause a computer task |
ai.promote_skill | ai:manage | Promote a skill version |
ai.propose_learning | ai:write | Ask to remember something |
ai.provision_computer | ai:handle | Set up my cloud computer |
ai.record_brain_insight | ai:write | Record an insight |
ai.record_code_session | ai:handle | Record a coding turn |
ai.record_computer_file | ai:handle | Save a computer file |
ai.record_computer_frame | ai:handle | Record a live frame |
ai.record_computer_machine | ai:handle | Record cloud computer state |
ai.record_computer_progress | ai:handle | Record computer progress |
ai.record_decide_outcome | ai:write | Confirm or correct one of Era’s decisions |
ai.record_plan_limits | ai:read | Record a subscription’s plan limits |
ai.record_provider_check | ai:manage | Record a provider health check |
ai.record_provider_health | ai:handle | Record a scheduled provider health check |
ai.record_skill_run | ai:read | Record a skill run |
ai.record_subscription_state | ai:read | Record a subscription’s state |
ai.record_template_install | ai:write | Record a marketplace install |
ai.record_turn | ai:write | Record a turn |
ai.record_usage | ai:read | Record AI usage |
ai.refile_brain_fact | ai:write | Re-file something Era learned |
ai.remind_task | ai:handle | Send a task reminder |
ai.remove_provider | ai:manage | Remove an AI provider |
ai.reopen_task | ai:write | Reopen a task |
ai.resolve_erasure_candidate | ai:manage | Decide a possible match of an erasure request |
ai.resume_computer_session | ai:handle | Resume a computer task |
ai.review_brain_fact | ai:write | Correct, forget or keep private something Era learned |
ai.run_agent | ai:handle | Run an agent |
ai.save_computer_folder | ai:handle | Remember a folder |
ai.save_computer_policy | ai:manage | Save computer rules |
ai.set_action_cap | ai:write | Set a daily allowance for Era |
ai.set_agent_enabled | ai:manage | Switch an agent on or off |
ai.set_brain_insight_status | ai:write | Mark an insight |
ai.set_budget | ai:manage | Set an AI budget |
ai.set_chat_member | ai:write | Share a chat with a person |
ai.set_connection_share | ai:write | Choose who may use a connection |
ai.set_model_policy | ai:manage | Choose a model for a kind of work |
ai.set_provider | ai:manage | Save an AI provider |
ai.set_skill_policy | ai:manage | Set a skill’s permissions |
ai.set_skill_release | ai:manage | Pause, resume or record an install |
ai.set_source_choice | ai:write | Choose where AI runs |
ai.set_subscription_use | ai:write | Choose where my subscription is used |
ai.share_chat | ai:write | Share a chat |
ai.snapshot_skill | ai:write | Save a skill version |
ai.start_computer | ai:handle | Turn on my cloud computer |
ai.start_computer_session | ai:handle | Give the computer a task |
ai.start_conversation | ai:write | Start a conversation |
ai.steer_computer_session | ai:handle | Tell a running computer task something |
ai.stop_all_computer_sessions | ai:handle | Emergency stop |
ai.stop_computer_session | ai:handle | Stop a computer task |
ai.unbind_brain | ai:manage | Take a brain away |
ai.uninstall_skill | ai:delete | Uninstall a skill |
ai.update_agent | ai:manage | Change an agent |
ai.update_brain | ai:manage | Change a brain |
ai.update_knowledge_base | ai:manage | Change a knowledge space |
ai.update_task | ai:write | Change a task |
ai.use_action_cap | ai:read | Use Era’s daily allowance |
ai.archive_brain
Archive a brain — Stops using a brain; what it knows stays in its history. The company brain stays.
Needs ai:manage · removes or cannot be undone · asks a person to confirm when Era runs it
https://app.getera.io/api/v1/brains/actions/archive_brain- Canonical address:
POST /api/v1/actions/ai.archive_brain
Input
| Field | Type | Required | Notes |
|---|---|---|---|
id | uuid | yes | Brain |
Preconditions
The action is refused with 409 and one of these codes:
| Code | Refused when |
|---|---|
brain_not_found | The brain must exist in this workspace. |
not_your_brain | Someone else’s personal brain is theirs to archive. |
archived | It is already archived. |
default_brain | The company brain cannot be archived. |
Events it publishes: ai.brain_archived
What it writes: brain (update) — Archives the brain; brain_binding (delete) — Disconnects it from every Era and workflow
curl -X POST https://app.getera.io/api/v1/brains/actions/archive_brain \
-H "Authorization: Bearer $ERA_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{"id":"ID_ID"}'{
"ok": true,
"result": "…",
"events": [
"ai.brain_archived"
]
}import { createEra } from "@getera/sdk"
const era = createEra({ apiKey: process.env.ERA_API_KEY })
const res = await era.brains.archiveBrain({
id: "ID_ID"
})era brains archive_brain \
--id "ID_ID"{
"name": "era__ai__archive_brain",
"arguments": {
"id": "ID_ID"
}
}Errors: 401 no or expired credential · 403 the credential does not hold ai:manage · 404 the record or module is outside what it may reach · 422 invalid input (problems[]) · 409 brain_not_found, not_your_brain, archived, default_brain · 429 slow down
ai.archive_knowledge_base
Archive a knowledge space — Stops filling and reading a space; what it holds stays in its history.
Needs ai:manage · reaches outside (sends, publishes or charges) · asks a person to confirm when Era runs it
https://app.getera.io/api/v1/knowledge_bases/actions/archive_knowledge_base- Canonical address:
POST /api/v1/actions/ai.archive_knowledge_base
Input
| Field | Type | Required | Notes |
|---|---|---|---|
id | uuid | yes | Space |
Preconditions
The action is refused with 409 and one of these codes:
| Code | Refused when |
|---|---|
knowledge_base_not_found | The space must exist in this workspace. |
archived | It is already archived. |
default_knowledge_base | The brain’s main space stays until another one is the main one. |
Events it publishes: ai.knowledge_base_archived
What it writes: knowledge_base (update) — Archives the space; brain_binding (update) — Takes it out of every connection that named it
curl -X POST https://app.getera.io/api/v1/knowledge_bases/actions/archive_knowledge_base \
-H "Authorization: Bearer $ERA_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{"id":"ID_ID"}'{
"ok": true,
"result": "…",
"events": [
"ai.knowledge_base_archived"
]
}import { createEra } from "@getera/sdk"
const era = createEra({ apiKey: process.env.ERA_API_KEY })
const res = await era.knowledgeBases.archiveKnowledgeBase({
id: "ID_ID"
})era knowledge_bases archive_knowledge_base \
--id "ID_ID"{
"name": "era__ai__archive_knowledge_base",
"arguments": {
"id": "ID_ID"
}
}Errors: 401 no or expired credential · 403 the credential does not hold ai:manage · 404 the record or module is outside what it may reach · 422 invalid input (problems[]) · 409 knowledge_base_not_found, archived, default_knowledge_base · 429 slow down
ai.assign_task
Hand a task over — Gives the task to a person or an agent, with a note. Handing it to an agent wakes it; an agent hands back the same way.
Needs ai:write · changes data
https://app.getera.io/api/v1/ai_tasks/{id}/actions/assign_task- Canonical address:
POST /api/v1/actions/ai.assign_task
Input
| Field | Type | Required | Notes |
|---|---|---|---|
id | uuid | yes | Filled from the path {id} · Task · id of ai_task |
assigneeUserId | uuid | Person · id of app_user | |
assigneeAgentId | uuid | Agent · id of ai_agent | |
note | string | Note · max 2000 |
Preconditions
The action is refused with 409 and one of these codes:
| Code | Refused when |
|---|---|
not_found | The task must exist in this workspace. |
not_member | The person must be a member of this workspace. |
unknown_agent | The agent must exist in this workspace. |
agent_disabled | A switched-off agent cannot be handed a task. |
Events it publishes: ai.task_assigned, ai.agent_requested
What it writes: ai_task (update) — Moves the task and appends the handoff
curl -X POST https://app.getera.io/api/v1/ai_tasks/AI_TASK_ID/actions/assign_task \
-H "Authorization: Bearer $ERA_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{"assigneeUserId":"APP_USER_ID"}'{
"ok": true,
"result": "…",
"events": [
"ai.task_assigned",
"ai.agent_requested"
]
}import { createEra } from "@getera/sdk"
const era = createEra({ apiKey: process.env.ERA_API_KEY })
const res = await era.aiTasks.assignTask("AI_TASK_ID", {
assigneeUserId: "APP_USER_ID"
})era ai_tasks assign_task AI_TASK_ID \
--assignee-user-id "APP_USER_ID"{
"name": "era__ai__assign_task",
"arguments": {
"id": "AI_TASK_ID",
"assigneeUserId": "APP_USER_ID"
}
}Errors: 401 no or expired credential · 403 the credential does not hold ai:write · 404 the record or module is outside what it may reach · 422 invalid input (problems[]) · 409 not_found, not_member, unknown_agent, agent_disabled · 429 slow down
ai.bind_brain
Give a brain to an Era, workflow or voice agent — Chooses which brain and spaces it knows from, and whether it may teach the brain what it learns.
Needs ai:manage · changes data
https://app.getera.io/api/v1/brain_bindings/actions/bind_brain- Canonical address:
POST /api/v1/actions/ai.bind_brain
Input
| Field | Type | Required | Notes |
|---|---|---|---|
subjectType | string | yes | For · agent · workflow · voice_agent · era_chat · meeting · team · role · max 20 |
subjectId | string | yes | Which one · max 120 |
brainId | uuid | yes | Brain |
knowledgeBaseIds | object / array | Spaces (empty = all) | |
access | string (enum) | Access · Allowed values: read, read_write |
Preconditions
The action is refused with 409 and one of these codes:
| Code | Refused when |
|---|---|
bad_subject | It names an Era, workflow, voice agent, meeting or Era chat. |
brain_not_found | The brain must exist in this workspace. |
not_your_brain | Someone else’s personal brain is theirs. |
archived | An archived brain is not given out. |
personal_brain | A personal brain serves only its owner’s own chat. |
agent_not_found | The Era must exist. |
subject_not_found | A team or role must exist in this workspace. |
knowledge_base_not_in_brain | The spaces must belong to that brain. |
Events it publishes: ai.brain_bound
What it writes: brain_binding (upsert) — Connects the brain (or changes its spaces and access)
curl -X POST https://app.getera.io/api/v1/brain_bindings/actions/bind_brain \
-H "Authorization: Bearer $ERA_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{"subjectType":"For","subjectId":"Which one","brainId":"BRAIN_ID"}'{
"ok": true,
"result": "…",
"events": [
"ai.brain_bound"
]
}import { createEra } from "@getera/sdk"
const era = createEra({ apiKey: process.env.ERA_API_KEY })
const res = await era.brainBindings.bindBrain({
subjectType: "For",
subjectId: "Which one",
brainId: "BRAIN_ID"
})era brain_bindings bind_brain \
--subject-type "For" \
--subject-id "Which one" \
--brain-id "BRAIN_ID"{
"name": "era__ai__bind_brain",
"arguments": {
"subjectType": "For",
"subjectId": "Which one",
"brainId": "BRAIN_ID"
}
}Errors: 401 no or expired credential · 403 the credential does not hold ai:manage · 404 the record or module is outside what it may reach · 422 invalid input (problems[]) · 409 bad_subject, brain_not_found, not_your_brain, archived, personal_brain, agent_not_found, subject_not_found, knowledge_base_not_in_brain · 429 slow down
ai.check_budget
Check the AI budget — Answers whether a run may start, with the spend per cap. Era’s front door calls it before every turn; it raises the alert when a threshold is crossed.
Needs ai:read · changes data
https://app.getera.io/api/v1/ai_budgets/actions/check_budget- Canonical address:
POST /api/v1/actions/ai.check_budget
Input
| Field | Type | Required | Notes |
|---|---|---|---|
agentId | uuid | Agent · id of ai_agent |
Events it publishes: ai.budget_alert
What it writes: ai_budget (update) — Stamps the alert key so an alert fires once
curl -X POST https://app.getera.io/api/v1/ai_budgets/actions/check_budget \
-H "Authorization: Bearer $ERA_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{"agentId":"AI_AGENT_ID"}'{
"ok": true,
"result": "…",
"events": [
"ai.budget_alert"
]
}import { createEra } from "@getera/sdk"
const era = createEra({ apiKey: process.env.ERA_API_KEY })
const res = await era.aiBudgets.checkBudget({
agentId: "AI_AGENT_ID"
})era ai_budgets check_budget \
--agent-id "AI_AGENT_ID"{
"name": "era__ai__check_budget",
"arguments": {
"agentId": "AI_AGENT_ID"
}
}Errors: 401 no or expired credential · 403 the credential does not hold ai:read · 404 the record or module is outside what it may reach · 422 invalid input (problems[]) · 429 slow down
ai.clear_budget
Remove an AI budget — Removes the cap. Spending is then unlimited for that scope.
Needs ai:manage · removes or cannot be undone · asks a person to confirm when Era runs it
https://app.getera.io/api/v1/ai_budgets/{id}/actions/clear_budget- Canonical address:
POST /api/v1/actions/ai.clear_budget
Input
| Field | Type | Required | Notes |
|---|---|---|---|
id | uuid | yes | Filled from the path {id} · Budget · id of ai_budget |
Preconditions
The action is refused with 409 and one of these codes:
| Code | Refused when |
|---|---|
not_found | The budget must exist in this workspace. |
Events it publishes: ai.budget_updated
What it writes: ai_budget (delete) — Removes the cap
curl -X POST https://app.getera.io/api/v1/ai_budgets/AI_BUDGET_ID/actions/clear_budget \
-H "Authorization: Bearer $ERA_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{}'{
"ok": true,
"result": "…",
"events": [
"ai.budget_updated"
]
}import { createEra } from "@getera/sdk"
const era = createEra({ apiKey: process.env.ERA_API_KEY })
const res = await era.aiBudgets.clearBudget("AI_BUDGET_ID")era ai_budgets clear_budget AI_BUDGET_ID{
"name": "era__ai__clear_budget",
"arguments": {
"id": "AI_BUDGET_ID"
}
}Errors: 401 no or expired credential · 403 the credential does not hold ai:manage · 404 the record or module is outside what it may reach · 422 invalid input (problems[]) · 409 not_found · 429 slow down
ai.close_code_session
Close the coding session — Ends the live coding session; the next request starts a new one.
Needs ai:handle · changes data
https://app.getera.io/api/v1/actions/ai.close_code_sessionInput
| Field | Type | Required | Notes |
|---|---|---|---|
id | uuid | yes | Session · id of code_session |
Preconditions
The action is refused with 409 and one of these codes:
| Code | Refused when |
|---|---|
not_found | Only an open session of yours can be closed. |
Events it publishes: ai.code_session_closed
What it writes: code_session (update) — Marks it closed
curl -X POST https://app.getera.io/api/v1/actions/ai.close_code_session \
-H "Authorization: Bearer $ERA_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{"id":"CODE_SESSION_ID"}'{
"ok": true,
"result": "…",
"events": [
"ai.code_session_closed"
]
}import { createEra } from "@getera/sdk"
const era = createEra({ apiKey: process.env.ERA_API_KEY })
const res = await era.actions.run("ai.close_code_session", {
id: "CODE_SESSION_ID"
})era ai close_code_session \
--id "CODE_SESSION_ID"{
"name": "era__ai__close_code_session",
"arguments": {
"id": "CODE_SESSION_ID"
}
}Errors: 401 no or expired credential · 403 the credential does not hold ai:handle · 404 the record or module is outside what it may reach · 422 invalid input (problems[]) · 409 not_found · 429 slow down
ai.complete_task
Complete a task — Marks it done. A repeating task writes its next occurrence.
Needs ai:write · changes data
https://app.getera.io/api/v1/ai_tasks/{id}/actions/complete_task- Canonical address:
POST /api/v1/actions/ai.complete_task
Input
| Field | Type | Required | Notes |
|---|---|---|---|
id | uuid | yes | Filled from the path {id} · Task · id of ai_task |
Preconditions
The action is refused with 409 and one of these codes:
| Code | Refused when |
|---|---|
not_found | The task must exist in this workspace. |
already_done | A done task cannot be completed again. |
Events it publishes: ai.task_completed
What it writes: ai_task (update) — Marks it done; ai_task (insert) — Writes the next occurrence of a repeating task
curl -X POST https://app.getera.io/api/v1/ai_tasks/AI_TASK_ID/actions/complete_task \
-H "Authorization: Bearer $ERA_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{}'{
"ok": true,
"result": "…",
"events": [
"ai.task_completed"
]
}import { createEra } from "@getera/sdk"
const era = createEra({ apiKey: process.env.ERA_API_KEY })
const res = await era.aiTasks.completeTask("AI_TASK_ID")era ai_tasks complete_task AI_TASK_ID{
"name": "era__ai__complete_task",
"arguments": {
"id": "AI_TASK_ID"
}
}Errors: 401 no or expired credential · 403 the credential does not hold ai:write · 404 the record or module is outside what it may reach · 422 invalid input (problems[]) · 409 not_found, already_done · 429 slow down
ai.connect_subscription
Connect my own AI subscription — Records a person’s own AI subscription sign-in (Claude, ChatGPT, Antigravity, Grok, Copilot, Cursor …) so their chat, Eras and workflows use their plan first. A cloud sign-in is sealed in the vault; a computer sign-in stays on that computer.
Needs ai:write · changes data
https://app.getera.io/api/v1/ai_providers/actions/connect_subscription- Canonical address:
POST /api/v1/actions/ai.connect_subscription
Input
| Field | Type | Required | Notes |
|---|---|---|---|
provider | string (enum) | yes | Subscription · Allowed values: claude_code, chatgpt, gemini_cli, grok_cli, copilot_cli, cursor_cli, kimi_cli, vibe_cli, opencode_cli, amp_cli, kiro_cli, cline_cli, auggie_cli, google |
execution | string (enum) | yes | Runs · Allowed values: remote, local_device, cloud_computer |
deviceId | string | Computer · max 64 | |
secretRef | string | Vault sign-in · max 64 | |
oauthSecretRef | string | Vault grant · max 64 | |
keyHint | string | Key (masked) · max 40 | |
accountLabel | string | Account · max 160 | |
status | string (enum) | Status · Allowed values: connecting, healthy | |
meta | object / array | Details |
Preconditions
The action is refused with 409 and one of these codes:
| Code | Refused when |
|---|---|
unknown_subscription | Only a subscription the Harness Manager knows, in the places it can run. |
bad_secret_ref | A cloud sign-in must be a vault secret of this workspace. |
device_required | A computer sign-in names the computer. |
Events it publishes: ai.subscription_connected
What it writes: ai_provider (upsert) — Writes the person’s own connection row (never a token)
curl -X POST https://app.getera.io/api/v1/ai_providers/actions/connect_subscription \
-H "Authorization: Bearer $ERA_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{"provider":"claude_code","execution":"remote"}'{
"ok": true,
"result": "…",
"events": [
"ai.subscription_connected"
]
}import { createEra } from "@getera/sdk"
const era = createEra({ apiKey: process.env.ERA_API_KEY })
const res = await era.aiProviders.connectSubscription({
provider: "claude_code",
execution: "remote"
})era ai_providers connect_subscription \
--provider "claude_code" \
--execution "remote"{
"name": "era__ai__connect_subscription",
"arguments": {
"provider": "claude_code",
"execution": "remote"
}
}Errors: 401 no or expired credential · 403 the credential does not hold ai:write · 404 the record or module is outside what it may reach · 422 invalid input (problems[]) · 409 unknown_subscription, bad_secret_ref, device_required · 429 slow down
ai.create_agent
Create an agent — Saves a brief and a tool budget. It arrives switched off.
Needs ai:manage · changes data
https://app.getera.io/api/v1/ai_agents/actions/create_agent- Canonical address:
POST /api/v1/actions/ai.create_agent
Input
| Field | Type | Required | Notes |
|---|---|---|---|
name | string | yes | Name · max 160 |
instructions | string | Instructions · max 20000 | |
description | string | Description · max 2000 | |
model | string | Model · max 120 | |
allowedModules | object / array | Limited to these modules · A list of module codes. Empty means every module its author can already use. | |
wakesOn | object / array | Wakes up on · A list of event names — crm.lead_won, crm.* or *. Empty means it only runs when asked. | |
maxSteps | number | Tool calls per run · min 1 · max 40 |
Preconditions
The action is refused with 409 and one of these codes:
| Code | Refused when |
|---|---|
empty_name | An agent needs a name. |
bad_modules | It may only be limited to modules this platform registers. |
bad_trigger | A wake-up trigger must be an event some module declares. |
Events it publishes: ai.agent_created
What it writes: ai_agent (insert) — Writes the agent
curl -X POST https://app.getera.io/api/v1/ai_agents/actions/create_agent \
-H "Authorization: Bearer $ERA_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{"name":"Name"}'{
"ok": true,
"result": "…",
"events": [
"ai.agent_created"
]
}import { createEra } from "@getera/sdk"
const era = createEra({ apiKey: process.env.ERA_API_KEY })
const res = await era.aiAgents.createAgent({
name: "Name"
})era ai_agents create_agent \
--name "Name"{
"name": "era__ai__create_agent",
"arguments": {
"name": "Name"
}
}Errors: 401 no or expired credential · 403 the credential does not hold ai:manage · 404 the record or module is outside what it may reach · 422 invalid input (problems[]) · 409 empty_name, bad_modules, bad_trigger · 429 slow down
ai.create_brain
Create a brain — A new brain with its own knowledge spaces — for the company, one person, an Era or a voice agent.
Needs ai:manage · changes data
https://app.getera.io/api/v1/brains/actions/create_brain- REST alias:
POST /api/v1/brains - Canonical address:
POST /api/v1/actions/ai.create_brain
Input
| Field | Type | Required | Notes |
|---|---|---|---|
name | string | yes | Name · max 80 |
description | string | What it is for · max 500 | |
kind | string (enum) | Kind · Allowed values: company, personal, team, era, voice, brand, custom | |
scope | string (enum) | Who uses it · Allowed values: workspace, team, era, voice_agent, person | |
scopeRef | uuid | Whose | |
memory | string (enum) | Memory · Allowed values: long, short | |
shortTtlHours | number | Short memory lasts (hours) · min 1 · max 720 | |
embeddingSpace | string (enum) | Where it understands meaning · Allowed values: bge-m3-1024, e5-small-384 | |
learnFrom | object / array | Learns from | |
knowledgeBases | object / array | Knowledge spaces |
Preconditions
The action is refused with 409 and one of these codes:
| Code | Refused when |
|---|---|
empty_name | A brain needs a name. |
name_taken | Brain names are unique in a workspace. |
not_your_brain | A personal brain can only be your own. |
missing_scope_ref | A brain for a team, an Era or a voice agent names which one. |
agent_not_found | An Era’s brain belongs to an Era that exists. |
team_not_found | A team’s brain belongs to a team of this workspace. |
invalid_learn_from | What it learns from is a set of known on/off switches. |
Events it publishes: ai.brain_created
What it writes: brain (insert) — Creates the brain; knowledge_base (insert) — Creates its first knowledge spaces; brain_binding (insert) — A team brain is given to its team
curl -X POST https://app.getera.io/api/v1/brains/actions/create_brain \
-H "Authorization: Bearer $ERA_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{"name":"Name"}'{
"ok": true,
"result": "…",
"events": [
"ai.brain_created"
]
}import { createEra } from "@getera/sdk"
const era = createEra({ apiKey: process.env.ERA_API_KEY })
const res = await era.brains.create({
name: "Name"
})era brains create \
--name "Name"{
"name": "era__ai__create_brain",
"arguments": {
"name": "Name"
}
}Errors: 401 no or expired credential · 403 the credential does not hold ai:manage · 404 the record or module is outside what it may reach · 422 invalid input (problems[]) · 409 empty_name, name_taken, not_your_brain, missing_scope_ref, agent_not_found, team_not_found, invalid_learn_from · 429 slow down
ai.create_knowledge_base
Add a knowledge space — A new space inside a brain — Sales, Product docs, Customer success, Personal notes.
Needs ai:manage · changes data
https://app.getera.io/api/v1/knowledge_bases/actions/create_knowledge_base- REST alias:
POST /api/v1/knowledge_bases - Canonical address:
POST /api/v1/actions/ai.create_knowledge_base
Input
| Field | Type | Required | Notes |
|---|---|---|---|
brainId | uuid | yes | Brain |
name | string | yes | Name · max 80 |
kind | string (enum) | Kind · Allowed values: company, product, sales, marketing, customers, projects, personal, voice, industry, meetings, brand, finance, support, custom | |
description | string | What goes here · max 500 |
Preconditions
The action is refused with 409 and one of these codes:
| Code | Refused when |
|---|---|
brain_not_found | The brain must exist in this workspace. |
not_your_brain | Someone else’s personal brain is theirs. |
archived | An archived brain gets no new spaces. |
empty_name | A space needs a name. |
name_taken | Space names are unique in a brain. |
Events it publishes: ai.knowledge_base_created
What it writes: knowledge_base (insert) — Creates the space
curl -X POST https://app.getera.io/api/v1/knowledge_bases/actions/create_knowledge_base \
-H "Authorization: Bearer $ERA_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{"brainId":"BRAIN_ID","name":"Name"}'{
"ok": true,
"result": "…",
"events": [
"ai.knowledge_base_created"
]
}import { createEra } from "@getera/sdk"
const era = createEra({ apiKey: process.env.ERA_API_KEY })
const res = await era.knowledgeBases.create({
brainId: "BRAIN_ID",
name: "Name"
})era knowledge_bases create \
--brain-id "BRAIN_ID" \
--name "Name"{
"name": "era__ai__create_knowledge_base",
"arguments": {
"brainId": "BRAIN_ID",
"name": "Name"
}
}Errors: 401 no or expired credential · 403 the credential does not hold ai:manage · 404 the record or module is outside what it may reach · 422 invalid input (problems[]) · 409 brain_not_found, not_your_brain, archived, empty_name, name_taken · 429 slow down
ai.create_task
Create a task — A to-do for a person or an agent, with a due date, priority, list and repeat rule. Given to an agent, it wakes the agent.
Needs ai:write · changes data
https://app.getera.io/api/v1/ai_tasks/actions/create_task- Canonical address:
POST /api/v1/actions/ai.create_task
Input
| Field | Type | Required | Notes |
|---|---|---|---|
title | string | yes | Title · max 300 |
description | string | Details · max 10000 | |
listName | string | List · max 80 | |
priority | string (enum) | Priority · Allowed values: low, normal, high, urgent | |
dueAt | date-time | Due | |
recurrence | string (enum) | Repeats · Allowed values: none, daily, weekly, monthly | |
assigneeUserId | uuid | Person · id of app_user | |
assigneeAgentId | uuid | Agent · id of ai_agent | |
recordType | string (enum) | About · Allowed values: customer, lead, appointment, order, conversation | |
recordId | uuid | Record id |
Preconditions
The action is refused with 409 and one of these codes:
| Code | Refused when |
|---|---|
empty_title | A task needs a title. |
not_member | The person must be a member of this workspace. |
unknown_agent | The agent must exist in this workspace. |
agent_disabled | A switched-off agent cannot be handed a task. |
Events it publishes: ai.task_created, ai.agent_requested
What it writes: ai_task (insert) — Writes the task
curl -X POST https://app.getera.io/api/v1/ai_tasks/actions/create_task \
-H "Authorization: Bearer $ERA_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{"title":"Title"}'{
"ok": true,
"result": "…",
"events": [
"ai.task_created",
"ai.agent_requested"
]
}import { createEra } from "@getera/sdk"
const era = createEra({ apiKey: process.env.ERA_API_KEY })
const res = await era.aiTasks.createTask({
title: "Title"
})era ai_tasks create_task \
--title "Title"{
"name": "era__ai__create_task",
"arguments": {
"title": "Title"
}
}Errors: 401 no or expired credential · 403 the credential does not hold ai:write · 404 the record or module is outside what it may reach · 422 invalid input (problems[]) · 409 empty_title, not_member, unknown_agent, agent_disabled · 429 slow down
ai.decide_computer_step
Approve or refuse a computer step — Answers the step the computer is waiting on. “Allow similar” approves the same kind of step on the same site for 15 minutes.
Needs ai:handle · changes data
https://app.getera.io/api/v1/actions/ai.decide_computer_stepInput
| Field | Type | Required | Notes |
|---|---|---|---|
id | uuid | yes | Session · id of computer_session |
approvalId | uuid | yes | Step |
decision | string (enum) | yes | Decision · Allowed values: approve, deny |
allowSimilar | boolean | Allow similar steps for 15 minutes | |
note | string | Note · max 500 |
Preconditions
The action is refused with 409 and one of these codes:
| Code | Refused when |
|---|---|
not_found | The session must exist in this workspace. |
no_pending_approval | The step must still be waiting for an answer. |
What it writes: computer_session (update) — Stores the decision for the worker; computer_session_event (insert) — Records who decided
curl -X POST https://app.getera.io/api/v1/actions/ai.decide_computer_step \
-H "Authorization: Bearer $ERA_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{"id":"COMPUTER_SESSION_ID","approvalId":"APPROVAL_ID","decision":"approve"}'{
"ok": true,
"result": "…",
"events": []
}import { createEra } from "@getera/sdk"
const era = createEra({ apiKey: process.env.ERA_API_KEY })
const res = await era.actions.run("ai.decide_computer_step", {
id: "COMPUTER_SESSION_ID",
approvalId: "APPROVAL_ID",
decision: "approve"
})era ai decide_computer_step \
--id "COMPUTER_SESSION_ID" \
--approval-id "APPROVAL_ID" \
--decision "approve"{
"name": "era__ai__decide_computer_step",
"arguments": {
"id": "COMPUTER_SESSION_ID",
"approvalId": "APPROVAL_ID",
"decision": "approve"
}
}Errors: 401 no or expired credential · 403 the credential does not hold ai:handle · 404 the record or module is outside what it may reach · 422 invalid input (problems[]) · 409 not_found, no_pending_approval · 429 slow down
ai.decide_learning
Answer what Era asked to keep — Approve (optionally re-worded, re-filed, with an end date) or reject. Approving keeps the memory — confirmed, with where it came from — or makes the skill live as its next version. In a chat, call it only after the person said yes or no.
Needs ai:write · changes data
https://app.getera.io/api/v1/era_learnings/actions/decide_learning- Canonical address:
POST /api/v1/actions/ai.decide_learning
Input
| Field | Type | Required | Notes |
|---|---|---|---|
id | uuid | yes | What Era asked |
decision | string (enum) | yes | Answer · Allowed values: approve, reject |
statement | string | Wording · max 4000 | |
memoryKind | string | Category · fact · preference · rule · procedure · max 20 | |
audience | string | For · person · workspace · module · max 20 | |
moduleCode | string | Module · max 64 | |
expiresAt | date-time | Until | |
skillDescription | string | What the skill is for · max 1024 | |
skillContent | string | The skill’s steps · max 50000 |
Preconditions
The action is refused with 409 and one of these codes:
| Code | Refused when |
|---|---|
learning_not_found | Era must have asked about it here. |
already_decided | A proposal is answered once. |
not_yours | A proposal for one person is theirs to answer (or a manager’s). |
empty_statement | A re-worded memory still says something. |
bad_memory_kind | A memory is a fact, a preference, a rule or a procedure. |
module_required | A memory for one module names a module that exists. |
already_expired | An end date is in the future. |
skill_incomplete | An edited skill keeps a one-line purpose and its steps. |
Events it publishes: ai.learning_decided
What it writes: era_learning (update) — Records the answer; an approval is written to Era’s memory or skills by the table
curl -X POST https://app.getera.io/api/v1/era_learnings/actions/decide_learning \
-H "Authorization: Bearer $ERA_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{"id":"ID_ID","decision":"approve"}'{
"ok": true,
"result": "…",
"events": [
"ai.learning_decided"
]
}import { createEra } from "@getera/sdk"
const era = createEra({ apiKey: process.env.ERA_API_KEY })
const res = await era.eraLearnings.decideLearning({
id: "ID_ID",
decision: "approve"
})era era_learnings decide_learning \
--id "ID_ID" \
--decision "approve"{
"name": "era__ai__decide_learning",
"arguments": {
"id": "ID_ID",
"decision": "approve"
}
}Errors: 401 no or expired credential · 403 the credential does not hold ai:write · 404 the record or module is outside what it may reach · 422 invalid input (problems[]) · 409 learning_not_found, already_decided, not_yours, empty_statement, bad_memory_kind, module_required, already_expired, skill_incomplete · 429 slow down
ai.delete_agent
Delete an agent — Removes the agent and its run history. Switching it off is usually what you want.
Needs ai:delete · removes or cannot be undone · asks a person to confirm when Era runs it
https://app.getera.io/api/v1/ai_agents/{id}/actions/delete_agent- Canonical address:
POST /api/v1/actions/ai.delete_agent
Input
| Field | Type | Required | Notes |
|---|---|---|---|
id | uuid | yes | Filled from the path {id} · Agent · id of ai_agent |
Preconditions
The action is refused with 409 and one of these codes:
| Code | Refused when |
|---|---|
not_found | The agent must exist in this workspace. |
Events it publishes: ai.agent_deleted
What it writes: ai_agent (delete) — Removes the agent; ai_run (delete) — Its run history goes with it, by cascade
curl -X POST https://app.getera.io/api/v1/ai_agents/AI_AGENT_ID/actions/delete_agent \
-H "Authorization: Bearer $ERA_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{}'{
"ok": true,
"result": "…",
"events": [
"ai.agent_deleted"
]
}import { createEra } from "@getera/sdk"
const era = createEra({ apiKey: process.env.ERA_API_KEY })
const res = await era.aiAgents.deleteAgent("AI_AGENT_ID")era ai_agents delete_agent AI_AGENT_ID{
"name": "era__ai__delete_agent",
"arguments": {
"id": "AI_AGENT_ID"
}
}Errors: 401 no or expired credential · 403 the credential does not hold ai:delete · 404 the record or module is outside what it may reach · 422 invalid input (problems[]) · 409 not_found · 429 slow down
ai.delete_computer
Delete my cloud computer — Deletes your cloud computer and its disk. This cannot be undone.
Needs ai:handle · removes or cannot be undone · asks a person to confirm when Era runs it
https://app.getera.io/api/v1/computer_machines/actions/delete_computer- Canonical address:
POST /api/v1/actions/ai.delete_computer
Input
This action takes no input.
Preconditions
The action is refused with 409 and one of these codes:
| Code | Refused when |
|---|---|
no_computer | You need a cloud computer first. |
Events it publishes: ai.computer_machine_requested
What it writes: computer_machine (update) — Asks the worker to delete it; computer_session (update) — Stops tasks running on it
curl -X POST https://app.getera.io/api/v1/computer_machines/actions/delete_computer \
-H "Authorization: Bearer $ERA_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{}'{
"ok": true,
"result": "…",
"events": [
"ai.computer_machine_requested"
]
}import { createEra } from "@getera/sdk"
const era = createEra({ apiKey: process.env.ERA_API_KEY })
const res = await era.computerMachines.deleteComputer()era computer_machines delete_computer{
"name": "era__ai__delete_computer",
"arguments": {}
}Errors: 401 no or expired credential · 403 the credential does not hold ai:handle · 404 the record or module is outside what it may reach · 422 invalid input (problems[]) · 409 no_computer · 429 slow down
ai.delete_conversation
Delete a conversation — Hides a thread. The record changes it made are not undone.
Needs ai:delete · removes or cannot be undone · asks a person to confirm when Era runs it
https://app.getera.io/api/v1/ai_conversations/{id}/actions/delete_conversation- Canonical address:
POST /api/v1/actions/ai.delete_conversation
Input
| Field | Type | Required | Notes |
|---|---|---|---|
id | uuid | yes | Filled from the path {id} · Conversation · id of ai_conversation |
Preconditions
The action is refused with 409 and one of these codes:
| Code | Refused when |
|---|---|
not_found | The conversation must exist in this workspace. |
Events it publishes: ai.conversation_deleted
What it writes: ai_conversation (update) — Writes the tombstone, through sql/056’s door
curl -X POST https://app.getera.io/api/v1/ai_conversations/AI_CONVERSATION_ID/actions/delete_conversation \
-H "Authorization: Bearer $ERA_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{}'{
"ok": true,
"result": "…",
"events": [
"ai.conversation_deleted"
]
}import { createEra } from "@getera/sdk"
const era = createEra({ apiKey: process.env.ERA_API_KEY })
const res = await era.aiConversations.deleteConversation("AI_CONVERSATION_ID")era ai_conversations delete_conversation AI_CONVERSATION_ID{
"name": "era__ai__delete_conversation",
"arguments": {
"id": "AI_CONVERSATION_ID"
}
}Errors: 401 no or expired credential · 403 the credential does not hold ai:delete · 404 the record or module is outside what it may reach · 422 invalid input (problems[]) · 409 not_found · 429 slow down
ai.delete_task
Delete a task — Removes it from every list.
Needs ai:delete · removes or cannot be undone · asks a person to confirm when Era runs it
https://app.getera.io/api/v1/ai_tasks/{id}/actions/delete_task- Canonical address:
POST /api/v1/actions/ai.delete_task
Input
| Field | Type | Required | Notes |
|---|---|---|---|
id | uuid | yes | Filled from the path {id} · Task · id of ai_task |
Preconditions
The action is refused with 409 and one of these codes:
| Code | Refused when |
|---|---|
not_found | The task must exist in this workspace. |
Events it publishes: ai.task_deleted
What it writes: ai_task (update) — Writes the tombstone through sql/082’s door
curl -X POST https://app.getera.io/api/v1/ai_tasks/AI_TASK_ID/actions/delete_task \
-H "Authorization: Bearer $ERA_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{}'{
"ok": true,
"result": "…",
"events": [
"ai.task_deleted"
]
}import { createEra } from "@getera/sdk"
const era = createEra({ apiKey: process.env.ERA_API_KEY })
const res = await era.aiTasks.deleteTask("AI_TASK_ID")era ai_tasks delete_task AI_TASK_ID{
"name": "era__ai__delete_task",
"arguments": {
"id": "AI_TASK_ID"
}
}Errors: 401 no or expired credential · 403 the credential does not hold ai:delete · 404 the record or module is outside what it may reach · 422 invalid input (problems[]) · 409 not_found · 429 slow down
ai.disconnect_subscription
Disconnect my subscription — Era stops using this plan. The sign-in was revoked at the provider before this runs.
Needs ai:write · removes or cannot be undone · asks a person to confirm when Era runs it
https://app.getera.io/api/v1/ai_providers/{id}/actions/disconnect_subscription- Canonical address:
POST /api/v1/actions/ai.disconnect_subscription
Input
| Field | Type | Required | Notes |
|---|---|---|---|
id | uuid | yes | Filled from the path {id} · Subscription · id of ai_provider |
Preconditions
The action is refused with 409 and one of these codes:
| Code | Refused when |
|---|---|
not_found | The subscription must be connected in this workspace. |
not_owner | Its owner, or a workspace manager for someone who left. |
Events it publishes: ai.subscription_disconnected
What it writes: ai_provider (delete) — Removes the connection row
curl -X POST https://app.getera.io/api/v1/ai_providers/AI_PROVIDER_ID/actions/disconnect_subscription \
-H "Authorization: Bearer $ERA_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{}'{
"ok": true,
"result": "…",
"events": [
"ai.subscription_disconnected"
]
}import { createEra } from "@getera/sdk"
const era = createEra({ apiKey: process.env.ERA_API_KEY })
const res = await era.aiProviders.disconnectSubscription("AI_PROVIDER_ID")era ai_providers disconnect_subscription AI_PROVIDER_ID{
"name": "era__ai__disconnect_subscription",
"arguments": {
"id": "AI_PROVIDER_ID"
}
}Errors: 401 no or expired credential · 403 the credential does not hold ai:write · 404 the record or module is outside what it may reach · 422 invalid input (problems[]) · 409 not_found, not_owner · 429 slow down
ai.erase_brain_fact
Permanently erase something Era learned — Kalıcı olarak sil: the fact, every earlier and later version of it, its links, the decisions about it and its mention in insights are deleted. Unut only stops Era using it.
Needs ai:manage · removes or cannot be undone · asks a person to confirm when Era runs it
https://app.getera.io/api/v1/brain_erasures/actions/erase_brain_fact- Canonical address:
POST /api/v1/actions/ai.erase_brain_fact
Input
| Field | Type | Required | Notes |
|---|---|---|---|
memoryId | uuid | yes | What Era learned |
reason | string | Why (e.g. a KVKK request’s reference) · max 500 |
Preconditions
The action is refused with 409 and one of these codes:
| Code | Refused when |
|---|---|
fact_not_found | Era must know it, and it must not be someone else’s private fact. |
Events it publishes: ai.brain_fact_erased
What it writes: brain_erasure (insert) — Records the erasure (without the erased words); brain_fact_review (delete) — Reviews that quote it go with it; decide_decision (delete) — Decisions taken about it go with it; brain_insight (update) — Insights drawn from it lose that source; one with no source left is deleted
curl -X POST https://app.getera.io/api/v1/brain_erasures/actions/erase_brain_fact \
-H "Authorization: Bearer $ERA_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{"memoryId":"MEMORY_ID"}'{
"ok": true,
"result": "…",
"events": [
"ai.brain_fact_erased"
]
}import { createEra } from "@getera/sdk"
const era = createEra({ apiKey: process.env.ERA_API_KEY })
const res = await era.brainErasures.eraseBrainFact({
memoryId: "MEMORY_ID"
})era brain_erasures erase_brain_fact \
--memory-id "MEMORY_ID"{
"name": "era__ai__erase_brain_fact",
"arguments": {
"memoryId": "MEMORY_ID"
}
}Errors: 401 no or expired credential · 403 the credential does not hold ai:manage · 404 the record or module is outside what it may reach · 422 invalid input (problems[]) · 409 fact_not_found · 429 slow down
ai.erase_brain_person
Erase everything Era learned about a person — A data-subject request (KVKK m.7 / GDPR art. 17): every fact about the person, every version of them, and the person in Era’s memory are deleted; the register keeps that it was done.
Needs ai:manage · removes or cannot be undone · asks a person to confirm when Era runs it
https://app.getera.io/api/v1/brain_erasures/actions/erase_brain_person- Canonical address:
POST /api/v1/actions/ai.erase_brain_person
Input
| Field | Type | Required | Notes |
|---|---|---|---|
entityId | uuid | yes | Person |
reason | string | Request reference · max 500 | |
requestedOn | string | The day they asked · max 10 |
Preconditions
The action is refused with 409 and one of these codes:
| Code | Refused when |
|---|---|
person_not_found | Era must know the person in this workspace. |
bad_date | The day they asked is a real day, not in the future. |
Events it publishes: ai.brain_person_erased
What it writes: brain_erasure (insert) — Records the request and what was erased; brain_fact_review (delete) — Reviews that quote the facts go with them; decide_decision (delete) — Decisions taken about the facts go with them; brain_insight (update) — Insights drawn from the facts lose them; one with no source left is deleted
curl -X POST https://app.getera.io/api/v1/brain_erasures/actions/erase_brain_person \
-H "Authorization: Bearer $ERA_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{"entityId":"ENTITY_ID"}'{
"ok": true,
"result": "…",
"events": [
"ai.brain_person_erased"
]
}import { createEra } from "@getera/sdk"
const era = createEra({ apiKey: process.env.ERA_API_KEY })
const res = await era.brainErasures.eraseBrainPerson({
entityId: "ENTITY_ID"
})era brain_erasures erase_brain_person \
--entity-id "ENTITY_ID"{
"name": "era__ai__erase_brain_person",
"arguments": {
"entityId": "ENTITY_ID"
}
}Errors: 401 no or expired credential · 403 the credential does not hold ai:manage · 404 the record or module is outside what it may reach · 422 invalid input (problems[]) · 409 person_not_found, bad_date · 429 slow down
ai.escalate_approval
Escalate a waiting approval — Tells the approvers a request has waited too long. Machine-only: the approvals list raises it.
Needs ai:read · reads only
403 machine_only).https://app.getera.io/api/v1/actions/ai.escalate_approvalInput
| Field | Type | Required | Notes |
|---|---|---|---|
approvalId | string | yes | Approval · max 64 |
intent | string | What it asks · max 300 | |
tool | string | Tool · max 200 | |
ageHours | number | yes | Waiting for (hours) · min 0 |
Events it publishes: ai.approval_escalated
Errors: 401 no or expired credential · 403 the credential does not hold ai:read · 404 the record or module is outside what it may reach · 422 invalid input (problems[]) · 429 slow down
ai.evaluate_skill
Record a skill evaluation — Stores how many test cases a version passed. The skill screen runs the cases, then calls this.
Needs ai:write · changes data
https://app.getera.io/api/v1/ai_skill_versions/{id}/actions/evaluate_skill- Canonical address:
POST /api/v1/actions/ai.evaluate_skill
Input
| Field | Type | Required | Notes |
|---|---|---|---|
versionId | uuid | yes | Filled from the path {id} · Version · id of ai_skill_version |
passed | number | yes | Passed · min 0 |
total | number | yes | Cases · min 0 |
notes | string | Notes · max 10000 |
Preconditions
The action is refused with 409 and one of these codes:
| Code | Refused when |
|---|---|
not_found | The version must exist in this workspace. |
Events it publishes: ai.skill_evaluated
What it writes: ai_skill_version (update) — Writes the score
curl -X POST https://app.getera.io/api/v1/ai_skill_versions/AI_SKILL_VERSION_ID/actions/evaluate_skill \
-H "Authorization: Bearer $ERA_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{"passed":1,"total":1}'{
"ok": true,
"result": "…",
"events": [
"ai.skill_evaluated"
]
}import { createEra } from "@getera/sdk"
const era = createEra({ apiKey: process.env.ERA_API_KEY })
const res = await era.aiSkillVersions.evaluateSkill("AI_SKILL_VERSION_ID", {
passed: 1,
total: 1
})era ai_skill_versions evaluate_skill AI_SKILL_VERSION_ID \
--passed 1 \
--total 1{
"name": "era__ai__evaluate_skill",
"arguments": {
"versionId": "AI_SKILL_VERSION_ID",
"passed": 1,
"total": 1
}
}Errors: 401 no or expired credential · 403 the credential does not hold ai:write · 404 the record or module is outside what it may reach · 422 invalid input (problems[]) · 409 not_found · 429 slow down
ai.forget_computer_folder
Forget a folder — Era no longer knows this folder by name.
Needs ai:handle · removes or cannot be undone
https://app.getera.io/api/v1/computer_folders/{id}/actions/forget_computer_folder- Canonical address:
POST /api/v1/actions/ai.forget_computer_folder
Input
| Field | Type | Required | Notes |
|---|---|---|---|
id | uuid | yes | Filled from the path {id} · Folder · id of computer_folder |
Preconditions
The action is refused with 409 and one of these codes:
| Code | Refused when |
|---|---|
not_found | The folder must be yours. |
What it writes: computer_folder (delete) — Removes the name
curl -X POST https://app.getera.io/api/v1/computer_folders/COMPUTER_FOLDER_ID/actions/forget_computer_folder \
-H "Authorization: Bearer $ERA_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{}'{
"ok": true,
"result": "…",
"events": []
}import { createEra } from "@getera/sdk"
const era = createEra({ apiKey: process.env.ERA_API_KEY })
const res = await era.computerFolders.forgetComputerFolder("COMPUTER_FOLDER_ID")era computer_folders forget_computer_folder COMPUTER_FOLDER_ID{
"name": "era__ai__forget_computer_folder",
"arguments": {
"id": "COMPUTER_FOLDER_ID"
}
}Errors: 401 no or expired credential · 403 the credential does not hold ai:handle · 404 the record or module is outside what it may reach · 422 invalid input (problems[]) · 409 not_found · 429 slow down
ai.forget_learning
Forget something ("bunu unut") — Forgets a memory — by its id, or by its words ("bunu unut: Ahmet Bey sabah randevusu"); Era stops using it and it stays in the history — or stops using a skill by its name (paused, not deleted). More than one match is refused with the candidates so you can ask which.
Needs ai:write · removes or cannot be undone
https://app.getera.io/api/v1/brain_fact_reviews/actions/forget_learning- Canonical address:
POST /api/v1/actions/ai.forget_learning
Input
| Field | Type | Required | Notes |
|---|---|---|---|
memoryId | uuid | Memory | |
about | string | What to forget, in words · max 500 | |
skillName | string | Skill to stop using · max 64 |
Preconditions
The action is refused with 409 and one of these codes:
| Code | Refused when |
|---|---|
nothing_to_forget | Era must remember it (or have that skill). |
ambiguous | Words that match more than one memory need a choice. |
Events it publishes: ai.learning_forgotten
What it writes: brain_fact_review (insert) — Records Unut; the table applies it; ai_skill_release (update) — Pauses the skill
curl -X POST https://app.getera.io/api/v1/brain_fact_reviews/actions/forget_learning \
-H "Authorization: Bearer $ERA_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{"memoryId":"MEMORY_ID"}'{
"ok": true,
"result": "…",
"events": [
"ai.learning_forgotten"
]
}import { createEra } from "@getera/sdk"
const era = createEra({ apiKey: process.env.ERA_API_KEY })
const res = await era.brainFactReviews.forgetLearning({
memoryId: "MEMORY_ID"
})era brain_fact_reviews forget_learning \
--memory-id "MEMORY_ID"{
"name": "era__ai__forget_learning",
"arguments": {
"memoryId": "MEMORY_ID"
}
}Errors: 401 no or expired credential · 403 the credential does not hold ai:write · 404 the record or module is outside what it may reach · 422 invalid input (problems[]) · 409 nothing_to_forget, ambiguous · 429 slow down
ai.link_engine_agent
Link an agent to an assistant — Makes an assistant (persona, skills, integrations) the authoring half of this agent. Empty unlinks.
Needs ai:manage · changes data
https://app.getera.io/api/v1/ai_agents/{id}/actions/link_engine_agent- Canonical address:
POST /api/v1/actions/ai.link_engine_agent
Input
| Field | Type | Required | Notes |
|---|---|---|---|
id | uuid | yes | Filled from the path {id} · Agent · id of ai_agent |
engineAgentId | string | Assistant · max 64 |
Preconditions
The action is refused with 409 and one of these codes:
| Code | Refused when |
|---|---|
not_found | The agent must exist in this workspace. |
already_linked | An assistant extends at most one agent. |
Events it publishes: ai.agent_linked
What it writes: ai_agent (update) — Writes engine_agent_id
curl -X POST https://app.getera.io/api/v1/ai_agents/AI_AGENT_ID/actions/link_engine_agent \
-H "Authorization: Bearer $ERA_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{"engineAgentId":"Assistant"}'{
"ok": true,
"result": "…",
"events": [
"ai.agent_linked"
]
}import { createEra } from "@getera/sdk"
const era = createEra({ apiKey: process.env.ERA_API_KEY })
const res = await era.aiAgents.linkEngineAgent("AI_AGENT_ID", {
engineAgentId: "Assistant"
})era ai_agents link_engine_agent AI_AGENT_ID \
--engine-agent-id "Assistant"{
"name": "era__ai__link_engine_agent",
"arguments": {
"id": "AI_AGENT_ID",
"engineAgentId": "Assistant"
}
}Errors: 401 no or expired credential · 403 the credential does not hold ai:manage · 404 the record or module is outside what it may reach · 422 invalid input (problems[]) · 409 not_found, already_linked · 429 slow down
ai.mark_chat_seen
Open a shared chat — Presence and the access log: says you are looking at a chat someone shared with you.
Needs ai:read · changes data
https://app.getera.io/api/v1/era_chat_seens/actions/mark_chat_seen- Canonical address:
POST /api/v1/actions/ai.mark_chat_seen
Input
| Field | Type | Required | Notes |
|---|---|---|---|
conversationId | uuid | yes | Chat |
Preconditions
The action is refused with 409 and one of these codes:
| Code | Refused when |
|---|---|
not_found | The chat must exist in this workspace. |
no_access | The chat must be shared with you, or with the workspace. |
What it writes: era_chat_member (update) — Stamps when you last looked; era_share_access_log (insert) — Logs the visit; era_chat_seen (upsert) — Remembers when you last looked, for the unseen dot
curl -X POST https://app.getera.io/api/v1/era_chat_seens/actions/mark_chat_seen \
-H "Authorization: Bearer $ERA_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{"conversationId":"CONVERSATION_ID"}'{
"ok": true,
"result": "…",
"events": []
}import { createEra } from "@getera/sdk"
const era = createEra({ apiKey: process.env.ERA_API_KEY })
const res = await era.eraChatSeens.markChatSeen({
conversationId: "CONVERSATION_ID"
})era era_chat_seens mark_chat_seen \
--conversation-id "CONVERSATION_ID"{
"name": "era__ai__mark_chat_seen",
"arguments": {
"conversationId": "CONVERSATION_ID"
}
}Errors: 401 no or expired credential · 403 the credential does not hold ai:read · 404 the record or module is outside what it may reach · 422 invalid input (problems[]) · 409 not_found, no_access · 429 slow down
ai.open_code_session
Start a coding session — Starts a live Claude Code or Codex session in a folder on your computer; what you say next goes into it.
Needs ai:handle · changes data
https://app.getera.io/api/v1/computer_folders/{id}/actions/open_code_session- Canonical address:
POST /api/v1/actions/ai.open_code_session
Input
| Field | Type | Required | Notes |
|---|---|---|---|
conversationId | uuid | Conversation | |
folderId | uuid | Filled from the path {id} · Folder · id of computer_folder | |
folderName | string | yes | Folder name · max 80 |
path | string | yes | Full path · max 1000 |
harness | string | yes | Engine · claude (Claude Code) or codex (Codex). · max 20 |
deviceId | string | Computer · max 80 | |
surface | string | Started from · max 40 |
Preconditions
The action is refused with 409 and one of these codes:
| Code | Refused when |
|---|---|
computer_access_required | Only the workspace owner, or a member given computer access, can reach a computer. |
unknown_harness | A coding session runs on Claude Code or Codex. |
Events it publishes: ai.code_session_opened, ai.code_session_closed
What it writes: code_session (insert) — Opens the session; code_session (update) — Closes the conversation’s previous session; computer_folder (update) — Marks the folder as used
curl -X POST https://app.getera.io/api/v1/computer_folders/COMPUTER_FOLDER_ID/actions/open_code_session \
-H "Authorization: Bearer $ERA_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{"folderName":"Folder name","path":"Full path","harness":"Engine"}'{
"ok": true,
"result": "…",
"events": [
"ai.code_session_opened",
"ai.code_session_closed"
]
}import { createEra } from "@getera/sdk"
const era = createEra({ apiKey: process.env.ERA_API_KEY })
const res = await era.computerFolders.openCodeSession("COMPUTER_FOLDER_ID", {
folderName: "Folder name",
path: "Full path",
harness: "Engine"
})era computer_folders open_code_session COMPUTER_FOLDER_ID \
--folder-name "Folder name" \
--path "Full path" \
--harness "Engine"{
"name": "era__ai__open_code_session",
"arguments": {
"folderId": "COMPUTER_FOLDER_ID",
"folderName": "Folder name",
"path": "Full path",
"harness": "Engine"
}
}Errors: 401 no or expired credential · 403 the credential does not hold ai:handle · 404 the record or module is outside what it may reach · 422 invalid input (problems[]) · 409 computer_access_required, unknown_harness · 429 slow down
ai.pause_computer
Turn off my cloud computer — Pauses your cloud computer: billing stops, the disk and open apps are kept.
Needs ai:handle · changes data
https://app.getera.io/api/v1/computer_machines/actions/pause_computer- Canonical address:
POST /api/v1/actions/ai.pause_computer
Input
This action takes no input.
Preconditions
The action is refused with 409 and one of these codes:
| Code | Refused when |
|---|---|
no_computer | You need a cloud computer first. |
not_running | Only a running computer can be paused. |
Events it publishes: ai.computer_machine_requested
What it writes: computer_machine (update) — Asks the worker to pause it; computer_session (update) — Stops tasks running on it
curl -X POST https://app.getera.io/api/v1/computer_machines/actions/pause_computer \
-H "Authorization: Bearer $ERA_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{}'{
"ok": true,
"result": "…",
"events": [
"ai.computer_machine_requested"
]
}import { createEra } from "@getera/sdk"
const era = createEra({ apiKey: process.env.ERA_API_KEY })
const res = await era.computerMachines.pauseComputer()era computer_machines pause_computer{
"name": "era__ai__pause_computer",
"arguments": {}
}Errors: 401 no or expired credential · 403 the credential does not hold ai:handle · 404 the record or module is outside what it may reach · 422 invalid input (problems[]) · 409 no_computer, not_running · 429 slow down
ai.pause_computer_session
Pause a computer task — Holds the task after its current step until you resume it.
Needs ai:handle · changes data
https://app.getera.io/api/v1/actions/ai.pause_computer_sessionInput
| Field | Type | Required | Notes |
|---|---|---|---|
id | uuid | yes | Session · id of computer_session |
Preconditions
The action is refused with 409 and one of these codes:
| Code | Refused when |
|---|---|
not_found | The session must exist in this workspace. |
not_running | Only a running task can be paused. |
What it writes: computer_session (update) — Sets the pause flag; computer_session_event (insert) — Records the pause
curl -X POST https://app.getera.io/api/v1/actions/ai.pause_computer_session \
-H "Authorization: Bearer $ERA_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{"id":"COMPUTER_SESSION_ID"}'{
"ok": true,
"result": "…",
"events": []
}import { createEra } from "@getera/sdk"
const era = createEra({ apiKey: process.env.ERA_API_KEY })
const res = await era.actions.run("ai.pause_computer_session", {
id: "COMPUTER_SESSION_ID"
})era ai pause_computer_session \
--id "COMPUTER_SESSION_ID"{
"name": "era__ai__pause_computer_session",
"arguments": {
"id": "COMPUTER_SESSION_ID"
}
}Errors: 401 no or expired credential · 403 the credential does not hold ai:handle · 404 the record or module is outside what it may reach · 422 invalid input (problems[]) · 409 not_found, not_running · 429 slow down
ai.promote_skill
Promote a skill version — Makes this version the live one. Promoting an older version is a rollback.
Needs ai:manage · changes data
https://app.getera.io/api/v1/ai_skill_versions/{id}/actions/promote_skill- Canonical address:
POST /api/v1/actions/ai.promote_skill
Input
| Field | Type | Required | Notes |
|---|---|---|---|
versionId | uuid | yes | Filled from the path {id} · Version · id of ai_skill_version |
Preconditions
The action is refused with 409 and one of these codes:
| Code | Refused when |
|---|---|
not_found | The version must exist in this workspace. |
not_evaluated | Only an evaluated or previously live version can be promoted. |
Events it publishes: ai.skill_promoted
What it writes: ai_skill_version (update) — Retires the live version and activates this one
curl -X POST https://app.getera.io/api/v1/ai_skill_versions/AI_SKILL_VERSION_ID/actions/promote_skill \
-H "Authorization: Bearer $ERA_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{}'{
"ok": true,
"result": "…",
"events": [
"ai.skill_promoted"
]
}import { createEra } from "@getera/sdk"
const era = createEra({ apiKey: process.env.ERA_API_KEY })
const res = await era.aiSkillVersions.promoteSkill("AI_SKILL_VERSION_ID")era ai_skill_versions promote_skill AI_SKILL_VERSION_ID{
"name": "era__ai__promote_skill",
"arguments": {
"versionId": "AI_SKILL_VERSION_ID"
}
}Errors: 401 no or expired credential · 403 the credential does not hold ai:manage · 404 the record or module is outside what it may reach · 422 invalid input (problems[]) · 409 not_found, not_evaluated · 429 slow down
ai.propose_learning
Ask to remember something — Era asks before it keeps anything ("Bunu hatırlayayım mı?"): a fact, a preference, a rule or a procedure, for one person, everyone or one module, optionally until a date — or a skill (named steps) it drafted from repeated work. Nothing is kept until a person approves.
Needs ai:write · changes data
https://app.getera.io/api/v1/era_learnings/actions/propose_learning- Canonical address:
POST /api/v1/actions/ai.propose_learning
Input
| Field | Type | Required | Notes |
|---|---|---|---|
kind | string (enum) | What · Allowed values: memory, skill | |
statement | string | What to remember (one self-contained sentence) · max 4000 | |
memoryKind | string | Category · fact · preference · rule · procedure · max 20 | |
audience | string | For · person (only the person you talk to) · workspace (everyone) · module (only in one module) · max 20 | |
moduleCode | string | Module · For audience "module": retail, appointments, crm … · max 64 | |
expiresAt | date-time | Until | |
forUser | uuid | Whose approval | |
brainId | uuid | Brain | |
knowledgeBaseId | uuid | Knowledge space | |
confidence | number | How sure · min 0 · max 1 | |
skillId | string | Skill to update · max 64 | |
skillName | string | Skill name (kebab-case) · max 64 | |
skillDescription | string | What the skill is for · max 1024 | |
skillContent | string | The skill’s steps · max 50000 | |
reason | string | Why Era thinks so · max 1000 | |
source | object / array | Where it came from · { kind: "conversation", ref, label, at, url } | |
evidenceCount | number | Seen this many times · min 1 · max 1000 | |
dedupeKey | string | Same-proposal key · max 200 | |
proposedBy | string | Proposed by · era · learning · skills · max 20 | |
told | boolean | The person said to keep it · Only when THEY told you to remember it (bunu öğren); never for something you noticed. |
Preconditions
The action is refused with 409 and one of these codes:
| Code | Refused when |
|---|---|
empty_statement | A memory says what to remember. |
bad_memory_kind | A memory is a fact, a preference, a rule or a procedure. |
module_required | A memory for one module names a module that exists. |
already_expired | An end date is in the future. |
already_known | Era does not ask about what it already remembers. |
already_proposed | Era asks about the same thing once until it is answered. |
rejected_before | Era does not ask again about what the owner said no to, or about a kind of thing the owner keeps refusing. |
skill_incomplete | A skill has a kebab-case name, a one-line purpose and its steps. |
skill_not_found | A skill to update must exist here. |
brain_not_found | A named brain must exist here. |
Events it publishes: ai.learning_proposed
What it writes: era_learning (insert) — Adds the proposal; nothing is kept yet
curl -X POST https://app.getera.io/api/v1/era_learnings/actions/propose_learning \
-H "Authorization: Bearer $ERA_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{"kind":"memory"}'{
"ok": true,
"result": "…",
"events": [
"ai.learning_proposed"
]
}import { createEra } from "@getera/sdk"
const era = createEra({ apiKey: process.env.ERA_API_KEY })
const res = await era.eraLearnings.proposeLearning({
kind: "memory"
})era era_learnings propose_learning \
--kind "memory"{
"name": "era__ai__propose_learning",
"arguments": {
"kind": "memory"
}
}Errors: 401 no or expired credential · 403 the credential does not hold ai:write · 404 the record or module is outside what it may reach · 422 invalid input (problems[]) · 409 empty_statement, bad_memory_kind, module_required, already_expired, already_known, already_proposed, rejected_before, skill_incomplete, skill_not_found, brain_not_found · 429 slow down
ai.provision_computer
Set up my cloud computer — Creates your own Linux computer in the cloud (browser, terminal, files) that you can watch and use.
Needs ai:handle · changes data
https://app.getera.io/api/v1/computer_machines/actions/provision_computer- Canonical address:
POST /api/v1/actions/ai.provision_computer
Input
| Field | Type | Required | Notes |
|---|---|---|---|
name | string | Name · max 80 | |
provider | string | Provider · max 40 |
Preconditions
The action is refused with 409 and one of these codes:
| Code | Refused when |
|---|---|
already_has_computer | One cloud computer per person. |
computer_access_required | Only the workspace owner, or a member given computer access, can reach a computer. |
unknown_provider | A provider asked for must be boxd, e2b or digitalocean. |
hours_used_up | The person’s cloud hours this month must be under the plan’s hours and the workspace cap. |
Events it publishes: ai.computer_machine_requested
What it writes: computer_machine (insert) — Requests the machine
curl -X POST https://app.getera.io/api/v1/computer_machines/actions/provision_computer \
-H "Authorization: Bearer $ERA_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{"name":"Name"}'{
"ok": true,
"result": "…",
"events": [
"ai.computer_machine_requested"
]
}import { createEra } from "@getera/sdk"
const era = createEra({ apiKey: process.env.ERA_API_KEY })
const res = await era.computerMachines.provisionComputer({
name: "Name"
})era computer_machines provision_computer \
--name "Name"{
"name": "era__ai__provision_computer",
"arguments": {
"name": "Name"
}
}Errors: 401 no or expired credential · 403 the credential does not hold ai:handle · 404 the record or module is outside what it may reach · 422 invalid input (problems[]) · 409 already_has_computer, computer_access_required, unknown_provider, hours_used_up · 429 slow down
ai.record_brain_insight
Record an insight — Era’s learning job (or Era itself) notes something a role should know, with where it came from.
Needs ai:write · changes data
https://app.getera.io/api/v1/brain_insights/actions/record_brain_insight- Canonical address:
POST /api/v1/actions/ai.record_brain_insight
Input
| Field | Type | Required | Notes |
|---|---|---|---|
role | string | For · sales · marketing · finance · operations · support · management · general · max 20 | |
title | string | yes | Title · max 200 |
body | string | Details · max 4000 | |
severity | string (enum) | Kind · Allowed values: info, opportunity, warning | |
brainId | uuid | Brain | |
sources | object / array | Sources | |
reasoning | string | Why · max 2000 | |
suggestedAction | object / array | Suggested next step | |
generatedBy | object / array | Made by | |
dedupeKey | string | Same-insight key · max 200 | |
origin | string (enum) | Noticed by · Allowed values: learning, outcome, era, person | |
kind | string | Kind of insight · max 64 |
Preconditions
The action is refused with 409 and one of these codes:
| Code | Refused when |
|---|---|
bad_role | An insight is for a known role. |
empty_title | An insight needs a title. |
brain_not_found | A named brain must exist. |
not_your_brain | Someone else’s personal brain is theirs. |
invalid_sources | Each source is an object naming where it came from. |
already_noted | The same insight (same key) is noted once. |
Events it publishes: ai.brain_insight_created
What it writes: brain_insight (insert) — Adds the insight (once per same-insight key)
curl -X POST https://app.getera.io/api/v1/brain_insights/actions/record_brain_insight \
-H "Authorization: Bearer $ERA_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{"title":"Title"}'{
"ok": true,
"result": "…",
"events": [
"ai.brain_insight_created"
]
}import { createEra } from "@getera/sdk"
const era = createEra({ apiKey: process.env.ERA_API_KEY })
const res = await era.brainInsights.recordBrainInsight({
title: "Title"
})era brain_insights record_brain_insight \
--title "Title"{
"name": "era__ai__record_brain_insight",
"arguments": {
"title": "Title"
}
}Errors: 401 no or expired credential · 403 the credential does not hold ai:write · 404 the record or module is outside what it may reach · 422 invalid input (problems[]) · 409 bad_role, empty_title, brain_not_found, not_your_brain, invalid_sources, already_noted · 429 slow down
ai.record_code_session
Record a coding turn — What the coding session is doing: the running turn, its summary, the files it touched, the diff and the tests.
Needs ai:handle · changes data
https://app.getera.io/api/v1/actions/ai.record_code_sessionInput
| Field | Type | Required | Notes |
|---|---|---|---|
id | uuid | yes | Session · id of code_session |
turnState | string | State · max 20 | |
currentJobId | string | Job · max 80 | |
providerSessionId | string | Resume cursor · max 200 | |
harness | string | Engine · max 20 | |
deviceId | string | Computer · max 80 | |
lastPrompt | string | Last prompt · max 4000 | |
lastSummary | string | Last summary · max 8000 | |
files | object / array | Files touched | |
diff | object / array | Diff summary | |
tests | object / array | Test result | |
addTurn | boolean | A turn ended | |
pushApproved | boolean | Push approved | |
pushPending | boolean | Push waits for OK |
Preconditions
The action is refused with 409 and one of these codes:
| Code | Refused when |
|---|---|
not_found | The session must be yours. |
invalid_state | Only known states, and files as a list. |
unknown_harness | A coding session runs on Claude Code or Codex. |
What it writes: code_session (update) — Stores the turn
curl -X POST https://app.getera.io/api/v1/actions/ai.record_code_session \
-H "Authorization: Bearer $ERA_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{"id":"CODE_SESSION_ID"}'{
"ok": true,
"result": "…",
"events": []
}import { createEra } from "@getera/sdk"
const era = createEra({ apiKey: process.env.ERA_API_KEY })
const res = await era.actions.run("ai.record_code_session", {
id: "CODE_SESSION_ID"
})era ai record_code_session \
--id "CODE_SESSION_ID"{
"name": "era__ai__record_code_session",
"arguments": {
"id": "CODE_SESSION_ID"
}
}Errors: 401 no or expired credential · 403 the credential does not hold ai:handle · 404 the record or module is outside what it may reach · 422 invalid input (problems[]) · 409 not_found, invalid_state, unknown_harness · 429 slow down
ai.record_computer_file
Save a computer file — The computer worker saves a file the task produced.
Needs ai:handle · changes data
https://app.getera.io/api/v1/actions/ai.record_computer_fileInput
| Field | Type | Required | Notes |
|---|---|---|---|
id | uuid | yes | Session · id of computer_session |
name | string | yes | Name · max 200 |
mime | string | Type · max 100 | |
content | string | yes | Content (base64) · max 14000000 |
Preconditions
The action is refused with 409 and one of these codes:
| Code | Refused when |
|---|---|
not_found | The session must exist in this workspace. |
too_large | A session file can be at most 10 MB. |
What it writes: computer_session_file (insert) — Stores the file; computer_session_event (insert) — Notes it on the timeline
curl -X POST https://app.getera.io/api/v1/actions/ai.record_computer_file \
-H "Authorization: Bearer $ERA_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{"id":"COMPUTER_SESSION_ID","name":"Name","content":"Content (base64)"}'{
"ok": true,
"result": "…",
"events": []
}import { createEra } from "@getera/sdk"
const era = createEra({ apiKey: process.env.ERA_API_KEY })
const res = await era.actions.run("ai.record_computer_file", {
id: "COMPUTER_SESSION_ID",
name: "Name",
content: "Content (base64)"
})era ai record_computer_file \
--id "COMPUTER_SESSION_ID" \
--name "Name" \
--content "Content (base64)"{
"name": "era__ai__record_computer_file",
"arguments": {
"id": "COMPUTER_SESSION_ID",
"name": "Name",
"content": "Content (base64)"
}
}Errors: 401 no or expired credential · 403 the credential does not hold ai:handle · 404 the record or module is outside what it may reach · 422 invalid input (problems[]) · 409 not_found, too_large · 429 slow down
ai.record_computer_frame
Record a live frame — The computer worker stores the latest picture of a running task.
Needs ai:handle · changes data
https://app.getera.io/api/v1/actions/ai.record_computer_frameInput
| Field | Type | Required | Notes |
|---|---|---|---|
id | uuid | yes | Session · id of computer_session |
image | string | yes | Image (base64) · max 3000000 |
mime | string | Type · max 40 | |
width | number | Width · min 1 | |
height | number | Height · min 1 |
Preconditions
The action is refused with 409 and one of these codes:
| Code | Refused when |
|---|---|
not_found | The session must exist in this workspace. |
invalid_frame | A frame must be an image under 2 MB. |
What it writes: computer_frame (upsert) — Replaces the session’s live picture
curl -X POST https://app.getera.io/api/v1/actions/ai.record_computer_frame \
-H "Authorization: Bearer $ERA_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{"id":"COMPUTER_SESSION_ID","image":"Image (base64)"}'{
"ok": true,
"result": "…",
"events": []
}import { createEra } from "@getera/sdk"
const era = createEra({ apiKey: process.env.ERA_API_KEY })
const res = await era.actions.run("ai.record_computer_frame", {
id: "COMPUTER_SESSION_ID",
image: "Image (base64)"
})era ai record_computer_frame \
--id "COMPUTER_SESSION_ID" \
--image "Image (base64)"{
"name": "era__ai__record_computer_frame",
"arguments": {
"id": "COMPUTER_SESSION_ID",
"image": "Image (base64)"
}
}Errors: 401 no or expired credential · 403 the credential does not hold ai:handle · 404 the record or module is outside what it may reach · 422 invalid input (problems[]) · 409 not_found, invalid_frame · 429 slow down
ai.record_computer_machine
Record cloud computer state — The computer worker reports what the provider did.
Needs ai:handle · changes data
https://app.getera.io/api/v1/computer_machines/{id}/actions/record_computer_machine- Canonical address:
POST /api/v1/actions/ai.record_computer_machine
Input
| Field | Type | Required | Notes |
|---|---|---|---|
id | uuid | yes | Filled from the path {id} · Computer · id of computer_machine |
state | string | yes | State · max 20 |
externalId | string | Provider id · max 200 | |
viewerSecretRef | string | Viewer secret · max 200 | |
viewerUrl | string | Viewer address · max 2000 | |
error | string | Error · max 500 | |
addSeconds | number | Seconds used · min 0 | |
metadata | object / array | Details |
Preconditions
The action is refused with 409 and one of these codes:
| Code | Refused when |
|---|---|
no_computer | The machine must exist. |
invalid_state | Only known states are recorded. |
Events it publishes: ai.computer_machine_changed
What it writes: computer_machine (update) — Stores the provider’s answer and the hours used
curl -X POST https://app.getera.io/api/v1/computer_machines/COMPUTER_MACHINE_ID/actions/record_computer_machine \
-H "Authorization: Bearer $ERA_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{"state":"State"}'{
"ok": true,
"result": "…",
"events": [
"ai.computer_machine_changed"
]
}import { createEra } from "@getera/sdk"
const era = createEra({ apiKey: process.env.ERA_API_KEY })
const res = await era.computerMachines.recordComputerMachine("COMPUTER_MACHINE_ID", {
state: "State"
})era computer_machines record_computer_machine COMPUTER_MACHINE_ID \
--state "State"{
"name": "era__ai__record_computer_machine",
"arguments": {
"id": "COMPUTER_MACHINE_ID",
"state": "State"
}
}Errors: 401 no or expired credential · 403 the credential does not hold ai:handle · 404 the record or module is outside what it may reach · 422 invalid input (problems[]) · 409 no_computer, invalid_state · 429 slow down
ai.record_computer_progress
Record computer progress — The computer worker reports status, steps, spending, approvals and the result.
Needs ai:handle · changes data
https://app.getera.io/api/v1/actions/ai.record_computer_progressInput
| Field | Type | Required | Notes |
|---|---|---|---|
id | uuid | yes | Session · id of computer_session |
worker | string | yes | Worker · max 200 |
status | string | Status · max 40 | |
activity | string | Activity · max 300 | |
provider | string | Provider · max 60 | |
stepCount | number | Steps · min 0 | |
costUsd | number | Cost · min 0 | |
currentUrl | string | Page · max 2000 | |
approval | object / array | Approval | |
clearApproval | boolean | Clear approval | |
result | string | Result · max 20000 | |
success | boolean | Success | |
events | object / array | Events |
Preconditions
The action is refused with 409 and one of these codes:
| Code | Refused when |
|---|---|
not_found | The session must exist in this workspace. |
not_your_session | Only the worker that claimed a session reports on it. |
already_stopped | A finished session takes no more progress. |
invalid_events | Timeline events need a known kind and a summary. |
Events it publishes: ai.computer_session_started, ai.computer_approval_requested, ai.computer_session_finished
What it writes: computer_session (update) — Updates status, activity, spending and the pending approval; computer_session_event (insert) — Adds the steps to the timeline
curl -X POST https://app.getera.io/api/v1/actions/ai.record_computer_progress \
-H "Authorization: Bearer $ERA_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{"id":"COMPUTER_SESSION_ID","worker":"Worker"}'{
"ok": true,
"result": "…",
"events": [
"ai.computer_session_started",
"ai.computer_approval_requested",
"ai.computer_session_finished"
]
}import { createEra } from "@getera/sdk"
const era = createEra({ apiKey: process.env.ERA_API_KEY })
const res = await era.actions.run("ai.record_computer_progress", {
id: "COMPUTER_SESSION_ID",
worker: "Worker"
})era ai record_computer_progress \
--id "COMPUTER_SESSION_ID" \
--worker "Worker"{
"name": "era__ai__record_computer_progress",
"arguments": {
"id": "COMPUTER_SESSION_ID",
"worker": "Worker"
}
}Errors: 401 no or expired credential · 403 the credential does not hold ai:handle · 404 the record or module is outside what it may reach · 422 invalid input (problems[]) · 409 not_found, not_your_session, already_stopped, invalid_events · 429 slow down
ai.record_decide_outcome
Confirm or correct one of Era’s decisions — Right or wrong — and if wrong, what was right. The next time Era decides the same question it learns from the corrections.
Needs ai:write · changes data
https://app.getera.io/api/v1/decide_decisions/actions/record_decide_outcome- Canonical address:
POST /api/v1/actions/ai.record_decide_outcome
Input
| Field | Type | Required | Notes |
|---|---|---|---|
decisionId | uuid | yes | Decision |
outcome | string (enum) | yes | Verdict · Allowed values: confirmed, corrected |
correctedAnswer | object / array | What was right | |
note | string | Note · max 500 | |
from | string (enum) | Judged by · Allowed values: person, workflow, era |
Preconditions
The action is refused with 409 and one of these codes:
| Code | Refused when |
|---|---|
decision_not_found | The decision must exist in this workspace. |
bad_correction | A correction names yes or no, one of the options, or one of the levels. |
same_answer | A correction differs from what Era decided. |
Events it publishes: ai.decide_outcome_recorded
What it writes: decide_decision (update) — Saves the verdict; corrections become examples for the next decisions
curl -X POST https://app.getera.io/api/v1/decide_decisions/actions/record_decide_outcome \
-H "Authorization: Bearer $ERA_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{"decisionId":"DECISION_ID","outcome":"confirmed"}'{
"ok": true,
"result": "…",
"events": [
"ai.decide_outcome_recorded"
]
}import { createEra } from "@getera/sdk"
const era = createEra({ apiKey: process.env.ERA_API_KEY })
const res = await era.decideDecisions.recordDecideOutcome({
decisionId: "DECISION_ID",
outcome: "confirmed"
})era decide_decisions record_decide_outcome \
--decision-id "DECISION_ID" \
--outcome "confirmed"{
"name": "era__ai__record_decide_outcome",
"arguments": {
"decisionId": "DECISION_ID",
"outcome": "confirmed"
}
}Errors: 401 no or expired credential · 403 the credential does not hold ai:write · 404 the record or module is outside what it may reach · 422 invalid input (problems[]) · 409 decision_not_found, bad_correction, same_answer · 429 slow down
ai.record_plan_limits
Record a subscription’s plan limits — The 5-hour and weekly usage its own harness reported. A used-up plan waits until it opens again; the router moves on.
Needs ai:read · changes data
https://app.getera.io/api/v1/ai_providers/{id}/actions/record_plan_limits- Canonical address:
POST /api/v1/actions/ai.record_plan_limits
Input
| Field | Type | Required | Notes |
|---|---|---|---|
id | uuid | yes | Filled from the path {id} · Subscription · id of ai_provider |
limits | object / array | yes | Plan limits |
Preconditions
The action is refused with 409 and one of these codes:
| Code | Refused when |
|---|---|
not_found | The subscription must be connected in this workspace. |
not_owner | Only its owner’s computer reports its limits. |
bad_plan_limits | Plan limits are a state, a source, a time and 5-hour / weekly windows of 0–100 %. |
Events it publishes: ai.subscription_limited, ai.subscription_recovered
What it writes: ai_provider (update) — Writes the plan’s windows; a used-up plan is limited until it opens again
curl -X POST https://app.getera.io/api/v1/ai_providers/AI_PROVIDER_ID/actions/record_plan_limits \
-H "Authorization: Bearer $ERA_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{"limits":{}}'{
"ok": true,
"result": "…",
"events": [
"ai.subscription_limited",
"ai.subscription_recovered"
]
}import { createEra } from "@getera/sdk"
const era = createEra({ apiKey: process.env.ERA_API_KEY })
const res = await era.aiProviders.recordPlanLimits("AI_PROVIDER_ID", {
limits: {}
})era ai_providers record_plan_limits AI_PROVIDER_ID --data '{"limits":{}}'{
"name": "era__ai__record_plan_limits",
"arguments": {
"id": "AI_PROVIDER_ID",
"limits": {}
}
}Errors: 401 no or expired credential · 403 the credential does not hold ai:read · 404 the record or module is outside what it may reach · 422 invalid input (problems[]) · 409 not_found, not_owner, bad_plan_limits · 429 slow down
ai.record_provider_check
Record a provider health check — Stores whether the provider answered a test call. The settings page’s Test button runs it.
Needs ai:manage · changes data
https://app.getera.io/api/v1/ai_providers/{id}/actions/record_provider_check- Canonical address:
POST /api/v1/actions/ai.record_provider_check
Input
| Field | Type | Required | Notes |
|---|---|---|---|
id | uuid | yes | Filled from the path {id} · Provider · id of ai_provider |
ok | boolean | yes | Answered |
error | string | Error · max 2000 |
Preconditions
The action is refused with 409 and one of these codes:
| Code | Refused when |
|---|---|
not_found | The provider must exist in this workspace. |
Events it publishes: ai.provider_checked
What it writes: ai_provider (update) — Writes status and the last error
curl -X POST https://app.getera.io/api/v1/ai_providers/AI_PROVIDER_ID/actions/record_provider_check \
-H "Authorization: Bearer $ERA_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{"ok":true}'{
"ok": true,
"result": "…",
"events": [
"ai.provider_checked"
]
}import { createEra } from "@getera/sdk"
const era = createEra({ apiKey: process.env.ERA_API_KEY })
const res = await era.aiProviders.recordProviderCheck("AI_PROVIDER_ID", {
ok: true
})era ai_providers record_provider_check AI_PROVIDER_ID \
--ok true{
"name": "era__ai__record_provider_check",
"arguments": {
"id": "AI_PROVIDER_ID",
"ok": true
}
}Errors: 401 no or expired credential · 403 the credential does not hold ai:manage · 404 the record or module is outside what it may reach · 422 invalid input (problems[]) · 409 not_found · 429 slow down
ai.record_provider_health
Record a scheduled provider health check — The health job’s answer for one provider: healthy or failing (runs route around a failing one), plus the key-rotation reminder. Machine-only: job ai.check_providers runs it as the platform.
Needs ai:handle · changes data
403 machine_only).https://app.getera.io/api/v1/ai_providers/{id}/actions/record_provider_health- Canonical address:
POST /api/v1/actions/ai.record_provider_health
Input
| Field | Type | Required | Notes |
|---|---|---|---|
id | uuid | yes | Filled from the path {id} · Provider · id of ai_provider |
ok | boolean | yes | Answered |
error | string | Error · max 2000 | |
latencyMs | number | Latency (ms) · min 0 |
Preconditions
The action is refused with 409 and one of these codes:
| Code | Refused when |
|---|---|
not_found | The provider must exist in this workspace. |
Events it publishes: ai.provider_unhealthy, ai.provider_recovered, ai.key_rotation_due
What it writes: ai_provider (update) — Writes status, failures, latency and the rotation stamp
Errors: 401 no or expired credential · 403 the credential does not hold ai:handle · 404 the record or module is outside what it may reach · 422 invalid input (problems[]) · 409 not_found · 429 slow down
ai.record_skill_run
Record a skill run — One line of a skill’s execution history. Machine-only: the run-skill endpoint and the chat’s compiled-skill injection call it.
Needs ai:read · changes data
403 machine_only).https://app.getera.io/api/v1/ai_skill_runs/actions/record_skill_run- Canonical address:
POST /api/v1/actions/ai.record_skill_run
Input
| Field | Type | Required | Notes |
|---|---|---|---|
skillId | string | yes | Skill · max 64 |
skillName | string | Name · max 200 | |
versionId | uuid | Version · id of ai_skill_version | |
mode | string (enum) | yes | Mode · Allowed values: load, exec, eval, compiled |
ok | boolean | yes | Succeeded |
durationMs | number | Duration (ms) · min 0 | |
costUsd | number | Cost (USD) · min 0 | |
error | string | Error · max 2000 |
What it writes: ai_skill_run (insert) — Appends the run
Errors: 401 no or expired credential · 403 the credential does not hold ai:read · 404 the record or module is outside what it may reach · 422 invalid input (problems[]) · 429 slow down
ai.record_subscription_state
Record a subscription’s state — What the last call or sign-in check said: connected, limit reached, sign in again, computer off.
Needs ai:read · changes data
https://app.getera.io/api/v1/ai_providers/{id}/actions/record_subscription_state- Canonical address:
POST /api/v1/actions/ai.record_subscription_state
Input
| Field | Type | Required | Notes |
|---|---|---|---|
id | uuid | yes | Filled from the path {id} · Subscription · id of ai_provider |
status | string (enum) | yes | Status · Allowed values: unchecked, healthy, failing, connecting, limited, relogin, offline, not_eligible |
detail | string | Detail · max 2000 | |
resetsAt | string | Limit resets at · max 40 | |
accountLabel | string | Account · max 160 | |
used | boolean | Was used |
Preconditions
The action is refused with 409 and one of these codes:
| Code | Refused when |
|---|---|
not_found | The subscription must be connected in this workspace. |
not_owner | Only its owner’s runs record its state. |
Events it publishes: ai.subscription_needs_login, ai.subscription_limited, ai.subscription_recovered
What it writes: ai_provider (update) — Writes status, the reason and the reset time
curl -X POST https://app.getera.io/api/v1/ai_providers/AI_PROVIDER_ID/actions/record_subscription_state \
-H "Authorization: Bearer $ERA_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{"status":"unchecked"}'{
"ok": true,
"result": "…",
"events": [
"ai.subscription_needs_login",
"ai.subscription_limited",
"ai.subscription_recovered"
]
}import { createEra } from "@getera/sdk"
const era = createEra({ apiKey: process.env.ERA_API_KEY })
const res = await era.aiProviders.recordSubscriptionState("AI_PROVIDER_ID", {
status: "unchecked"
})era ai_providers record_subscription_state AI_PROVIDER_ID \
--status "unchecked"{
"name": "era__ai__record_subscription_state",
"arguments": {
"id": "AI_PROVIDER_ID",
"status": "unchecked"
}
}Errors: 401 no or expired credential · 403 the credential does not hold ai:read · 404 the record or module is outside what it may reach · 422 invalid input (problems[]) · 409 not_found, not_owner · 429 slow down
ai.record_template_install
Record a marketplace install — Remembers which template an agent, skill or workflow came from and the apps it calls, so its screen can ask for the connections it still waits for.
Needs ai:write · changes data
https://app.getera.io/api/v1/ai_template_installs/actions/record_template_install- Canonical address:
POST /api/v1/actions/ai.record_template_install
Input
| Field | Type | Required | Notes |
|---|---|---|---|
templateId | string | yes | Template · max 120 |
templateName | string | yes | Template name · max 200 |
kind | string (enum) | yes | Kind · Allowed values: agent, skill, workflow |
instanceId | string | yes | Installed as · max 120 |
requiredApps | object / array | Apps it calls · ["gmail", "slack"] |
Events it publishes: ai.template_installed
What it writes: ai_template_install (upsert) — Writes the install record
curl -X POST https://app.getera.io/api/v1/ai_template_installs/actions/record_template_install \
-H "Authorization: Bearer $ERA_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{"templateId":"Template","templateName":"Template name","kind":"agent","instanceId":"Installed as"}'{
"ok": true,
"result": "…",
"events": [
"ai.template_installed"
]
}import { createEra } from "@getera/sdk"
const era = createEra({ apiKey: process.env.ERA_API_KEY })
const res = await era.aiTemplateInstalls.recordTemplateInstall({
templateId: "Template",
templateName: "Template name",
kind: "agent",
instanceId: "Installed as"
})era ai_template_installs record_template_install \
--template-id "Template" \
--template-name "Template name" \
--kind "agent" \
--instance-id "Installed as"{
"name": "era__ai__record_template_install",
"arguments": {
"templateId": "Template",
"templateName": "Template name",
"kind": "agent",
"instanceId": "Installed as"
}
}Errors: 401 no or expired credential · 403 the credential does not hold ai:write · 404 the record or module is outside what it may reach · 422 invalid input (problems[]) · 429 slow down
ai.record_turn
Record a turn — Appends one message, and what it called, to a conversation.
Needs ai:write · changes data
https://app.getera.io/api/v1/ai_conversations/{id}/actions/record_turn- Canonical address:
POST /api/v1/actions/ai.record_turn
Input
| Field | Type | Required | Notes |
|---|---|---|---|
conversationId | uuid | yes | Filled from the path {id} · Conversation · id of ai_conversation |
role | string (enum) | yes | From · Allowed values: user, assistant, system |
content | string | Text · max 200000 | |
toolCalls | object / array | What it called · A list of { name, input, ok, code }. One entry per action the assistant ran. |
Preconditions
The action is refused with 409 and one of these codes:
| Code | Refused when |
|---|---|
not_found | The conversation must exist in this workspace. |
bad_tool_calls | The tool-call record must be a list. |
What it writes: ai_message (insert) — Appends the turn; ai_conversation (update) — Moves the thread to the top and titles it
curl -X POST https://app.getera.io/api/v1/ai_conversations/AI_CONVERSATION_ID/actions/record_turn \
-H "Authorization: Bearer $ERA_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{"role":"user"}'{
"ok": true,
"result": "…",
"events": []
}import { createEra } from "@getera/sdk"
const era = createEra({ apiKey: process.env.ERA_API_KEY })
const res = await era.aiConversations.recordTurn("AI_CONVERSATION_ID", {
role: "user"
})era ai_conversations record_turn AI_CONVERSATION_ID \
--role "user"{
"name": "era__ai__record_turn",
"arguments": {
"conversationId": "AI_CONVERSATION_ID",
"role": "user"
}
}Errors: 401 no or expired credential · 403 the credential does not hold ai:write · 404 the record or module is outside what it may reach · 422 invalid input (problems[]) · 409 not_found, bad_tool_calls · 429 slow down
ai.record_usage
Record AI usage — Writes one run’s tokens and cost to the ledger and raises a budget alert when a threshold is crossed. Machine-only: the agent runner and the console call it.
Needs ai:read · changes data
403 machine_only).https://app.getera.io/api/v1/ai_usages/actions/record_usage- Canonical address:
POST /api/v1/actions/ai.record_usage
Input
| Field | Type | Required | Notes |
|---|---|---|---|
source | string (enum) | yes | Source · Allowed values: agent_run, console, era, skill_eval |
ref | string | Reference · max 120 | |
agentId | uuid | Agent · id of ai_agent | |
runId | uuid | Run · id of ai_run | |
conversationId | uuid | Conversation · id of ai_conversation | |
model | string | Model · max 120 | |
modelCalls | number | Model calls · min 0 | |
promptTokens | number | Prompt tokens · min 0 | |
completionTokens | number | Completion tokens · min 0 | |
cacheReadTokens | number | Cache read tokens · min 0 | |
cacheWriteTokens | number | Cache write tokens · min 0 | |
toolCalls | number | Tool calls · min 0 | |
toolResultChars | number | Tool result characters · min 0 | |
costUsd | number | Cost (USD) · min 0 |
Events it publishes: ai.budget_alert
What it writes: ai_usage (insert) — Appends the meter reading (idempotent per ref); ai_budget (update) — Stamps the alert key so an alert fires once
Errors: 401 no or expired credential · 403 the credential does not hold ai:read · 404 the record or module is outside what it may reach · 422 invalid input (problems[]) · 429 slow down
ai.refile_brain_fact
Re-file something Era learned — Düzenle: make it a fact, preference, rule or procedure; for only you, everyone or one module; with or without an end date.
Needs ai:write · changes data
https://app.getera.io/api/v1/brain_fact_reviews/actions/refile_brain_fact- Canonical address:
POST /api/v1/actions/ai.refile_brain_fact
Input
| Field | Type | Required | Notes |
|---|---|---|---|
memoryId | uuid | yes | What Era learned |
kind | string | Category · fact · preference · rule · procedure · max 20 | |
audience | string | For · person · workspace · module · max 20 | |
moduleCode | string | Module · max 64 | |
expiresAt | date-time | Until | |
noExpiry | boolean | No end date |
Preconditions
The action is refused with 409 and one of these codes:
| Code | Refused when |
|---|---|
fact_not_found | Era must know it, and it must not be someone else’s private fact. |
not_current | Only what Era knows now can be changed. |
bad_memory_kind | A memory is a fact, a preference, a rule or a procedure. |
module_required | A memory for one module names a module that exists. |
already_expired | An end date is in the future. |
unchanged | A re-file changes something. |
Events it publishes: ai.memory_refiled
What it writes: brain_fact_review (insert) — Records the re-file; the table applies it
curl -X POST https://app.getera.io/api/v1/brain_fact_reviews/actions/refile_brain_fact \
-H "Authorization: Bearer $ERA_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{"memoryId":"MEMORY_ID"}'{
"ok": true,
"result": "…",
"events": [
"ai.memory_refiled"
]
}import { createEra } from "@getera/sdk"
const era = createEra({ apiKey: process.env.ERA_API_KEY })
const res = await era.brainFactReviews.refileBrainFact({
memoryId: "MEMORY_ID"
})era brain_fact_reviews refile_brain_fact \
--memory-id "MEMORY_ID"{
"name": "era__ai__refile_brain_fact",
"arguments": {
"memoryId": "MEMORY_ID"
}
}Errors: 401 no or expired credential · 403 the credential does not hold ai:write · 404 the record or module is outside what it may reach · 422 invalid input (problems[]) · 409 fact_not_found, not_current, bad_memory_kind, module_required, already_expired, unchanged · 429 slow down
ai.remind_task
Send a task reminder — Raises ai.task_due (due within a day) or ai.task_overdue for the assignee, once per due date. Machine-only: the reminder sweep (ai.remind_tasks job) calls it as the platform.
Needs ai:handle · changes data
403 machine_only).https://app.getera.io/api/v1/ai_tasks/{id}/actions/remind_task- Canonical address:
POST /api/v1/actions/ai.remind_task
Input
| Field | Type | Required | Notes |
|---|---|---|---|
id | uuid | yes | Filled from the path {id} · Task · id of ai_task |
Preconditions
The action is refused with 409 and one of these codes:
| Code | Refused when |
|---|---|
not_found | The task must exist in this workspace. |
not_due | Only an open task due within a day, or past due, is reminded. |
already_reminded | Each reminder goes out once per due date. |
Events it publishes: ai.task_due, ai.task_overdue
What it writes: ai_task (update) — Stamps the reminder so it is sent once
Errors: 401 no or expired credential · 403 the credential does not hold ai:handle · 404 the record or module is outside what it may reach · 422 invalid input (problems[]) · 409 not_found, not_due, already_reminded · 429 slow down
ai.remove_provider
Remove an AI provider — Stops using this provider. Runs fall back to the deployment key, if there is one.
Needs ai:manage · removes or cannot be undone · asks a person to confirm when Era runs it
https://app.getera.io/api/v1/ai_providers/{id}/actions/remove_provider- Canonical address:
POST /api/v1/actions/ai.remove_provider
Input
| Field | Type | Required | Notes |
|---|---|---|---|
id | uuid | yes | Filled from the path {id} · Provider · id of ai_provider |
Preconditions
The action is refused with 409 and one of these codes:
| Code | Refused when |
|---|---|
not_found | The provider must exist in this workspace. |
Events it publishes: ai.provider_removed
What it writes: ai_provider (delete) — Removes the provider row
curl -X POST https://app.getera.io/api/v1/ai_providers/AI_PROVIDER_ID/actions/remove_provider \
-H "Authorization: Bearer $ERA_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{}'{
"ok": true,
"result": "…",
"events": [
"ai.provider_removed"
]
}import { createEra } from "@getera/sdk"
const era = createEra({ apiKey: process.env.ERA_API_KEY })
const res = await era.aiProviders.removeProvider("AI_PROVIDER_ID")era ai_providers remove_provider AI_PROVIDER_ID{
"name": "era__ai__remove_provider",
"arguments": {
"id": "AI_PROVIDER_ID"
}
}Errors: 401 no or expired credential · 403 the credential does not hold ai:manage · 404 the record or module is outside what it may reach · 422 invalid input (problems[]) · 409 not_found · 429 slow down
ai.reopen_task
Reopen a task — Puts a done or cancelled task back on the list.
Needs ai:write · changes data
https://app.getera.io/api/v1/ai_tasks/{id}/actions/reopen_task- Canonical address:
POST /api/v1/actions/ai.reopen_task
Input
| Field | Type | Required | Notes |
|---|---|---|---|
id | uuid | yes | Filled from the path {id} · Task · id of ai_task |
Preconditions
The action is refused with 409 and one of these codes:
| Code | Refused when |
|---|---|
not_found | The task must exist in this workspace. |
Events it publishes: ai.task_reopened
What it writes: ai_task (update) — Sets it open
curl -X POST https://app.getera.io/api/v1/ai_tasks/AI_TASK_ID/actions/reopen_task \
-H "Authorization: Bearer $ERA_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{}'{
"ok": true,
"result": "…",
"events": [
"ai.task_reopened"
]
}import { createEra } from "@getera/sdk"
const era = createEra({ apiKey: process.env.ERA_API_KEY })
const res = await era.aiTasks.reopenTask("AI_TASK_ID")era ai_tasks reopen_task AI_TASK_ID{
"name": "era__ai__reopen_task",
"arguments": {
"id": "AI_TASK_ID"
}
}Errors: 401 no or expired credential · 403 the credential does not hold ai:write · 404 the record or module is outside what it may reach · 422 invalid input (problems[]) · 409 not_found · 429 slow down
ai.resolve_erasure_candidate
Decide a possible match of an erasure request — Someone Era knows only shares the name of a customer whose data was erased: erase what Era learned about them too, or dismiss it as a different person.
Needs ai:manage · reaches outside (sends, publishes or charges) · asks a person to confirm when Era runs it
https://app.getera.io/api/v1/brain_erasures/actions/resolve_erasure_candidate- Canonical address:
POST /api/v1/actions/ai.resolve_erasure_candidate
Input
| Field | Type | Required | Notes |
|---|---|---|---|
id | uuid | yes | Possible match |
decision | string (enum) | yes | Decision · Allowed values: erase, dismiss |
Preconditions
The action is refused with 409 and one of these codes:
| Code | Refused when |
|---|---|
candidate_not_found | The possible match must exist in this workspace. |
already_resolved | A possible match is decided once. |
Events it publishes: ai.erasure_candidate_resolved
What it writes: brain_erasure_candidate (update) — Saves the decision; brain_erasure (insert) — An erasure is registered
curl -X POST https://app.getera.io/api/v1/brain_erasures/actions/resolve_erasure_candidate \
-H "Authorization: Bearer $ERA_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{"id":"ID_ID","decision":"erase"}'{
"ok": true,
"result": "…",
"events": [
"ai.erasure_candidate_resolved"
]
}import { createEra } from "@getera/sdk"
const era = createEra({ apiKey: process.env.ERA_API_KEY })
const res = await era.brainErasures.resolveErasureCandidate({
id: "ID_ID",
decision: "erase"
})era brain_erasures resolve_erasure_candidate \
--id "ID_ID" \
--decision "erase"{
"name": "era__ai__resolve_erasure_candidate",
"arguments": {
"id": "ID_ID",
"decision": "erase"
}
}Errors: 401 no or expired credential · 403 the credential does not hold ai:manage · 404 the record or module is outside what it may reach · 422 invalid input (problems[]) · 409 candidate_not_found, already_resolved · 429 slow down
ai.resume_computer_session
Resume a computer task — Lets a paused task continue.
Needs ai:handle · changes data
https://app.getera.io/api/v1/actions/ai.resume_computer_sessionInput
| Field | Type | Required | Notes |
|---|---|---|---|
id | uuid | yes | Session · id of computer_session |
Preconditions
The action is refused with 409 and one of these codes:
| Code | Refused when |
|---|---|
not_found | The session must exist in this workspace. |
not_paused | Only a paused task can be resumed. |
What it writes: computer_session (update) — Clears the pause flag; computer_session_event (insert) — Records the resume
curl -X POST https://app.getera.io/api/v1/actions/ai.resume_computer_session \
-H "Authorization: Bearer $ERA_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{"id":"COMPUTER_SESSION_ID"}'{
"ok": true,
"result": "…",
"events": []
}import { createEra } from "@getera/sdk"
const era = createEra({ apiKey: process.env.ERA_API_KEY })
const res = await era.actions.run("ai.resume_computer_session", {
id: "COMPUTER_SESSION_ID"
})era ai resume_computer_session \
--id "COMPUTER_SESSION_ID"{
"name": "era__ai__resume_computer_session",
"arguments": {
"id": "COMPUTER_SESSION_ID"
}
}Errors: 401 no or expired credential · 403 the credential does not hold ai:handle · 404 the record or module is outside what it may reach · 422 invalid input (problems[]) · 409 not_found, not_paused · 429 slow down
ai.review_brain_fact
Correct, forget or keep private something Era learned — Düzelt writes your wording, Unut stops Era using it, Gizli tut keeps it to you, Doğru confirms it, Taşı moves it to another space of its brain.
Needs ai:write · changes data
https://app.getera.io/api/v1/brain_fact_reviews/actions/review_brain_fact- Canonical address:
POST /api/v1/actions/ai.review_brain_fact
Input
| Field | Type | Required | Notes |
|---|---|---|---|
memoryId | uuid | yes | What Era learned |
decision | string (enum) | yes | Decision · Allowed values: correct, forget, keep_private, confirm, move |
correctedText | string | What is right · max 4000 | |
knowledgeBaseId | uuid | Move to |
Preconditions
The action is refused with 409 and one of these codes:
| Code | Refused when |
|---|---|
fact_not_found | Era must know it, and it must not be someone else’s private fact. |
not_current | Only what Era knows now can be changed. |
empty_correction | A correction says what is right. |
unchanged | A correction changes the wording; a move changes the space. |
knowledge_base_not_in_brain | A fact moves to a space of its own brain. |
Events it publishes: ai.brain_fact_reviewed
What it writes: brain_fact_review (insert) — Records the decision; the table applies it to what Era knows
curl -X POST https://app.getera.io/api/v1/brain_fact_reviews/actions/review_brain_fact \
-H "Authorization: Bearer $ERA_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{"memoryId":"MEMORY_ID","decision":"correct"}'{
"ok": true,
"result": "…",
"events": [
"ai.brain_fact_reviewed"
]
}import { createEra } from "@getera/sdk"
const era = createEra({ apiKey: process.env.ERA_API_KEY })
const res = await era.brainFactReviews.reviewBrainFact({
memoryId: "MEMORY_ID",
decision: "correct"
})era brain_fact_reviews review_brain_fact \
--memory-id "MEMORY_ID" \
--decision "correct"{
"name": "era__ai__review_brain_fact",
"arguments": {
"memoryId": "MEMORY_ID",
"decision": "correct"
}
}Errors: 401 no or expired credential · 403 the credential does not hold ai:write · 404 the record or module is outside what it may reach · 422 invalid input (problems[]) · 409 fact_not_found, not_current, empty_correction, unchanged, knowledge_base_not_in_brain · 429 slow down
ai.run_agent
Run an agent — Puts one agent run on the queue. An automation step can call this.
Needs ai:handle · changes data
https://app.getera.io/api/v1/actions/ai.run_agentInput
| Field | Type | Required | Notes |
|---|---|---|---|
agentId | uuid | yes | Agent · id of ai_agent |
prompt | string | What to do · max 20000 |
Preconditions
The action is refused with 409 and one of these codes:
| Code | Refused when |
|---|---|
not_found | The agent must exist in this workspace. |
agent_disabled | A switched-off agent cannot be run. |
budget_exceeded | The workspace or agent AI budget for today or this month is used up. |
Events it publishes: ai.agent_requested
curl -X POST https://app.getera.io/api/v1/actions/ai.run_agent \
-H "Authorization: Bearer $ERA_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{"agentId":"AI_AGENT_ID"}'{
"ok": true,
"result": "…",
"events": [
"ai.agent_requested"
]
}import { createEra } from "@getera/sdk"
const era = createEra({ apiKey: process.env.ERA_API_KEY })
const res = await era.actions.run("ai.run_agent", {
agentId: "AI_AGENT_ID"
})era ai run_agent \
--agent-id "AI_AGENT_ID"{
"name": "era__ai__run_agent",
"arguments": {
"agentId": "AI_AGENT_ID"
}
}Errors: 401 no or expired credential · 403 the credential does not hold ai:handle · 404 the record or module is outside what it may reach · 422 invalid input (problems[]) · 409 not_found, agent_disabled, budget_exceeded · 429 slow down
ai.save_computer_folder
Remember a folder — Gives a folder on your computer a name Era understands ("quickera", "Era reposu").
Needs ai:handle · changes data
https://app.getera.io/api/v1/computer_folders/actions/save_computer_folder- Canonical address:
POST /api/v1/actions/ai.save_computer_folder
Input
| Field | Type | Required | Notes |
|---|---|---|---|
name | string | yes | Name · max 80 |
path | string | yes | Full path · max 1000 |
aliases | object / array | Other names · Other ways you say it: ["era reposu", "era projesi"]. |
Preconditions
The action is refused with 409 and one of these codes:
| Code | Refused when |
|---|---|
computer_access_required | Only the workspace owner, or a member given computer access, can reach a computer. |
invalid_folder | A folder needs a name and a full path. |
invalid_aliases | Other names must be a list of names. |
What it writes: computer_folder (upsert) — Stores the name, the path and the other names
curl -X POST https://app.getera.io/api/v1/computer_folders/actions/save_computer_folder \
-H "Authorization: Bearer $ERA_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{"name":"Name","path":"Full path"}'{
"ok": true,
"result": "…",
"events": []
}import { createEra } from "@getera/sdk"
const era = createEra({ apiKey: process.env.ERA_API_KEY })
const res = await era.computerFolders.saveComputerFolder({
name: "Name",
path: "Full path"
})era computer_folders save_computer_folder \
--name "Name" \
--path "Full path"{
"name": "era__ai__save_computer_folder",
"arguments": {
"name": "Name",
"path": "Full path"
}
}Errors: 401 no or expired credential · 403 the credential does not hold ai:handle · 404 the record or module is outside what it may reach · 422 invalid input (problems[]) · 409 computer_access_required, invalid_folder, invalid_aliases · 429 slow down
ai.save_computer_policy
Save computer rules — Which sites and apps the computer may use, when it asks first, and how much it may spend.
Needs ai:manage · changes data
https://app.getera.io/api/v1/computer_policies/actions/save_computer_policy- Canonical address:
POST /api/v1/actions/ai.save_computer_policy
Input
| Field | Type | Required | Notes |
|---|---|---|---|
allowDomains | object / array | Only these sites | |
denyDomains | object / array | Never these sites | |
denyApps | object / array | Never these apps | |
approvalMode | string (enum) | Ask before · Allowed values: risky, every_action, never | |
maxSteps | number | Most steps per task · min 1 · max 200 | |
maxMinutes | number | Longest task (minutes) · min 1 · max 1440 | |
monthlyCloudHours | number | Cloud hours per person per month · min 0 · max 744 | |
defaultModel | string | Default model · max 200 | |
provider | string (enum) | Cloud computer provider · Allowed values: ``, boxd, e2b, digitalocean |
Preconditions
The action is refused with 409 and one of these codes:
| Code | Refused when |
|---|---|
invalid_domain | Sites are written like example.com or *.example.com. |
unknown_provider | The provider must be boxd, e2b or digitalocean. |
Events it publishes: ai.computer_policy_saved
What it writes: computer_policy (upsert) — Stores the workspace computer rules
curl -X POST https://app.getera.io/api/v1/computer_policies/actions/save_computer_policy \
-H "Authorization: Bearer $ERA_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{"allowDomains":{}}'{
"ok": true,
"result": "…",
"events": [
"ai.computer_policy_saved"
]
}import { createEra } from "@getera/sdk"
const era = createEra({ apiKey: process.env.ERA_API_KEY })
const res = await era.computerPolicies.saveComputerPolicy({
allowDomains: {}
})era computer_policies save_computer_policy --data '{"allowDomains":{}}'{
"name": "era__ai__save_computer_policy",
"arguments": {
"allowDomains": {}
}
}Errors: 401 no or expired credential · 403 the credential does not hold ai:manage · 404 the record or module is outside what it may reach · 422 invalid input (problems[]) · 409 invalid_domain, unknown_provider · 429 slow down
ai.set_action_cap
Set a daily allowance for Era — Lets Era do one kind of thing up to N times a day without asking you first (0 makes it ask every time again).
Needs ai:write · changes data
https://app.getera.io/api/v1/era_action_caps/actions/set_action_cap- Canonical address:
POST /api/v1/actions/ai.set_action_cap
Input
| Field | Type | Required | Notes |
|---|---|---|---|
kind | string | yes | What · max 80 |
dailyLimit | number | yes | Times a day · min 0 · max 1000 |
Preconditions
The action is refused with 409 and one of these codes:
| Code | Refused when |
|---|---|
not_cappable | Only something Era would otherwise ask about (not money, not deleting) can have an allowance. |
What it writes: era_action_cap (upsert) — Writes (or removes) your allowance for that kind
curl -X POST https://app.getera.io/api/v1/era_action_caps/actions/set_action_cap \
-H "Authorization: Bearer $ERA_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{"kind":"What","dailyLimit":1}'{
"ok": true,
"result": "…",
"events": []
}import { createEra } from "@getera/sdk"
const era = createEra({ apiKey: process.env.ERA_API_KEY })
const res = await era.eraActionCaps.setActionCap({
kind: "What",
dailyLimit: 1
})era era_action_caps set_action_cap \
--kind "What" \
--daily-limit 1{
"name": "era__ai__set_action_cap",
"arguments": {
"kind": "What",
"dailyLimit": 1
}
}Errors: 401 no or expired credential · 403 the credential does not hold ai:write · 404 the record or module is outside what it may reach · 422 invalid input (problems[]) · 409 not_cappable · 429 slow down
ai.set_agent_enabled
Switch an agent on or off — The only thing that decides whether an agent reacts to anything.
Needs ai:manage · changes data
https://app.getera.io/api/v1/ai_agents/{id}/actions/set_agent_enabled- Canonical address:
POST /api/v1/actions/ai.set_agent_enabled
Input
| Field | Type | Required | Notes |
|---|---|---|---|
id | uuid | yes | Filled from the path {id} · Agent · id of ai_agent |
enabled | boolean | yes | Running |
Preconditions
The action is refused with 409 and one of these codes:
| Code | Refused when |
|---|---|
not_found | The agent must exist in this workspace. |
no_instructions | An agent with no instructions cannot be switched on. |
Events it publishes: ai.agent_enabled, ai.agent_disabled
What it writes: ai_agent (update) — Flips the switch
curl -X POST https://app.getera.io/api/v1/ai_agents/AI_AGENT_ID/actions/set_agent_enabled \
-H "Authorization: Bearer $ERA_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{"enabled":true}'{
"ok": true,
"result": "…",
"events": [
"ai.agent_enabled",
"ai.agent_disabled"
]
}import { createEra } from "@getera/sdk"
const era = createEra({ apiKey: process.env.ERA_API_KEY })
const res = await era.aiAgents.setAgentEnabled("AI_AGENT_ID", {
enabled: true
})era ai_agents set_agent_enabled AI_AGENT_ID \
--enabled true{
"name": "era__ai__set_agent_enabled",
"arguments": {
"id": "AI_AGENT_ID",
"enabled": true
}
}Errors: 401 no or expired credential · 403 the credential does not hold ai:manage · 404 the record or module is outside what it may reach · 422 invalid input (problems[]) · 409 not_found, no_instructions · 429 slow down
ai.set_brain_insight_status
Mark an insight — Seen, done or dismissed.
Needs ai:write · changes data
https://app.getera.io/api/v1/brain_insights/actions/set_brain_insight_status- Canonical address:
POST /api/v1/actions/ai.set_brain_insight_status
Input
| Field | Type | Required | Notes |
|---|---|---|---|
id | uuid | yes | Insight |
status | string | yes | Status · new · seen · done · dismissed · max 20 |
Preconditions
The action is refused with 409 and one of these codes:
| Code | Refused when |
|---|---|
bad_status | The status is new, seen, done or dismissed. |
insight_not_found | The insight must exist in this workspace. |
Events it publishes: ai.brain_insight_updated
What it writes: brain_insight (update) — Saves the status
curl -X POST https://app.getera.io/api/v1/brain_insights/actions/set_brain_insight_status \
-H "Authorization: Bearer $ERA_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{"id":"ID_ID","status":"Status"}'{
"ok": true,
"result": "…",
"events": [
"ai.brain_insight_updated"
]
}import { createEra } from "@getera/sdk"
const era = createEra({ apiKey: process.env.ERA_API_KEY })
const res = await era.brainInsights.setBrainInsightStatus({
id: "ID_ID",
status: "Status"
})era brain_insights set_brain_insight_status \
--id "ID_ID" \
--status "Status"{
"name": "era__ai__set_brain_insight_status",
"arguments": {
"id": "ID_ID",
"status": "Status"
}
}Errors: 401 no or expired credential · 403 the credential does not hold ai:write · 404 the record or module is outside what it may reach · 422 invalid input (problems[]) · 409 bad_status, insight_not_found · 429 slow down
ai.set_budget
Set an AI budget — A daily and/or monthly USD cap for the workspace, or for one agent. Runs over the cap are refused.
Needs ai:manage · changes data
https://app.getera.io/api/v1/ai_budgets/actions/set_budget- Canonical address:
POST /api/v1/actions/ai.set_budget
Input
| Field | Type | Required | Notes |
|---|---|---|---|
agentId | uuid | Agent · Empty = the whole workspace. · id of ai_agent | |
dailyUsd | number (money) | Daily cap (USD) · min 0 | |
monthlyUsd | number (money) | Monthly cap (USD) · min 0 | |
alertPct | number | Alert at (%) · min 1 · max 100 |
Preconditions
The action is refused with 409 and one of these codes:
| Code | Refused when |
|---|---|
unknown_agent | The agent must exist in this workspace. |
Events it publishes: ai.budget_updated
What it writes: ai_budget (upsert) — Writes the cap
curl -X POST https://app.getera.io/api/v1/ai_budgets/actions/set_budget \
-H "Authorization: Bearer $ERA_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{"agentId":"AI_AGENT_ID"}'{
"ok": true,
"result": "…",
"events": [
"ai.budget_updated"
]
}import { createEra } from "@getera/sdk"
const era = createEra({ apiKey: process.env.ERA_API_KEY })
const res = await era.aiBudgets.setBudget({
agentId: "AI_AGENT_ID"
})era ai_budgets set_budget \
--agent-id "AI_AGENT_ID"{
"name": "era__ai__set_budget",
"arguments": {
"agentId": "AI_AGENT_ID"
}
}Errors: 401 no or expired credential · 403 the credential does not hold ai:manage · 404 the record or module is outside what it may reach · 422 invalid input (problems[]) · 409 unknown_agent · 429 slow down
ai.set_chat_member
Share a chat with a person — Adds a person to a chat with view or act access, and whether they may approve, or removes them.
Needs ai:write · changes data
https://app.getera.io/api/v1/era_chat_members/actions/set_chat_member- Canonical address:
POST /api/v1/actions/ai.set_chat_member
Input
| Field | Type | Required | Notes |
|---|---|---|---|
conversationId | uuid | yes | Chat |
userId | uuid | yes | Person |
access | string (enum) | yes | Access · Allowed values: view, act, none |
canApprove | boolean | Can approve |
Preconditions
The action is refused with 409 and one of these codes:
| Code | Refused when |
|---|---|
not_found | The chat must exist in this workspace. |
not_owner | Only the person who started the chat (or an admin) can share it. |
owner_is_member | The person who started the chat cannot be added to it. |
not_a_member | Only active members of the workspace can be added. |
approve_needs_act | Can approve requires can act. |
not_an_approver | Can approve requires the person to hold ai.approve in the workspace. |
Events it publishes: ai.chat_shared
What it writes: era_chat_member (upsert) — Writes (or removes) their seat in the chat
curl -X POST https://app.getera.io/api/v1/era_chat_members/actions/set_chat_member \
-H "Authorization: Bearer $ERA_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{"conversationId":"CONVERSATION_ID","userId":"USER_ID","access":"view"}'{
"ok": true,
"result": "…",
"events": [
"ai.chat_shared"
]
}import { createEra } from "@getera/sdk"
const era = createEra({ apiKey: process.env.ERA_API_KEY })
const res = await era.eraChatMembers.setChatMember({
conversationId: "CONVERSATION_ID",
userId: "USER_ID",
access: "view"
})era era_chat_members set_chat_member \
--conversation-id "CONVERSATION_ID" \
--user-id "USER_ID" \
--access "view"{
"name": "era__ai__set_chat_member",
"arguments": {
"conversationId": "CONVERSATION_ID",
"userId": "USER_ID",
"access": "view"
}
}Errors: 401 no or expired credential · 403 the credential does not hold ai:write · 404 the record or module is outside what it may reach · 422 invalid input (problems[]) · 409 not_found, not_owner, owner_is_member, not_a_member, approve_needs_act, not_an_approver · 429 slow down
ai.set_connection_share
Choose who may use a connection — Only me, my team, or everyone in the workspace — the owner decides, for every kind of connection.
Needs ai:write · reaches outside (sends, publishes or charges)
https://app.getera.io/api/v1/ai_providers/{id}/actions/set_connection_share- Canonical address:
POST /api/v1/actions/ai.set_connection_share
Input
| Field | Type | Required | Notes |
|---|---|---|---|
id | uuid | yes | Filled from the path {id} · Connection · id of ai_provider |
scope | string (enum) | yes | Who may use it · Allowed values: me, team, workspace |
teamId | uuid | Team |
Preconditions
The action is refused with 409 and one of these codes:
| Code | Refused when |
|---|---|
not_found | The connection must exist here. |
not_owner | Its owner, or a manager for a workspace-level one. |
team_required | Sharing with a team names the team. |
Events it publishes: ai.connection_shared
What it writes: ai_provider (update) — Writes share_scope and the team
curl -X POST https://app.getera.io/api/v1/ai_providers/AI_PROVIDER_ID/actions/set_connection_share \
-H "Authorization: Bearer $ERA_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{"scope":"me"}'{
"ok": true,
"result": "…",
"events": [
"ai.connection_shared"
]
}import { createEra } from "@getera/sdk"
const era = createEra({ apiKey: process.env.ERA_API_KEY })
const res = await era.aiProviders.setConnectionShare("AI_PROVIDER_ID", {
scope: "me"
})era ai_providers set_connection_share AI_PROVIDER_ID \
--scope "me"{
"name": "era__ai__set_connection_share",
"arguments": {
"id": "AI_PROVIDER_ID",
"scope": "me"
}
}Errors: 401 no or expired credential · 403 the credential does not hold ai:write · 404 the record or module is outside what it may reach · 422 invalid input (problems[]) · 409 not_found, not_owner, team_required · 429 slow down
ai.set_model_policy
Choose a model for a kind of work — Default, chat, agent, classify, summarize, extract, build or research — with an optional fallback. An empty model clears the row.
Needs ai:manage · changes data
https://app.getera.io/api/v1/ai_model_policies/actions/set_model_policy- Canonical address:
POST /api/v1/actions/ai.set_model_policy
Input
| Field | Type | Required | Notes |
|---|---|---|---|
taskClass | string (enum) | yes | Kind of work · Allowed values: default, chat, agent, classify, summarize, extract, build, research |
model | string | Model · max 120 | |
fallbackModel | string | Fallback model · max 120 |
Events it publishes: ai.model_policy_updated
What it writes: ai_model_policy (upsert) — Writes or clears the policy row
curl -X POST https://app.getera.io/api/v1/ai_model_policies/actions/set_model_policy \
-H "Authorization: Bearer $ERA_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{"taskClass":"default"}'{
"ok": true,
"result": "…",
"events": [
"ai.model_policy_updated"
]
}import { createEra } from "@getera/sdk"
const era = createEra({ apiKey: process.env.ERA_API_KEY })
const res = await era.aiModelPolicies.setModelPolicy({
taskClass: "default"
})era ai_model_policies set_model_policy \
--task-class "default"{
"name": "era__ai__set_model_policy",
"arguments": {
"taskClass": "default"
}
}Errors: 401 no or expired credential · 403 the credential does not hold ai:manage · 404 the record or module is outside what it may reach · 422 invalid input (problems[]) · 429 slow down
ai.set_provider
Save an AI provider — Points the workspace at a model provider and a key already sealed in the vault.
Needs ai:manage · changes data
https://app.getera.io/api/v1/ai_providers/actions/set_provider- Canonical address:
POST /api/v1/actions/ai.set_provider
Input
| Field | Type | Required | Notes |
|---|---|---|---|
provider | string (enum) | yes | Provider · Allowed values: anthropic, openai, google, xai, mistral, deepseek, zai, moonshot, groq, openrouter, azure_openai, ollama, openai_compatible, muapi, fal, replicate, bfl, ideogram, stability, luma, runway, kling, elevenlabs, deepgram, assemblyai, chatgpt, claude_code, gemini_cli, typesafe, grok_cli, copilot_cli, cursor_cli, kimi_cli, vibe_cli, opencode_cli, amp_cli, kiro_cli, cline_cli, auggie_cli |
secretRef | string | Vault key · vault:<id> from apps.store_secret · max 64 | |
keyHint | string | Key (masked) · max 40 | |
baseUrl | string | Base URL · max 300 | |
label | string | Label · max 120 | |
makeDefault | boolean | Use by default | |
personal | boolean | Only for me · My own key: only my requests use it. |
Preconditions
The action is refused with 409 and one of these codes:
| Code | Refused when |
|---|---|
bad_secret_ref | The key must be a vault secret of this workspace. |
subscription_provider | A subscription (ChatGPT, Claude, Antigravity plan) is connected by signing in, not with a key. |
base_url_required | Azure OpenAI and a custom gateway need their endpoint address. |
Events it publishes: ai.provider_updated
What it writes: ai_provider (upsert) — Writes the provider row (never the key)
curl -X POST https://app.getera.io/api/v1/ai_providers/actions/set_provider \
-H "Authorization: Bearer $ERA_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{"provider":"anthropic"}'{
"ok": true,
"result": "…",
"events": [
"ai.provider_updated"
]
}import { createEra } from "@getera/sdk"
const era = createEra({ apiKey: process.env.ERA_API_KEY })
const res = await era.aiProviders.setProvider({
provider: "anthropic"
})era ai_providers set_provider \
--provider "anthropic"{
"name": "era__ai__set_provider",
"arguments": {
"provider": "anthropic"
}
}Errors: 401 no or expired credential · 403 the credential does not hold ai:manage · 404 the record or module is outside what it may reach · 422 invalid input (problems[]) · 409 bad_secret_ref, subscription_provider, base_url_required · 429 slow down
ai.set_skill_policy
Set a skill’s permissions — Published or not, which connected apps it may call, which hosts its sandbox may reach (nothing by default) and which vault secrets it may read.
Needs ai:manage · changes data
https://app.getera.io/api/v1/ai_skill_releases/actions/set_skill_policy- Canonical address:
POST /api/v1/actions/ai.set_skill_policy
Input
| Field | Type | Required | Notes |
|---|---|---|---|
skillId | string | yes | Skill · max 64 |
published | boolean | Published | |
allowedIntegrations | object / array | Apps it may call · ["gmail", "crm"] | |
allowedDomains | object / array | Hosts it may reach · ["api.example.com", "*.example.org"] | |
secrets | object / array | Secrets it may read · [{ "name": "API_KEY", "ref": "vault:<id>" }] |
Preconditions
The action is refused with 409 and one of these codes:
| Code | Refused when |
|---|---|
bad_policy | Apps, hosts and secret names must be well-formed lists. |
bad_secret_ref | A secret must be a vault ref of this workspace. |
Events it publishes: ai.skill_policy_updated
What it writes: ai_skill_release (upsert) — Writes the release policy
curl -X POST https://app.getera.io/api/v1/ai_skill_releases/actions/set_skill_policy \
-H "Authorization: Bearer $ERA_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{"skillId":"Skill"}'{
"ok": true,
"result": "…",
"events": [
"ai.skill_policy_updated"
]
}import { createEra } from "@getera/sdk"
const era = createEra({ apiKey: process.env.ERA_API_KEY })
const res = await era.aiSkillReleases.setSkillPolicy({
skillId: "Skill"
})era ai_skill_releases set_skill_policy \
--skill-id "Skill"{
"name": "era__ai__set_skill_policy",
"arguments": {
"skillId": "Skill"
}
}Errors: 401 no or expired credential · 403 the credential does not hold ai:manage · 404 the record or module is outside what it may reach · 422 invalid input (problems[]) · 409 bad_policy, bad_secret_ref · 429 slow down
ai.set_skill_release
Pause, resume or record an install — Pausing stops every agent from being offered the skill. Recording an install keeps the template and version it came from.
Needs ai:manage · changes data
https://app.getera.io/api/v1/ai_skill_releases/actions/set_skill_release- Canonical address:
POST /api/v1/actions/ai.set_skill_release
Input
| Field | Type | Required | Notes |
|---|---|---|---|
skillId | string | yes | Skill · max 64 |
paused | boolean | Paused | |
sourceTemplate | string | Template · max 120 | |
sourceVersion | string | Template version · max 40 |
Events it publishes: ai.skill_paused, ai.skill_resumed, ai.skill_installed
What it writes: ai_skill_release (upsert) — Writes the release row
curl -X POST https://app.getera.io/api/v1/ai_skill_releases/actions/set_skill_release \
-H "Authorization: Bearer $ERA_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{"skillId":"Skill"}'{
"ok": true,
"result": "…",
"events": [
"ai.skill_paused",
"ai.skill_resumed",
"ai.skill_installed"
]
}import { createEra } from "@getera/sdk"
const era = createEra({ apiKey: process.env.ERA_API_KEY })
const res = await era.aiSkillReleases.setSkillRelease({
skillId: "Skill"
})era ai_skill_releases set_skill_release \
--skill-id "Skill"{
"name": "era__ai__set_skill_release",
"arguments": {
"skillId": "Skill"
}
}Errors: 401 no or expired credential · 403 the credential does not hold ai:manage · 404 the record or module is outside what it may reach · 422 invalid input (problems[]) · 429 slow down
ai.set_source_choice
Choose where AI runs — For one Era, workflow, brain, voice agent, the creative studio, the computer or my own chat: which subscription or key, and what it may fall back to.
Needs ai:write · changes data
https://app.getera.io/api/v1/ai_source_choices/actions/set_source_choice- Canonical address:
POST /api/v1/actions/ai.set_source_choice
Input
| Field | Type | Required | Notes |
|---|---|---|---|
subjectType | string (enum) | yes | For · Allowed values: chat, agent, workflow, brain, voice_agent, creative, computer |
subjectId | string | yes | Which one · max 120 |
mode | string (enum) | AI source · Allowed values: auto, byok, byos, connection | |
connectionId | uuid | Connection · id of ai_provider | |
model | string | Model · max 160 | |
allowShared | boolean | A colleague’s shared connection | |
allowByok | boolean | Company keys | |
whenOffline | string (enum) | If the computer is off · Allowed values: wait, fallback |
Preconditions
The action is refused with 409 and one of these codes:
| Code | Refused when |
|---|---|
bad_subject | An Era, a workflow, a brain, a voice agent, creative, computer or chat. |
not_owner | A person’s chat default is set by that person. |
connection_not_usable | Only your own connection, a workspace one, or one shared with you. |
connection_required | “This one” names the connection. |
Events it publishes: ai.source_choice_updated
What it writes: ai_source_choice (upsert) — One row per AI-using thing
curl -X POST https://app.getera.io/api/v1/ai_source_choices/actions/set_source_choice \
-H "Authorization: Bearer $ERA_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{"subjectType":"chat","subjectId":"Which one"}'{
"ok": true,
"result": "…",
"events": [
"ai.source_choice_updated"
]
}import { createEra } from "@getera/sdk"
const era = createEra({ apiKey: process.env.ERA_API_KEY })
const res = await era.aiSourceChoices.setSourceChoice({
subjectType: "chat",
subjectId: "Which one"
})era ai_source_choices set_source_choice \
--subject-type "chat" \
--subject-id "Which one"{
"name": "era__ai__set_source_choice",
"arguments": {
"subjectType": "chat",
"subjectId": "Which one"
}
}Errors: 401 no or expired credential · 403 the credential does not hold ai:write · 404 the record or module is outside what it may reach · 422 invalid input (problems[]) · 409 bad_subject, not_owner, connection_not_usable, connection_required · 429 slow down
ai.set_subscription_use
Choose where my subscription is used — Era chat, my Eras, workflows, the brain, search memory, creative, voice and the computer — each can be switched off.
Needs ai:write · changes data
https://app.getera.io/api/v1/ai_providers/{id}/actions/set_subscription_use- Canonical address:
POST /api/v1/actions/ai.set_subscription_use
Input
| Field | Type | Required | Notes |
|---|---|---|---|
id | uuid | yes | Filled from the path {id} · Subscription · id of ai_provider |
chat | boolean | Era chat | |
agents | boolean | My Eras | |
workflows | boolean | Workflows | |
computer | boolean | Computer | |
brain | boolean | Brain | |
embeddings | boolean | Search memory | |
creative | boolean | Creative studio | |
voice | boolean | Voice |
Preconditions
The action is refused with 409 and one of these codes:
| Code | Refused when |
|---|---|
not_found | The subscription must be connected in this workspace. |
not_owner | Only its owner chooses where it is used. |
What it writes: ai_provider (update) — Writes the four switches
curl -X POST https://app.getera.io/api/v1/ai_providers/AI_PROVIDER_ID/actions/set_subscription_use \
-H "Authorization: Bearer $ERA_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{"chat":true}'{
"ok": true,
"result": "…",
"events": []
}import { createEra } from "@getera/sdk"
const era = createEra({ apiKey: process.env.ERA_API_KEY })
const res = await era.aiProviders.setSubscriptionUse("AI_PROVIDER_ID", {
chat: true
})era ai_providers set_subscription_use AI_PROVIDER_ID \
--chat true{
"name": "era__ai__set_subscription_use",
"arguments": {
"id": "AI_PROVIDER_ID",
"chat": true
}
}Errors: 401 no or expired credential · 403 the credential does not hold ai:write · 404 the record or module is outside what it may reach · 422 invalid input (problems[]) · 409 not_found, not_owner · 429 slow down
ai.share_chat
Share a chat — Makes a chat private or visible to the workspace, and turns its read-only link on or off.
Needs ai:write · reaches outside (sends, publishes or charges)
https://app.getera.io/api/v1/era_chat_shares/actions/share_chat- Canonical address:
POST /api/v1/actions/ai.share_chat
Input
| Field | Type | Required | Notes |
|---|---|---|---|
conversationId | uuid | yes | Chat |
visibility | string (enum) | Who sees it · Allowed values: private, workspace | |
link | string (enum) | Read-only link · Allowed values: keep, new, off | |
linkExpiresAt | date-time | Link expires |
Preconditions
The action is refused with 409 and one of these codes:
| Code | Refused when |
|---|---|
not_found | The chat must exist in this workspace. |
not_owner | Only the person who started the chat (or an admin) can share it. |
bad_expiry | A link has to expire in the future. |
Events it publishes: ai.chat_visibility_changed
What it writes: era_chat_share (upsert) — Stores who sees the chat, the link hash and its expiry
curl -X POST https://app.getera.io/api/v1/era_chat_shares/actions/share_chat \
-H "Authorization: Bearer $ERA_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{"conversationId":"CONVERSATION_ID"}'{
"ok": true,
"result": "…",
"events": [
"ai.chat_visibility_changed"
]
}import { createEra } from "@getera/sdk"
const era = createEra({ apiKey: process.env.ERA_API_KEY })
const res = await era.eraChatShares.shareChat({
conversationId: "CONVERSATION_ID"
})era era_chat_shares share_chat \
--conversation-id "CONVERSATION_ID"{
"name": "era__ai__share_chat",
"arguments": {
"conversationId": "CONVERSATION_ID"
}
}Errors: 401 no or expired credential · 403 the credential does not hold ai:write · 404 the record or module is outside what it may reach · 422 invalid input (problems[]) · 409 not_found, not_owner, bad_expiry · 429 slow down
ai.snapshot_skill
Save a skill version — Freezes the skill’s current definition as the next numbered version.
Needs ai:write · changes data
https://app.getera.io/api/v1/ai_skill_versions/actions/snapshot_skill- Canonical address:
POST /api/v1/actions/ai.snapshot_skill
Input
| Field | Type | Required | Notes |
|---|---|---|---|
skillId | string | yes | Skill · max 64 |
definition | object / array | yes | Definition · { kind, content, code, language, inputSchema, enrichOp, enrichConfig, description } |
note | string | Note · max 2000 |
Preconditions
The action is refused with 409 and one of these codes:
| Code | Refused when |
|---|---|
bad_definition | The definition must be an object. |
Events it publishes: ai.skill_version_created
What it writes: ai_skill_version (insert) — Writes the version
curl -X POST https://app.getera.io/api/v1/ai_skill_versions/actions/snapshot_skill \
-H "Authorization: Bearer $ERA_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{"skillId":"Skill","definition":{}}'{
"ok": true,
"result": "…",
"events": [
"ai.skill_version_created"
]
}import { createEra } from "@getera/sdk"
const era = createEra({ apiKey: process.env.ERA_API_KEY })
const res = await era.aiSkillVersions.snapshotSkill({
skillId: "Skill",
definition: {}
})era ai_skill_versions snapshot_skill --data '{"skillId":"Skill","definition":{}}'{
"name": "era__ai__snapshot_skill",
"arguments": {
"skillId": "Skill",
"definition": {}
}
}Errors: 401 no or expired credential · 403 the credential does not hold ai:write · 404 the record or module is outside what it may reach · 422 invalid input (problems[]) · 409 bad_definition · 429 slow down
ai.start_computer
Turn on my cloud computer — Wakes your cloud computer with its disk as you left it.
Needs ai:handle · changes data
https://app.getera.io/api/v1/computer_machines/actions/start_computer- Canonical address:
POST /api/v1/actions/ai.start_computer
Input
This action takes no input.
Preconditions
The action is refused with 409 and one of these codes:
| Code | Refused when |
|---|---|
no_computer | You need a cloud computer first. |
already_running | It is already on. |
computer_access_required | Only the workspace owner, or a member given computer access, can reach a computer. |
hours_used_up | The person’s cloud hours this month must be under the plan’s hours and the workspace cap. |
Events it publishes: ai.computer_machine_requested
What it writes: computer_machine (update) — Asks the worker to start it
curl -X POST https://app.getera.io/api/v1/computer_machines/actions/start_computer \
-H "Authorization: Bearer $ERA_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{}'{
"ok": true,
"result": "…",
"events": [
"ai.computer_machine_requested"
]
}import { createEra } from "@getera/sdk"
const era = createEra({ apiKey: process.env.ERA_API_KEY })
const res = await era.computerMachines.startComputer()era computer_machines start_computer{
"name": "era__ai__start_computer",
"arguments": {}
}Errors: 401 no or expired credential · 403 the credential does not hold ai:handle · 404 the record or module is outside what it may reach · 422 invalid input (problems[]) · 409 no_computer, already_running, computer_access_required, hours_used_up · 429 slow down
ai.start_computer_session
Give the computer a task — Queues a browser or desktop task on Era’s browser, your cloud computer or your own PC. Risky steps wait for your approval.
Needs ai:handle · changes data
https://app.getera.io/api/v1/actions/ai.start_computer_sessionInput
| Field | Type | Required | Notes |
|---|---|---|---|
title | string | Name · max 200 | |
objective | string | What should it do? · max 4000 | |
kind | string (enum) | Kind · Allowed values: browser, desktop | |
target | string (enum) | Where · Allowed values: server, cloud, device | |
startUrl | string | Start page · max 2000 | |
model | string | Model · max 200 | |
maxSteps | number | Most steps · min 1 · max 200 | |
deviceId | string | Device · max 100 | |
agentId | uuid | Agent | |
source | string (enum) | Asked by · Allowed values: person, era, workflow, agent | |
sourceRef | string | Source reference · max 300 |
Preconditions
The action is refused with 409 and one of these codes:
| Code | Refused when |
|---|---|
empty_title | A task needs a clear purpose. |
blocked_start_url | The start page must be allowed by the workspace computer rules. |
no_cloud_computer | A cloud task needs the person’s cloud computer. |
no_device | A task on your own PC must name the device. |
too_many_running | At most three computer tasks run at once in a workspace. |
computer_access_required | Only the workspace owner, or a member given computer access, can reach a computer. |
Events it publishes: ai.computer_session_queued
What it writes: computer_session (insert) — Creates the queued task with its step limit and rules; computer_session_event (insert) — Records that it was queued
curl -X POST https://app.getera.io/api/v1/actions/ai.start_computer_session \
-H "Authorization: Bearer $ERA_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{"title":"Name"}'{
"ok": true,
"result": "…",
"events": [
"ai.computer_session_queued"
]
}import { createEra } from "@getera/sdk"
const era = createEra({ apiKey: process.env.ERA_API_KEY })
const res = await era.actions.run("ai.start_computer_session", {
title: "Name"
})era ai start_computer_session \
--title "Name"{
"name": "era__ai__start_computer_session",
"arguments": {
"title": "Name"
}
}Errors: 401 no or expired credential · 403 the credential does not hold ai:handle · 404 the record or module is outside what it may reach · 422 invalid input (problems[]) · 409 empty_title, blocked_start_url, no_cloud_computer, no_device, too_many_running, computer_access_required · 429 slow down
ai.start_conversation
Start a conversation — Opens a thread with Era, or with one saved agent.
Needs ai:write · changes data
https://app.getera.io/api/v1/ai_conversations/actions/start_conversation- Canonical address:
POST /api/v1/actions/ai.start_conversation
Input
| Field | Type | Required | Notes |
|---|---|---|---|
title | string | Title · max 200 | |
agentId | uuid | Agent · id of ai_agent |
Preconditions
The action is refused with 409 and one of these codes:
| Code | Refused when |
|---|---|
unknown_agent | The agent must exist in this workspace. |
Events it publishes: ai.conversation_started
What it writes: ai_conversation (insert) — Opens the thread
curl -X POST https://app.getera.io/api/v1/ai_conversations/actions/start_conversation \
-H "Authorization: Bearer $ERA_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{"title":"Title"}'{
"ok": true,
"result": "…",
"events": [
"ai.conversation_started"
]
}import { createEra } from "@getera/sdk"
const era = createEra({ apiKey: process.env.ERA_API_KEY })
const res = await era.aiConversations.startConversation({
title: "Title"
})era ai_conversations start_conversation \
--title "Title"{
"name": "era__ai__start_conversation",
"arguments": {
"title": "Title"
}
}Errors: 401 no or expired credential · 403 the credential does not hold ai:write · 404 the record or module is outside what it may reach · 422 invalid input (problems[]) · 409 unknown_agent · 429 slow down
ai.steer_computer_session
Tell a running computer task something — Adds your instructions to a task while it runs; the computer reads them before its next step.
Needs ai:handle · changes data
https://app.getera.io/api/v1/actions/ai.steer_computer_sessionInput
| Field | Type | Required | Notes |
|---|---|---|---|
id | uuid | yes | Session · id of computer_session |
text | string | yes | Message · max 4000 |
Preconditions
The action is refused with 409 and one of these codes:
| Code | Refused when |
|---|---|
not_found | The session must exist in this workspace. |
not_running | Only a task that is still running takes new instructions. |
empty_message | The message must say something. |
What it writes: computer_session_event (insert) — Adds the message to the timeline, where the worker reads it
curl -X POST https://app.getera.io/api/v1/actions/ai.steer_computer_session \
-H "Authorization: Bearer $ERA_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{"id":"COMPUTER_SESSION_ID","text":"Message"}'{
"ok": true,
"result": "…",
"events": []
}import { createEra } from "@getera/sdk"
const era = createEra({ apiKey: process.env.ERA_API_KEY })
const res = await era.actions.run("ai.steer_computer_session", {
id: "COMPUTER_SESSION_ID",
text: "Message"
})era ai steer_computer_session \
--id "COMPUTER_SESSION_ID" \
--text "Message"{
"name": "era__ai__steer_computer_session",
"arguments": {
"id": "COMPUTER_SESSION_ID",
"text": "Message"
}
}Errors: 401 no or expired credential · 403 the credential does not hold ai:handle · 404 the record or module is outside what it may reach · 422 invalid input (problems[]) · 409 not_found, not_running, empty_message · 429 slow down
ai.stop_all_computer_sessions
Emergency stop — Stops every computer task running in this workspace.
Needs ai:handle · reaches outside (sends, publishes or charges) · asks a person to confirm when Era runs it
https://app.getera.io/api/v1/actions/ai.stop_all_computer_sessionsInput
This action takes no input.
Preconditions
The action is refused with 409 and one of these codes:
| Code | Refused when |
|---|---|
nothing_running | Something must be running to stop. |
Events it publishes: ai.computer_session_stopped, ai.computer_session_finished
What it writes: computer_session (update) — Marks every running task stopping; computer_session_event (insert) — Records the emergency stop on each
curl -X POST https://app.getera.io/api/v1/actions/ai.stop_all_computer_sessions \
-H "Authorization: Bearer $ERA_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{}'{
"ok": true,
"result": "…",
"events": [
"ai.computer_session_stopped",
"ai.computer_session_finished"
]
}import { createEra } from "@getera/sdk"
const era = createEra({ apiKey: process.env.ERA_API_KEY })
const res = await era.actions.run("ai.stop_all_computer_sessions")era ai stop_all_computer_sessions{
"name": "era__ai__stop_all_computer_sessions",
"arguments": {}
}Errors: 401 no or expired credential · 403 the credential does not hold ai:handle · 404 the record or module is outside what it may reach · 422 invalid input (problems[]) · 409 nothing_running · 429 slow down
ai.stop_computer_session
Stop a computer task — Stops the task within one step and leaves its history in place.
Needs ai:handle · reaches outside (sends, publishes or charges) · asks a person to confirm when Era runs it
https://app.getera.io/api/v1/actions/ai.stop_computer_sessionInput
| Field | Type | Required | Notes |
|---|---|---|---|
id | uuid | yes | Session · id of computer_session |
Preconditions
The action is refused with 409 and one of these codes:
| Code | Refused when |
|---|---|
not_found | The session must exist in this workspace. |
already_stopped | A finished session cannot be stopped again. |
Events it publishes: ai.computer_session_stopped, ai.computer_session_finished
What it writes: computer_session (update) — Marks the session stopping or stopped; computer_session_event (insert) — Records who stopped it
curl -X POST https://app.getera.io/api/v1/actions/ai.stop_computer_session \
-H "Authorization: Bearer $ERA_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{"id":"COMPUTER_SESSION_ID"}'{
"ok": true,
"result": "…",
"events": [
"ai.computer_session_stopped",
"ai.computer_session_finished"
]
}import { createEra } from "@getera/sdk"
const era = createEra({ apiKey: process.env.ERA_API_KEY })
const res = await era.actions.run("ai.stop_computer_session", {
id: "COMPUTER_SESSION_ID"
})era ai stop_computer_session \
--id "COMPUTER_SESSION_ID"{
"name": "era__ai__stop_computer_session",
"arguments": {
"id": "COMPUTER_SESSION_ID"
}
}Errors: 401 no or expired credential · 403 the credential does not hold ai:handle · 404 the record or module is outside what it may reach · 422 invalid input (problems[]) · 409 not_found, already_stopped · 429 slow down
ai.unbind_brain
Take a brain away — The Era, workflow or voice agent stops knowing from this brain.
Needs ai:manage · removes or cannot be undone
https://app.getera.io/api/v1/brain_bindings/actions/unbind_brain- Canonical address:
POST /api/v1/actions/ai.unbind_brain
Input
| Field | Type | Required | Notes |
|---|---|---|---|
subjectType | string | yes | For · agent · workflow · voice_agent · era_chat · meeting · team · role · max 20 |
subjectId | string | yes | Which one · max 120 |
brainId | uuid | yes | Brain |
Preconditions
The action is refused with 409 and one of these codes:
| Code | Refused when |
|---|---|
bad_subject | It names an Era, workflow, voice agent, meeting or Era chat. |
brain_not_found | The brain must exist in this workspace. |
not_bound | The brain must be connected to it. |
Events it publishes: ai.brain_unbound
What it writes: brain_binding (delete) — Disconnects the brain
curl -X POST https://app.getera.io/api/v1/brain_bindings/actions/unbind_brain \
-H "Authorization: Bearer $ERA_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{"subjectType":"For","subjectId":"Which one","brainId":"BRAIN_ID"}'{
"ok": true,
"result": "…",
"events": [
"ai.brain_unbound"
]
}import { createEra } from "@getera/sdk"
const era = createEra({ apiKey: process.env.ERA_API_KEY })
const res = await era.brainBindings.unbindBrain({
subjectType: "For",
subjectId: "Which one",
brainId: "BRAIN_ID"
})era brain_bindings unbind_brain \
--subject-type "For" \
--subject-id "Which one" \
--brain-id "BRAIN_ID"{
"name": "era__ai__unbind_brain",
"arguments": {
"subjectType": "For",
"subjectId": "Which one",
"brainId": "BRAIN_ID"
}
}Errors: 401 no or expired credential · 403 the credential does not hold ai:manage · 404 the record or module is outside what it may reach · 422 invalid input (problems[]) · 409 bad_subject, brain_not_found, not_bound · 429 slow down
ai.uninstall_skill
Uninstall a skill — Drops the skill’s versions and release record. The screen removes the skill itself.
Needs ai:delete · removes or cannot be undone · asks a person to confirm when Era runs it
https://app.getera.io/api/v1/ai_skill_releases/actions/uninstall_skill- Canonical address:
POST /api/v1/actions/ai.uninstall_skill
Input
| Field | Type | Required | Notes |
|---|---|---|---|
skillId | string | yes | Skill · max 64 |
Events it publishes: ai.skill_uninstalled
What it writes: ai_skill_release (delete) — Removes the release row; ai_skill_version (delete) — Removes its versions
curl -X POST https://app.getera.io/api/v1/ai_skill_releases/actions/uninstall_skill \
-H "Authorization: Bearer $ERA_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{"skillId":"Skill"}'{
"ok": true,
"result": "…",
"events": [
"ai.skill_uninstalled"
]
}import { createEra } from "@getera/sdk"
const era = createEra({ apiKey: process.env.ERA_API_KEY })
const res = await era.aiSkillReleases.uninstallSkill({
skillId: "Skill"
})era ai_skill_releases uninstall_skill \
--skill-id "Skill"{
"name": "era__ai__uninstall_skill",
"arguments": {
"skillId": "Skill"
}
}Errors: 401 no or expired credential · 403 the credential does not hold ai:delete · 404 the record or module is outside what it may reach · 422 invalid input (problems[]) · 429 slow down
ai.update_agent
Change an agent — Rewrites its brief, its model, its tool budget or what wakes it.
Needs ai:manage · changes data
https://app.getera.io/api/v1/ai_agents/{id}/actions/update_agent- Canonical address:
POST /api/v1/actions/ai.update_agent
Input
| Field | Type | Required | Notes |
|---|---|---|---|
id | uuid | yes | Filled from the path {id} · Agent · id of ai_agent |
name | string | Name · max 160 | |
instructions | string | Instructions · max 20000 | |
description | string | Description · max 2000 | |
model | string | Model · max 120 | |
allowedModules | object / array | Limited to these modules · A list of module codes. Empty means every module its author can already use. | |
wakesOn | object / array | Wakes up on · A list of event names — crm.lead_won, crm.* or *. Empty means it only runs when asked. | |
maxSteps | number | Tool calls per run · min 1 · max 40 |
Preconditions
The action is refused with 409 and one of these codes:
| Code | Refused when |
|---|---|
not_found | The agent must exist in this workspace. |
empty_name | An agent needs a name. |
bad_modules | It may only be limited to modules this platform registers. |
bad_trigger | A wake-up trigger must be an event some module declares. |
Events it publishes: ai.agent_updated
What it writes: ai_agent (update) — Rewrites the agent
curl -X POST https://app.getera.io/api/v1/ai_agents/AI_AGENT_ID/actions/update_agent \
-H "Authorization: Bearer $ERA_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{"name":"Name"}'{
"ok": true,
"result": "…",
"events": [
"ai.agent_updated"
]
}import { createEra } from "@getera/sdk"
const era = createEra({ apiKey: process.env.ERA_API_KEY })
const res = await era.aiAgents.updateAgent("AI_AGENT_ID", {
name: "Name"
})era ai_agents update_agent AI_AGENT_ID \
--name "Name"{
"name": "era__ai__update_agent",
"arguments": {
"id": "AI_AGENT_ID",
"name": "Name"
}
}Errors: 401 no or expired credential · 403 the credential does not hold ai:manage · 404 the record or module is outside what it may reach · 422 invalid input (problems[]) · 409 not_found, empty_name, bad_modules, bad_trigger · 429 slow down
ai.update_brain
Change a brain — Rename it, choose what it learns from, how long a short memory lasts and how sure it must be to remember.
Needs ai:manage · changes data
https://app.getera.io/api/v1/brains/actions/update_brain- Canonical address:
POST /api/v1/actions/ai.update_brain
Input
| Field | Type | Required | Notes |
|---|---|---|---|
id | uuid | yes | Brain |
name | string | Name · max 80 | |
description | string | What it is for · max 500 | |
shortTtlHours | number | Short memory lasts (hours) · min 1 · max 720 | |
embeddingSpace | string (enum) | Where it understands meaning · Allowed values: bge-m3-1024, e5-small-384 | |
learnFrom | object / array | Learns from | |
rememberThreshold | number | How sure before remembering · min 0 · max 1 | |
askBeforeRemembering | boolean | Ask before remembering what it hears in chats |
Preconditions
The action is refused with 409 and one of these codes:
| Code | Refused when |
|---|---|
brain_not_found | The brain must exist in this workspace. |
not_your_brain | Someone else’s personal brain is theirs to change. |
archived | An archived brain does not change. |
empty_name | A brain needs a name. |
name_taken | Brain names are unique in a workspace. |
space_locked | Where a brain understands meaning is fixed once it knows something. |
invalid_learn_from | What it learns from is a set of known on/off switches. |
Events it publishes: ai.brain_updated
What it writes: brain (update) — Saves the brain’s settings
curl -X POST https://app.getera.io/api/v1/brains/actions/update_brain \
-H "Authorization: Bearer $ERA_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{"id":"ID_ID"}'{
"ok": true,
"result": "…",
"events": [
"ai.brain_updated"
]
}import { createEra } from "@getera/sdk"
const era = createEra({ apiKey: process.env.ERA_API_KEY })
const res = await era.brains.updateBrain({
id: "ID_ID"
})era brains update_brain \
--id "ID_ID"{
"name": "era__ai__update_brain",
"arguments": {
"id": "ID_ID"
}
}Errors: 401 no or expired credential · 403 the credential does not hold ai:manage · 404 the record or module is outside what it may reach · 422 invalid input (problems[]) · 409 brain_not_found, not_your_brain, archived, empty_name, name_taken, space_locked, invalid_learn_from · 429 slow down
ai.update_knowledge_base
Change a knowledge space — Rename a space, describe what goes in it, or make it the brain’s main space.
Needs ai:manage · changes data
https://app.getera.io/api/v1/knowledge_bases/actions/update_knowledge_base- Canonical address:
POST /api/v1/actions/ai.update_knowledge_base
Input
| Field | Type | Required | Notes |
|---|---|---|---|
id | uuid | yes | Space |
name | string | Name · max 80 | |
description | string | What goes here · max 500 | |
makeDefault | boolean | Make it the main space |
Preconditions
The action is refused with 409 and one of these codes:
| Code | Refused when |
|---|---|
knowledge_base_not_found | The space must exist in this workspace. |
archived | An archived space does not change. |
empty_name | A space needs a name. |
name_taken | Space names are unique in a brain. |
Events it publishes: ai.knowledge_base_updated
What it writes: knowledge_base (update) — Saves the space
curl -X POST https://app.getera.io/api/v1/knowledge_bases/actions/update_knowledge_base \
-H "Authorization: Bearer $ERA_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{"id":"ID_ID"}'{
"ok": true,
"result": "…",
"events": [
"ai.knowledge_base_updated"
]
}import { createEra } from "@getera/sdk"
const era = createEra({ apiKey: process.env.ERA_API_KEY })
const res = await era.knowledgeBases.updateKnowledgeBase({
id: "ID_ID"
})era knowledge_bases update_knowledge_base \
--id "ID_ID"{
"name": "era__ai__update_knowledge_base",
"arguments": {
"id": "ID_ID"
}
}Errors: 401 no or expired credential · 403 the credential does not hold ai:manage · 404 the record or module is outside what it may reach · 422 invalid input (problems[]) · 409 knowledge_base_not_found, archived, empty_name, name_taken · 429 slow down
ai.update_task
Change a task — Title, details, list, priority, due date, repeat rule or status.
Needs ai:write · changes data
https://app.getera.io/api/v1/ai_tasks/{id}/actions/update_task- Canonical address:
POST /api/v1/actions/ai.update_task
Input
| Field | Type | Required | Notes |
|---|---|---|---|
id | uuid | yes | Filled from the path {id} · Task · id of ai_task |
title | string | Title · max 300 | |
description | string | Details · max 10000 | |
listName | string | List · max 80 | |
priority | string (enum) | Priority · Allowed values: low, normal, high, urgent | |
dueAt | date-time | Due | |
recurrence | string (enum) | Repeats · Allowed values: none, daily, weekly, monthly | |
status | string (enum) | Status · Allowed values: open, in_progress, cancelled |
Preconditions
The action is refused with 409 and one of these codes:
| Code | Refused when |
|---|---|
not_found | The task must exist in this workspace. |
empty_title | A task needs a title. |
Events it publishes: ai.task_updated, ai.task_cancelled
What it writes: ai_task (update) — Rewrites the task
curl -X POST https://app.getera.io/api/v1/ai_tasks/AI_TASK_ID/actions/update_task \
-H "Authorization: Bearer $ERA_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{"title":"Title"}'{
"ok": true,
"result": "…",
"events": [
"ai.task_updated",
"ai.task_cancelled"
]
}import { createEra } from "@getera/sdk"
const era = createEra({ apiKey: process.env.ERA_API_KEY })
const res = await era.aiTasks.updateTask("AI_TASK_ID", {
title: "Title"
})era ai_tasks update_task AI_TASK_ID \
--title "Title"{
"name": "era__ai__update_task",
"arguments": {
"id": "AI_TASK_ID",
"title": "Title"
}
}Errors: 401 no or expired credential · 403 the credential does not hold ai:write · 404 the record or module is outside what it may reach · 422 invalid input (problems[]) · 409 not_found, empty_title · 429 slow down
ai.use_action_cap
Use Era’s daily allowance — Before Era acts without asking: takes one from today’s allowance for that kind, or gives one back when the action was refused.
Needs ai:read · changes data
https://app.getera.io/api/v1/era_action_caps/actions/use_action_cap- Canonical address:
POST /api/v1/actions/ai.use_action_cap
Input
| Field | Type | Required | Notes |
|---|---|---|---|
kind | string | yes | What · max 80 |
op | string (enum) | Use or give back · Allowed values: use, give_back |
What it writes: era_action_cap (update) — Counts today’s use of the allowance
curl -X POST https://app.getera.io/api/v1/era_action_caps/actions/use_action_cap \
-H "Authorization: Bearer $ERA_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{"kind":"What"}'{
"ok": true,
"result": "…",
"events": []
}import { createEra } from "@getera/sdk"
const era = createEra({ apiKey: process.env.ERA_API_KEY })
const res = await era.eraActionCaps.useActionCap({
kind: "What"
})era era_action_caps use_action_cap \
--kind "What"{
"name": "era__ai__use_action_cap",
"arguments": {
"kind": "What"
}
}Errors: 401 no or expired credential · 403 the credential does not hold ai:read · 404 the record or module is outside what it may reach · 422 invalid input (problems[]) · 429 slow down
Data models
AiAgent
Table ai_agent · Resource ai_agents
GET /api/v1/ai_agentsGET /api/v1/ai_agents/{id}
| Column | Type | Nullable | Allowed values | References |
|---|---|---|---|---|
id | string (uuid) · uuid | |||
organization_id | string (uuid) · uuid | organization | ||
workspace_id | string (uuid) · uuid | workspace | ||
name | string · text | |||
description | string · text | yes | ||
instructions | string · text | |||
model | string · text | |||
allowed_modules | string[] · text[] | |||
wakes_on | string[] · text[] | |||
max_steps | integer · int4 | |||
is_enabled | boolean · bool | |||
acts_as_user_id | string (uuid) · uuid | app_user | ||
engine_agent_id | string · text | yes | ||
last_run_at | string (date-time) · timestamptz | yes | ||
run_count | integer · int4 | |||
failure_count | integer · int4 | |||
created_at | string (date-time) · timestamptz | |||
updated_at | string (date-time) · timestamptz |
Primary key: id
Checks:
CHECK ((length(btrim(name)) > 0))CHECK (((max_steps >= 1) AND (max_steps <= 40)))CHECK (os.valid_event_patterns(wakes_on))
AiBudget
Table ai_budget · Resource ai_budgets
GET /api/v1/ai_budgetsGET /api/v1/ai_budgets/{id}
| Column | Type | Nullable | Allowed values | References |
|---|---|---|---|---|
id | string (uuid) · uuid | |||
organization_id | string (uuid) · uuid | organization | ||
workspace_id | string (uuid) · uuid | workspace | ||
agent_id | string (uuid) · uuid | yes | ai_agent | |
daily_usd | string (decimal) · numeric | yes | ||
monthly_usd | string (decimal) · numeric | yes | ||
alert_pct | integer · int4 | |||
last_alert_key | string · text | yes | ||
updated_at | string (date-time) · timestamptz |
Primary key: id
Checks:
CHECK (((alert_pct >= 1) AND (alert_pct <= 100)))CHECK ((((daily_usd IS NULL) OR (daily_usd >= (0)::numeric)) AND ((monthly_usd IS NULL) OR (monthly_usd >= (0)::numeric))))
AiConversation
Table ai_conversation · Resource ai_conversations
GET /api/v1/ai_conversationsGET /api/v1/ai_conversations/{id}
| Column | Type | Nullable | Allowed values | References |
|---|---|---|---|---|
id | string (uuid) · uuid | |||
organization_id | string (uuid) · uuid | organization | ||
workspace_id | string (uuid) · uuid | workspace | ||
agent_id | string (uuid) · uuid | yes | ai_agent | |
created_by | string (uuid) · uuid | app_user | ||
title | string · text | yes | ||
message_count | integer · int4 | |||
last_message_at | string (date-time) · timestamptz | yes | ||
created_at | string (date-time) · timestamptz | |||
updated_at | string (date-time) · timestamptz | |||
deleted_at | string (date-time) · timestamptz | yes |
Primary key: id
AiMessage
Table ai_message · Resource ai_messages
GET /api/v1/ai_messagesGET /api/v1/ai_messages/{id}
| Column | Type | Nullable | Allowed values | References |
|---|---|---|---|---|
id | string (uuid) · uuid | |||
organization_id | string (uuid) · uuid | organization | ||
workspace_id | string (uuid) · uuid | workspace | ||
conversation_id | string (uuid) · uuid | ai_conversation | ||
position | integer · int4 | |||
role | string · text | user, assistant, system | ||
content | string · text | |||
tool_calls | object · jsonb | |||
created_at | string (date-time) · timestamptz |
Primary key: id
Unique: conversation_id, position
Checks:
CHECK (("position" >= 0))
AiModelPolicy
Table ai_model_policy · Resource ai_model_policies
GET /api/v1/ai_model_policiesGET /api/v1/ai_model_policies/{id}
| Column | Type | Nullable | Allowed values | References |
|---|---|---|---|---|
id | string (uuid) · uuid | |||
organization_id | string (uuid) · uuid | organization | ||
workspace_id | string (uuid) · uuid | workspace | ||
task_class | string · text | default, chat, agent, classify, summarize, extract, build, research | ||
model | string · text | |||
fallback_model | string · text | yes | ||
updated_at | string (date-time) · timestamptz |
Primary key: id
Unique: workspace_id, task_class
Checks:
CHECK ((length(btrim(model)) > 0))
AiProvider
Table ai_provider · Resource ai_providers
GET /api/v1/ai_providersGET /api/v1/ai_providers/{id}
| Column | Type | Nullable | Allowed values | References |
|---|---|---|---|---|
id | string (uuid) · uuid | |||
organization_id | string (uuid) · uuid | organization | ||
workspace_id | string (uuid) · uuid | workspace | ||
provider | string · text | |||
label | string · text | yes | ||
key_hint | string · text | yes | ||
base_url | string · text | yes | ||
is_default | boolean · bool | |||
status | string · text | unchecked, healthy, failing, connecting, limited, relogin, offline, not_eligible | ||
last_checked_at | string (date-time) · timestamptz | yes | ||
last_error | string · text | yes | ||
created_by | string (uuid) · uuid | yes | app_user | |
created_at | string (date-time) · timestamptz | |||
updated_at | string (date-time) · timestamptz | |||
key_set_at | string (date-time) · timestamptz | yes | ||
consecutive_failures | integer · int4 | |||
last_latency_ms | integer · int4 | yes | ||
rotation_reminded_at | string (date-time) · timestamptz | yes | ||
connection_kind | string · text | api_key, subscription | ||
owner_user_id | string (uuid) · uuid | yes | app_user | |
execution | string · text | remote, local_device, cloud_computer | ||
device_id | string · text | yes | ||
capabilities | string[] · text[] | |||
account_label | string · text | yes | ||
limit_resets_at | string (date-time) · timestamptz | yes | ||
use_for | object · jsonb | |||
last_used_at | string (date-time) · timestamptz | yes | ||
meta | object · jsonb | |||
share_scope | string · text | |||
share_team_id | string (uuid) · uuid | yes | team | |
plan_limits | object · jsonb | yes |
Primary key: id
Checks:
CHECK ((provider = ANY ('{amp_cli,anthropic,auggie_cli,azure_openai,bfl,chatgpt,claude_code,cline_cli,copilot_cli,cursor_cli,deepseek,elevenlabs,fal,gemini_cli,google,grok_cli,groq,ideogram,kimi_cli,kiro_cli,kling,luma,mistral,moonshot,ollama,openai,openai_compatible,opencode_cli,openrouter,replicate,runway,stability,typesafe,vibe_cli,xai,zai,deepgram,assemblyai}'::text[])))CHECK (((plan_limits IS NULL) OR ((jsonb_typeof(plan_limits) = 'object'::text) AND (plan_limits ? 'state'::text))))CHECK (((share_scope = ANY (ARRAY['me'::text, 'team'::text, 'workspace'::text])) AND ((share_scope <> 'team'::text) OR (share_team_id IS NOT NULL))))CHECK ((jsonb_typeof(use_for) = 'object'::text))
AiRun
Table ai_run · Resource ai_runs
GET /api/v1/ai_runsGET /api/v1/ai_runs/{id}
| Column | Type | Nullable | Allowed values | References |
|---|---|---|---|---|
id | string (uuid) · uuid | |||
organization_id | string (uuid) · uuid | organization | ||
workspace_id | string (uuid) · uuid | workspace | ||
agent_id | string (uuid) · uuid | ai_agent | ||
event_id | string (int64) · int8 | yes | ||
event_name | string · text | yes | ||
conversation_id | string (uuid) · uuid | yes | ai_conversation | |
status | string · text | running, succeeded, failed, skipped, refused | ||
started_at | string (date-time) · timestamptz | |||
finished_at | string (date-time) · timestamptz | yes | ||
steps | object · jsonb | |||
error | string · text | yes | ||
model | string · text | yes | ||
model_calls | integer · int4 | |||
cost_usd | string (decimal) · numeric | |||
repairs | integer · int4 | |||
answer | string · text | yes | ||
touched_records | object · jsonb | |||
approval_ids | string[] · uuid[] |
Primary key: id
AiSkillRelease
Table ai_skill_release · Resource ai_skill_releases
GET /api/v1/ai_skill_releasesGET /api/v1/ai_skill_releases/{id}
| Column | Type | Nullable | Allowed values | References |
|---|---|---|---|---|
id | string (uuid) · uuid | |||
organization_id | string (uuid) · uuid | organization | ||
workspace_id | string (uuid) · uuid | workspace | ||
skill_id | string · text | |||
paused | boolean · bool | |||
source_template | string · text | yes | ||
source_version | string · text | yes | ||
installed_at | string (date-time) · timestamptz | yes | ||
updated_at | string (date-time) · timestamptz | |||
published | boolean · bool | |||
allowed_integrations | string[] · text[] | |||
allowed_domains | string[] · text[] |
Primary key: id
Unique: workspace_id, skill_id
AiSkillRun
Table ai_skill_run · Resource ai_skill_runs
GET /api/v1/ai_skill_runsGET /api/v1/ai_skill_runs/{id}
| Column | Type | Nullable | Allowed values | References |
|---|---|---|---|---|
id | string (uuid) · uuid | |||
organization_id | string (uuid) · uuid | organization | ||
workspace_id | string (uuid) · uuid | workspace | ||
skill_id | string · text | |||
skill_name | string · text | yes | ||
version_id | string (uuid) · uuid | yes | ai_skill_version | |
mode | string · text | load, exec, eval, compiled | ||
status | string · text | ok, error | ||
duration_ms | integer · int4 | yes | ||
cost_usd | string (decimal) · numeric | |||
error | string · text | yes | ||
created_at | string (date-time) · timestamptz |
Primary key: id
AiSkillVersion
Table ai_skill_version · Resource ai_skill_versions
GET /api/v1/ai_skill_versionsGET /api/v1/ai_skill_versions/{id}
| Column | Type | Nullable | Allowed values | References |
|---|---|---|---|---|
id | string (uuid) · uuid | |||
organization_id | string (uuid) · uuid | organization | ||
workspace_id | string (uuid) · uuid | workspace | ||
skill_id | string · text | |||
version | integer · int4 | |||
definition | object · jsonb | |||
note | string · text | yes | ||
status | string · text | draft, active, retired | ||
eval_score | string (decimal) · numeric | yes | ||
eval_passed | integer · int4 | yes | ||
eval_total | integer · int4 | yes | ||
eval_notes | string · text | yes | ||
evaluated_at | string (date-time) · timestamptz | yes | ||
was_active | boolean · bool | |||
created_by | string (uuid) · uuid | yes | app_user | |
created_at | string (date-time) · timestamptz |
Primary key: id
Unique: workspace_id, skill_id, version
AiSourceChoice
Table ai_source_choice · Resource ai_source_choices
GET /api/v1/ai_source_choicesGET /api/v1/ai_source_choices/{id}
| Column | Type | Nullable | Allowed values | References |
|---|---|---|---|---|
id | string (uuid) · uuid | |||
organization_id | string (uuid) · uuid | organization | ||
workspace_id | string (uuid) · uuid | workspace | ||
subject_type | string · text | chat, agent, workflow, brain, voice_agent, creative, computer | ||
subject_id | string · text | |||
connection_id | string (uuid) · uuid | yes | ai_provider | |
model | string · text | yes | ||
allow_shared | boolean · bool | |||
allow_byok | boolean · bool | |||
when_offline | string · text | wait, fallback | ||
created_by | string (uuid) · uuid | yes | app_user | |
created_at | string (date-time) · timestamptz | |||
updated_at | string (date-time) · timestamptz | |||
source_mode | string · text | auto, byok, byos, connection |
Primary key: id
Unique: workspace_id, subject_type, subject_id
AiTask
Table ai_task · Resource ai_tasks
GET /api/v1/ai_tasksGET /api/v1/ai_tasks/{id}
| Column | Type | Nullable | Allowed values | References |
|---|---|---|---|---|
id | string (uuid) · uuid | |||
organization_id | string (uuid) · uuid | organization | ||
workspace_id | string (uuid) · uuid | workspace | ||
title | string · text | |||
description | string · text | yes | ||
list_name | string · text | |||
status | string · text | open, in_progress, done, cancelled | ||
priority | string · text | low, normal, high, urgent | ||
due_at | string (date-time) · timestamptz | yes | ||
assignee_user_id | string (uuid) · uuid | yes | app_user | |
assignee_agent_id | string (uuid) · uuid | yes | ai_agent | |
recurrence | string · text | none, daily, weekly, monthly | ||
recurrence_of | string (uuid) · uuid | yes | ai_task | |
handoffs | object · jsonb | |||
created_by | string (uuid) · uuid | app_user | ||
completed_at | string (date-time) · timestamptz | yes | ||
created_at | string (date-time) · timestamptz | |||
updated_at | string (date-time) · timestamptz | |||
deleted_at | string (date-time) · timestamptz | yes | ||
record_type | string · text | yes | ||
record_id | string (uuid) · uuid | yes | ||
due_reminded_at | string (date-time) · timestamptz | yes | ||
overdue_reminded_at | string (date-time) · timestamptz | yes |
Primary key: id
Checks:
CHECK (((assignee_user_id IS NULL) OR (assignee_agent_id IS NULL)))CHECK ((((record_type IS NULL) AND (record_id IS NULL)) OR ((record_type = ANY (ARRAY['customer'::text, 'lead'::text, 'appointment'::text, 'order'::text, 'conversation'::text])) AND (record_id IS NOT NULL))))CHECK ((length(btrim(title)) > 0))
AiTemplateInstall
Table ai_template_install · Resource ai_template_installs
GET /api/v1/ai_template_installsGET /api/v1/ai_template_installs/{id}
| Column | Type | Nullable | Allowed values | References |
|---|---|---|---|---|
id | string (uuid) · uuid | |||
organization_id | string (uuid) · uuid | organization | ||
workspace_id | string (uuid) · uuid | workspace | ||
template_id | string · text | |||
template_name | string · text | |||
kind | string · text | agent, skill, workflow | ||
instance_id | string · text | |||
required_apps | string[] · text[] | |||
installed_by | string (uuid) · uuid | yes | app_user | |
created_at | string (date-time) · timestamptz |
Primary key: id
Unique: workspace_id, kind, instance_id
AiUsage
Table ai_usage · Resource ai_usages
GET /api/v1/ai_usagesGET /api/v1/ai_usages/{id}
| Column | Type | Nullable | Allowed values | References |
|---|---|---|---|---|
id | string (uuid) · uuid | |||
organization_id | string (uuid) · uuid | organization | ||
workspace_id | string (uuid) · uuid | workspace | ||
agent_id | string (uuid) · uuid | yes | ai_agent | |
run_id | string (uuid) · uuid | yes | ai_run | |
conversation_id | string (uuid) · uuid | yes | ai_conversation | |
source | string · text | agent_run, console, era, skill_eval, router | ||
ref | string · text | yes | ||
model | string · text | yes | ||
model_calls | integer · int4 | |||
tool_calls | integer · int4 | |||
tool_result_chars | integer · int4 | |||
cost_usd | string (decimal) · numeric | |||
created_at | string (date-time) · timestamptz | |||
surface | string · text | yes | ||
capability | string · text | yes | ||
source_kind | string · text | yes | ||
provider | string · text | yes | ||
units | string (decimal) · numeric | yes | ||
unit | string · text | yes | ||
user_id | string (uuid) · uuid | yes | ||
connection_id | string (uuid) · uuid | yes | ai_provider | |
latency_ms | integer · int4 | yes | ||
attempts | object · jsonb | yes | ||
gateway_request_id | string · text | yes |
Primary key: id
Checks:
CHECK (((source_kind IS NULL) OR (source_kind = ANY (ARRAY['native'::text, 'byos'::text, 'byok'::text])))) NOT VALID
BrainBinding
Table brain_binding · Resource brain_bindings
GET /api/v1/brain_bindingsGET /api/v1/brain_bindings/{id}
| Column | Type | Nullable | Allowed values | References |
|---|---|---|---|---|
id | string (uuid) · uuid | |||
organization_id | string (uuid) · uuid | organization | ||
workspace_id | string (uuid) · uuid | workspace | ||
subject_type | string · text | agent, workflow, voice_agent, era_chat, meeting, team, role | ||
subject_id | string · text | |||
brain_id | string (uuid) · uuid | brain | ||
knowledge_base_ids | string[] · uuid[] | |||
access | string · text | read, read_write | ||
created_by | string (uuid) · uuid | yes | app_user | |
created_at | string (date-time) · timestamptz | |||
updated_at | string (date-time) · timestamptz |
Primary key: id
Checks:
CHECK (((length(subject_id) >= 1) AND (length(subject_id) <= 120)))
BrainErasure
Table brain_erasure · Resource brain_erasures
GET /api/v1/brain_erasuresGET /api/v1/brain_erasures/{id}
| Column | Type | Nullable | Allowed values | References |
|---|---|---|---|---|
id | string (uuid) · uuid | |||
organization_id | string (uuid) · uuid | organization | ||
workspace_id | string (uuid) · uuid | workspace | ||
kind | string · text | fact, person | ||
subject_label | string · text | |||
subject_ref | string · text | yes | ||
privacy_request_id | string (uuid) · uuid | yes | ||
reason | string · text | yes | ||
requested_on | string (date) · date | yes | ||
counts | object · jsonb | |||
erased_by | string (uuid) · uuid | yes | app_user | |
created_at | string (date-time) · timestamptz |
Primary key: id
Checks:
CHECK ((jsonb_typeof(counts) = 'object'::text))CHECK (((reason IS NULL) OR (length(reason) <= 500)))CHECK (((length(subject_label) >= 1) AND (length(subject_label) <= 200)))CHECK (((subject_ref IS NULL) OR (length(subject_ref) <= 200)))
BrainFactReview
Table brain_fact_review · Resource brain_fact_reviews
GET /api/v1/brain_fact_reviewsGET /api/v1/brain_fact_reviews/{id}
| Column | Type | Nullable | Allowed values | References |
|---|---|---|---|---|
id | string (uuid) · uuid | |||
organization_id | string (uuid) · uuid | organization | ||
workspace_id | string (uuid) · uuid | workspace | ||
memory_id | string (uuid) · uuid | |||
decision | string · text | correct, forget, keep_private, confirm, move, refile | ||
corrected_text | string · text | yes | ||
applied_memory_id | string (uuid) · uuid | yes | ||
reviewed_by | string (uuid) · uuid | yes | app_user | |
created_at | string (date-time) · timestamptz | |||
target_knowledge_base_id | string (uuid) · uuid | yes | knowledge_base | |
new_kind | string · text | yes | ||
new_audience | string · text | yes | ||
new_module_code | string · text | yes | ||
new_expires_at | string (date-time) · timestamptz | yes | ||
clear_expiry | boolean · bool |
Primary key: id
Checks:
CHECK (((decision = 'correct'::text) = (corrected_text IS NOT NULL)))CHECK (((corrected_text IS NULL) OR ((length(corrected_text) >= 3) AND (length(corrected_text) <= 4000))))CHECK (((decision = 'move'::text) = (target_knowledge_base_id IS NOT NULL)))CHECK (((new_audience IS NULL) OR (new_audience = ANY (ARRAY['person'::text, 'workspace'::text, 'module'::text]))))CHECK (((new_kind IS NULL) OR (new_kind = ANY (ARRAY['fact'::text, 'preference'::text, 'rule'::text, 'procedure'::text, 'decision'::text, 'commitment'::text, 'episode'::text]))))CHECK (((decision <> 'refile'::text) OR (new_kind IS NOT NULL) OR (new_audience IS NOT NULL) OR (new_expires_at IS NOT NULL) OR clear_expiry))
BrainInsight
Table brain_insight · Resource brain_insights
GET /api/v1/brain_insightsGET /api/v1/brain_insights/{id}
| Column | Type | Nullable | Allowed values | References |
|---|---|---|---|---|
id | string (uuid) · uuid | |||
organization_id | string (uuid) · uuid | organization | ||
workspace_id | string (uuid) · uuid | workspace | ||
brain_id | string (uuid) · uuid | yes | brain | |
role | string · text | sales, marketing, finance, operations, support, management, general | ||
title | string · text | |||
body | string · text | |||
severity | string · text | info, opportunity, warning | ||
sources | object · jsonb | |||
reasoning | string · text | yes | ||
suggested_action | object · jsonb | yes | ||
generated_by | object · jsonb | |||
status | string · text | new, seen, done, dismissed | ||
dedupe_key | string · text | yes | ||
status_by | string (uuid) · uuid | yes | app_user | |
created_at | string (date-time) · timestamptz | |||
updated_at | string (date-time) · timestamptz | |||
origin | string · text | learning, outcome, era, person | ||
kind | string · text | yes |
Primary key: id
Checks:
CHECK ((length(body) <= 4000))CHECK (((dedupe_key IS NULL) OR (length(dedupe_key) <= 200)))CHECK ((jsonb_typeof(generated_by) = 'object'::text))CHECK (((kind IS NULL) OR (length(kind) <= 64)))CHECK (((reasoning IS NULL) OR (length(reasoning) <= 2000)))CHECK ((jsonb_typeof(sources) = 'array'::text))CHECK (((suggested_action IS NULL) OR (jsonb_typeof(suggested_action) = 'object'::text)))CHECK (((length(btrim(title)) >= 1) AND (length(btrim(title)) <= 200)))
Brain
Table brain · Resource brains
GET /api/v1/brainsGET /api/v1/brains/{id}POST /api/v1/brains→ai.create_brain
| Column | Type | Nullable | Allowed values | References |
|---|---|---|---|---|
id | string (uuid) · uuid | |||
organization_id | string (uuid) · uuid | organization | ||
workspace_id | string (uuid) · uuid | workspace | ||
name | string · text | |||
description | string · text | yes | ||
kind | string · text | company, personal, team, era, voice, brand, custom | ||
scope | string · text | workspace, team, era, voice_agent, person | ||
scope_ref | string (uuid) · uuid | yes | ||
memory | string · text | long, short | ||
short_ttl_hours | integer · int4 | yes | ||
embedding_space | string · text | bge-m3-1024, e5-small-384 | ||
learn_from | object · jsonb | |||
remember_threshold | number · float4 | |||
is_default | boolean · bool | |||
archived_at | string (date-time) · timestamptz | yes | ||
created_by | string (uuid) · uuid | yes | app_user | |
created_at | string (date-time) · timestamptz | |||
updated_at | string (date-time) · timestamptz | |||
ask_before_remembering | boolean · bool |
Primary key: id
Checks:
CHECK (((scope = 'workspace'::text) = (scope_ref IS NULL)))CHECK (((memory = 'long'::text) OR (short_ttl_hours IS NOT NULL)))CHECK (((description IS NULL) OR (length(description) <= 500)))CHECK ((jsonb_typeof(learn_from) = 'object'::text))CHECK (((length(btrim(name)) >= 1) AND (length(btrim(name)) <= 80)))CHECK (((remember_threshold >= (0)::double precision) AND (remember_threshold <= (1)::double precision)))CHECK (((short_ttl_hours IS NULL) OR ((short_ttl_hours >= 1) AND (short_ttl_hours <= 720))))
ComputerFolder
Table computer_folder · Resource computer_folders
GET /api/v1/computer_foldersGET /api/v1/computer_folders/{id}
| Column | Type | Nullable | Allowed values | References |
|---|---|---|---|---|
id | string (uuid) · uuid | |||
organization_id | string (uuid) · uuid | organization | ||
workspace_id | string (uuid) · uuid | workspace | ||
owner_user_id | string (uuid) · uuid | app_user | ||
name | string · text | |||
aliases | string[] · text[] | |||
path | string · text | |||
visibility | string · text | private, everyone | ||
last_used_at | string (date-time) · timestamptz | yes | ||
created_at | string (date-time) · timestamptz | |||
updated_at | string (date-time) · timestamptz |
Primary key: id
Checks:
CHECK (((length(name) >= 1) AND (length(name) <= 80)))CHECK (((length(path) >= 1) AND (length(path) <= 1000)))
ComputerMachine
Table computer_machine · Resource computer_machines
GET /api/v1/computer_machinesGET /api/v1/computer_machines/{id}
| Column | Type | Nullable | Allowed values | References |
|---|---|---|---|---|
id | string (uuid) · uuid | |||
organization_id | string (uuid) · uuid | organization | ||
workspace_id | string (uuid) · uuid | workspace | ||
owner_user_id | string (uuid) · uuid | app_user | ||
name | string · text | |||
provider | string · text | |||
external_id | string · text | yes | ||
state | string · text | requested, provisioning, running, pausing, paused, failed, deleting, deleted | ||
resolution_w | integer · int4 | |||
resolution_h | integer · int4 | |||
viewer_url | string · text | yes | ||
last_error | string · text | yes | ||
seconds_used | string (int64) · int8 | |||
month_seconds_used | string (int64) · int8 | |||
usage_month | string · text | yes | ||
started_at | string (date-time) · timestamptz | yes | ||
paused_at | string (date-time) · timestamptz | yes | ||
deleted_at | string (date-time) · timestamptz | yes | ||
metadata | object · jsonb | |||
created_at | string (date-time) · timestamptz | |||
updated_at | string (date-time) · timestamptz |
Primary key: id
ComputerPolicy
Table computer_policy · Resource computer_policies
GET /api/v1/computer_policiesGET /api/v1/computer_policies/{id}
| Column | Type | Nullable | Allowed values | References |
|---|---|---|---|---|
workspace_id | string (uuid) · uuid | workspace | ||
organization_id | string (uuid) · uuid | organization | ||
allow_domains | string[] · text[] | |||
deny_domains | string[] · text[] | |||
deny_apps | string[] · text[] | |||
approval_mode | string · text | risky, every_action, never | ||
max_steps | integer · int4 | |||
max_minutes | integer · int4 | |||
monthly_cloud_hours | string (decimal) · numeric | |||
default_model | string · text | yes | ||
updated_by | string (uuid) · uuid | yes | app_user | |
created_at | string (date-time) · timestamptz | |||
updated_at | string (date-time) · timestamptz | |||
provider | string · text | yes |
Primary key: workspace_id
Checks:
CHECK (((max_minutes >= 1) AND (max_minutes <= 1440)))CHECK (((max_steps >= 1) AND (max_steps <= 200)))CHECK ((monthly_cloud_hours >= (0)::numeric))CHECK (((provider IS NULL) OR (provider = ANY (ARRAY['boxd'::text, 'e2b'::text, 'digitalocean'::text]))))
DecideDecision
Table decide_decision · Resource decide_decisions
GET /api/v1/decide_decisionsGET /api/v1/decide_decisions/{id}
| Column | Type | Nullable | Allowed values | References |
|---|---|---|---|---|
id | string (uuid) · uuid | |||
organization_id | string (uuid) · uuid | organization | ||
workspace_id | string (uuid) · uuid | workspace | ||
question_key | string · text | |||
question | object · jsonb | |||
focus | object · jsonb | yes | ||
answer | object · jsonb | |||
confidence | number · float4 | yes | ||
provider | string · text | yes | ||
model | string · text | yes | ||
needs_review | boolean · bool | |||
ref | string · text | yes | ||
outcome | string · text | yes | ||
corrected_answer | object · jsonb | yes | ||
outcome_source | string · text | yes | ||
outcome_note | string · text | yes | ||
outcome_by | string (uuid) · uuid | yes | app_user | |
outcome_at | string (date-time) · timestamptz | yes | ||
created_at | string (date-time) · timestamptz |
Primary key: id
Checks:
CHECK ((jsonb_typeof(answer) = 'object'::text))CHECK (((outcome = 'corrected'::text) = (corrected_answer IS NOT NULL)))CHECK (((corrected_answer IS NULL) OR (jsonb_typeof(corrected_answer) = 'object'::text)))CHECK (((outcome IS NULL) OR (outcome = ANY (ARRAY['confirmed'::text, 'corrected'::text]))))CHECK (((outcome_note IS NULL) OR (length(outcome_note) <= 500)))CHECK (((outcome_source IS NULL) OR (outcome_source = ANY (ARRAY['fact_review'::text, 'person'::text, 'workflow'::text, 'era'::text]))))CHECK ((jsonb_typeof(question) = 'object'::text))CHECK (((length(question_key) >= 1) AND (length(question_key) <= 160)))CHECK (((ref IS NULL) OR (length(ref) <= 200)))
EraActionCap
Table era_action_cap · Resource era_action_caps
GET /api/v1/era_action_capsGET /api/v1/era_action_caps/{id}
| Column | Type | Nullable | Allowed values | References |
|---|---|---|---|---|
id | string (uuid) · uuid | |||
organization_id | string (uuid) · uuid | organization | ||
workspace_id | string (uuid) · uuid | workspace | ||
user_id | string (uuid) · uuid | app_user | ||
kind | string · text | |||
daily_limit | integer · int4 | |||
used | integer · int4 | |||
used_on | string (date) · date | yes | ||
created_at | string (date-time) · timestamptz | |||
updated_at | string (date-time) · timestamptz |
Primary key: id
Unique: workspace_id, user_id, kind
Checks:
CHECK (((daily_limit >= 1) AND (daily_limit <= 1000)))CHECK (((kind ~ '^[a-z][a-z0-9_]*\.[a-z][a-z0-9_]*$'::text) AND (length(kind) <= 80)))CHECK ((used >= 0))
EraChatMember
Table era_chat_member · Resource era_chat_members
GET /api/v1/era_chat_membersGET /api/v1/era_chat_members/{id}
| Column | Type | Nullable | Allowed values | References |
|---|---|---|---|---|
id | string (uuid) · uuid | |||
organization_id | string (uuid) · uuid | organization | ||
workspace_id | string (uuid) · uuid | workspace | ||
conversation_id | string (uuid) · uuid | conversations | ||
user_id | string (uuid) · uuid | app_user | ||
access | string · text | view, act | ||
can_approve | boolean · bool | |||
added_by | string (uuid) · uuid | yes | app_user | |
last_seen_at | string (date-time) · timestamptz | yes | ||
created_at | string (date-time) · timestamptz | |||
updated_at | string (date-time) · timestamptz |
Primary key: id
Unique: conversation_id, user_id
Checks:
CHECK (((NOT can_approve) OR (access = 'act'::text)))
EraChatSeen
Table era_chat_seen · Resource era_chat_seens
GET /api/v1/era_chat_seensGET /api/v1/era_chat_seens/{id}
| Column | Type | Nullable | Allowed values | References |
|---|---|---|---|---|
id | string (uuid) · uuid | |||
organization_id | string (uuid) · uuid | organization | ||
workspace_id | string (uuid) · uuid | workspace | ||
conversation_id | string (uuid) · uuid | conversations | ||
user_id | string (uuid) · uuid | app_user | ||
seen_at | string (date-time) · timestamptz |
Primary key: id
Unique: conversation_id, user_id
EraChatShare
Table era_chat_share · Resource era_chat_shares
GET /api/v1/era_chat_sharesGET /api/v1/era_chat_shares/{id}
| Column | Type | Nullable | Allowed values | References |
|---|---|---|---|---|
id | string (uuid) · uuid | |||
organization_id | string (uuid) · uuid | organization | ||
workspace_id | string (uuid) · uuid | workspace | ||
conversation_id | string (uuid) · uuid | conversations | ||
created_by | string (uuid) · uuid | app_user | ||
visibility | string · text | private, workspace | ||
link_expires_at | string (date-time) · timestamptz | yes | ||
created_at | string (date-time) · timestamptz | |||
updated_at | string (date-time) · timestamptz |
Primary key: id
Unique: conversation_id · link_token_hash
EraLearning
Table era_learning · Resource era_learnings
GET /api/v1/era_learningsGET /api/v1/era_learnings/{id}
| Column | Type | Nullable | Allowed values | References |
|---|---|---|---|---|
id | string (uuid) · uuid | |||
organization_id | string (uuid) · uuid | organization | ||
workspace_id | string (uuid) · uuid | workspace | ||
kind | string · text | memory, skill | ||
status | string · text | proposed, approved, rejected | ||
proposed_by | string · text | era, learning, skills | ||
for_user | string (uuid) · uuid | yes | app_user | |
statement | string · text | yes | ||
memory_kind | string · text | yes | ||
audience | string · text | person, workspace, module | ||
module_code | string · text | yes | ||
expires_at | string (date-time) · timestamptz | yes | ||
brain_id | string (uuid) · uuid | yes | brain | |
knowledge_base_id | string (uuid) · uuid | yes | knowledge_base | |
confidence | number · float4 | yes | ||
skill_id | string · text | yes | ||
skill_name | string · text | yes | ||
skill_description | string · text | yes | ||
skill_content | string · text | yes | ||
reason | string · text | yes | ||
source | object · jsonb | |||
evidence_count | integer · int4 | |||
dedupe_key | string · text | yes | ||
decided_by | string (uuid) · uuid | yes | app_user | |
decided_at | string (date-time) · timestamptz | yes | ||
result_ref | string · text | yes | ||
created_at | string (date-time) · timestamptz | |||
updated_at | string (date-time) · timestamptz | |||
score | number · float4 | yes | ||
lowered_by | object · jsonb |
Primary key: id
Checks:
CHECK (((kind <> 'memory'::text) OR ((statement IS NOT NULL) AND (memory_kind IS NOT NULL))))CHECK (((kind <> 'skill'::text) OR ((skill_name IS NOT NULL) AND (skill_description IS NOT NULL) AND (skill_content IS NOT NULL))))CHECK (((audience = 'module'::text) = (module_code IS NOT NULL)))CHECK (((status = 'proposed'::text) = (decided_at IS NULL)))CHECK (((confidence IS NULL) OR ((confidence >= (0)::double precision) AND (confidence <= (1)::double precision))))CHECK ((evidence_count >= 1))CHECK ((jsonb_typeof(lowered_by) = 'array'::text))CHECK (((memory_kind IS NULL) OR (memory_kind = ANY (ARRAY['fact'::text, 'preference'::text, 'rule'::text, 'procedure'::text]))))CHECK (((reason IS NULL) OR (length(reason) <= 1000)))CHECK (((score IS NULL) OR ((score >= (0)::double precision) AND (score <= (1)::double precision))))CHECK (((skill_content IS NULL) OR (length(skill_content) <= 50000)))CHECK (((skill_description IS NULL) OR (length(skill_description) <= 1024)))CHECK (((skill_name IS NULL) OR (skill_name ~ '^[a-z0-9]+(-[a-z0-9]+)*$'::text)))CHECK ((jsonb_typeof(source) = 'object'::text))CHECK (((statement IS NULL) OR ((length(statement) >= 3) AND (length(statement) <= 4000))))
KnowledgeBase
Table knowledge_base · Resource knowledge_bases
GET /api/v1/knowledge_basesGET /api/v1/knowledge_bases/{id}POST /api/v1/knowledge_bases→ai.create_knowledge_base
| Column | Type | Nullable | Allowed values | References |
|---|---|---|---|---|
id | string (uuid) · uuid | |||
organization_id | string (uuid) · uuid | organization | ||
workspace_id | string (uuid) · uuid | workspace | ||
brain_id | string (uuid) · uuid | brain | ||
name | string · text | |||
kind | string · text | company, product, sales, marketing, customers, projects, personal, voice, industry, meetings, brand, finance, support, custom | ||
description | string · text | yes | ||
is_default | boolean · bool | |||
archived_at | string (date-time) · timestamptz | yes | ||
created_by | string (uuid) · uuid | yes | app_user | |
created_at | string (date-time) · timestamptz | |||
updated_at | string (date-time) · timestamptz |
Primary key: id
Checks:
CHECK (((description IS NULL) OR (length(description) <= 500)))CHECK (((length(btrim(name)) >= 1) AND (length(btrim(name)) <= 80)))
Events
Workflows and webhooks react to these events.
| Event | What happens | Payload |
|---|---|---|
ai.agent_created | An agent was created. | id, name |
ai.agent_deleted | An agent was removed. | id, name |
ai.agent_disabled | An agent stopped listening. | id, name |
ai.agent_enabled | An agent started listening. | id, name |
ai.agent_linked | An agent was linked to (or unlinked from) an assistant. | id, engineAgentId |
ai.agent_requested | Somebody or something asked an agent to run. | id, prompt |
ai.agent_updated | An agent’s brief, model or triggers changed. | id, name |
ai.approval_escalated | A request for approval has waited too long. | approvalId, intent, tool, ageHours |
ai.brain_archived | A brain was archived. | id, name |
ai.brain_bound | An Era, workflow or voice agent now uses a brain. | id, subjectType, subjectId, brainId, access |
ai.brain_created | A brain was created. | id, name, kind |
ai.brain_fact_erased | Something Era learned was permanently erased. | id, facts |
ai.brain_fact_reviewed | A person corrected, forgot, kept private or confirmed something Era learned. | id, memoryId, decision, appliedMemoryId |
ai.brain_insight_created | Era noticed something for a role. | id, role, title, severity |
ai.brain_insight_updated | An insight was seen, done or dismissed. | id, status |
ai.brain_person_erased | Everything Era learned about a person was permanently erased. | id, facts, entities |
ai.brain_unbound | An Era, workflow or voice agent stopped using a brain. | subjectType, subjectId, brainId |
ai.brain_updated | A brain’s name, memory or what it learns from changed. | id, name |
ai.budget_alert | AI spend crossed a budget alert threshold or its cap. Point a notification rule at it. | budgetId, scope, agentId, period, capUsd, spentUsd, level |
ai.budget_updated | An AI budget was set or removed. | id, agentId |
ai.chat_shared | A chat was shared with a person (or their access changed). | conversationId, title, access, canApprove, recipientUserId |
ai.chat_visibility_changed | A chat became private or visible to the workspace, or its link changed. | conversationId, visibility, link |
ai.code_session_closed | A live coding session was closed. | id |
ai.code_session_opened | A live coding session started in a folder on the person’s computer. | id, folderName, harness, conversationId |
ai.computer_approval_requested | A computer task is waiting for a person to approve a step. | id, summary, risk, recipientUserId |
ai.computer_machine_changed | A cloud computer changed state. | id, state, recipientUserId |
ai.computer_machine_requested | A person asked their cloud computer to be created, started, paused or deleted. | id, op |
ai.computer_policy_saved | The workspace computer rules changed. | approvalMode |
ai.computer_session_created | A computer session was prepared. | id, title, needsProvider |
ai.computer_session_finished | A computer task finished, failed or was stopped. | id, status, success, result, sourceRef |
ai.computer_session_queued | A computer task was queued for the computer worker. | id, title, kind, target |
ai.computer_session_started | A computer task started running. | id, provider |
ai.computer_session_stopped | A computer session was stopped. | id |
ai.connection_shared | Who may use an AI connection changed. | id, provider, scope |
ai.conversation_deleted | A thread was deleted. | id |
ai.conversation_started | A thread with Era was opened. | id, agentId |
ai.decide_outcome_recorded | A person confirmed or corrected one of Era’s decisions. | id, questionKey, outcome |
ai.erasure_candidate_resolved | A manager erased or dismissed a possible match of an erasure request. | id, decision, facts |
ai.key_rotation_due | A provider key is older than the rotation period. | id, provider, ageDays, recipientUserId |
ai.knowledge_base_archived | A knowledge space was archived. | id, brainId, name |
ai.knowledge_base_created | A knowledge space was created. | id, brainId, name |
ai.knowledge_base_updated | A knowledge space changed. | id, brainId, name |
ai.learning_decided | A person approved or rejected what Era asked to keep. | id, kind, decision, resultRef |
ai.learning_forgotten | A person told Era to forget something, or to stop using a skill. | kind, ref |
ai.learning_proposed | Era asked to remember something, or to keep a skill. | id, kind, proposedBy |
ai.memory_refiled | A person changed a memory’s category, who it is for or when it ends. | id, memoryId |
ai.model_policy_updated | The model for a kind of work changed. | taskClass, model |
ai.provider_checked | An AI provider health check ran. | id, ok |
ai.provider_recovered | A failing provider answered again. | id, provider, recipientUserId |
ai.provider_removed | An AI provider was removed. | id, provider |
ai.provider_unhealthy | A provider failed its scheduled check; runs route around it. | id, provider, error, recipientUserId |
ai.provider_updated | An AI provider or its key was saved. | id, provider |
ai.skill_evaluated | A skill version was evaluated. | id, skillId, score |
ai.skill_installed | A skill was installed from a template. | skillId |
ai.skill_paused | A skill was paused. | skillId |
ai.skill_policy_updated | A skill’s published state or permissions changed. | skillId, published |
ai.skill_promoted | A skill version went live (or was rolled back to). | id, skillId, version |
ai.skill_resumed | A skill was resumed. | skillId |
ai.skill_uninstalled | A skill was uninstalled. | skillId |
ai.skill_version_created | A skill version was saved. | id, skillId, version |
ai.source_choice_updated | Where an Era, workflow, brain or other AI-using thing runs changed. | id, subjectType, subjectId |
ai.subscription_connected | A person connected their own AI subscription. | id, provider, execution, recipientUserId |
ai.subscription_disconnected | A person disconnected their own AI subscription. | id, provider, recipientUserId |
ai.subscription_limited | A person’s own subscription reached its plan limit. | id, provider, resetsAt, recipientUserId |
ai.subscription_needs_login | A person’s own subscription signed out; they need to sign in again. | id, provider, recipientUserId |
ai.subscription_recovered | A person’s own subscription works again. | id, provider, recipientUserId |
ai.task_assigned | A task was handed to a person or an agent. | id, assigneeUserId, assigneeAgentId, recipientUserId |
ai.task_cancelled | A task was cancelled (its status set to cancelled). | id |
ai.task_completed | A task was completed. | id, nextId |
ai.task_created | A task was created. | id, title, recordType, recordId, recipientUserId |
ai.task_deleted | A task was deleted. | id |
ai.task_due | A task is due within a day. For its assignee (or its author when an agent holds it). | id, title, dueAt, recordType, recordId, recipientUserId |
ai.task_overdue | A task is past its due date. For its assignee (or its author when an agent holds it). | id, title, dueAt, recordType, recordId, recipientUserId |
ai.task_reopened | A task was reopened. | id |
ai.task_updated | A task changed. | id |
ai.template_installed | An agent, skill or workflow was installed from the marketplace. | id, kind, instanceId, templateId, requiredApps |