ReferenceReference by module

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

ResourceTableList and readPOSTPATCHDELETE
ai_agentsai_agent/api/v1/ai_agents
ai_budgetsai_budget/api/v1/ai_budgets
ai_conversationsai_conversation/api/v1/ai_conversations
ai_messagesai_message/api/v1/ai_messages
ai_model_policiesai_model_policy/api/v1/ai_model_policies
ai_providersai_provider/api/v1/ai_providers
ai_runsai_run/api/v1/ai_runs
ai_skill_releasesai_skill_release/api/v1/ai_skill_releases
ai_skill_runsai_skill_run/api/v1/ai_skill_runs
ai_skill_versionsai_skill_version/api/v1/ai_skill_versions
ai_source_choicesai_source_choice/api/v1/ai_source_choices
ai_tasksai_task/api/v1/ai_tasks
ai_template_installsai_template_install/api/v1/ai_template_installs
ai_usagesai_usage/api/v1/ai_usages
brain_bindingsbrain_binding/api/v1/brain_bindings
brain_erasuresbrain_erasure/api/v1/brain_erasures
brain_fact_reviewsbrain_fact_review/api/v1/brain_fact_reviews
brain_insightsbrain_insight/api/v1/brain_insights
brainsbrain/api/v1/brainsai.create_brain
computer_folderscomputer_folder/api/v1/computer_folders
computer_machinescomputer_machine/api/v1/computer_machines
computer_policiescomputer_policy/api/v1/computer_policies
decide_decisionsdecide_decision/api/v1/decide_decisions
era_action_capsera_action_cap/api/v1/era_action_caps
era_chat_membersera_chat_member/api/v1/era_chat_members
era_chat_seensera_chat_seen/api/v1/era_chat_seens
era_chat_sharesera_chat_share/api/v1/era_chat_shares
era_learningsera_learning/api/v1/era_learnings
knowledge_basesknowledge_base/api/v1/knowledge_basesai.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

ActionNeedsWhat it does
ai.archive_brainai:manageArchive a brain
ai.archive_knowledge_baseai:manageArchive a knowledge space
ai.assign_taskai:writeHand a task over
ai.bind_brainai:manageGive a brain to an Era, workflow or voice agent
ai.check_budgetai:readCheck the AI budget
ai.clear_budgetai:manageRemove an AI budget
ai.close_code_sessionai:handleClose the coding session
ai.complete_taskai:writeComplete a task
ai.connect_subscriptionai:writeConnect my own AI subscription
ai.create_agentai:manageCreate an agent
ai.create_brainai:manageCreate a brain
ai.create_knowledge_baseai:manageAdd a knowledge space
ai.create_taskai:writeCreate a task
ai.decide_computer_stepai:handleApprove or refuse a computer step
ai.decide_learningai:writeAnswer what Era asked to keep
ai.delete_agentai:deleteDelete an agent
ai.delete_computerai:handleDelete my cloud computer
ai.delete_conversationai:deleteDelete a conversation
ai.delete_taskai:deleteDelete a task
ai.disconnect_subscriptionai:writeDisconnect my subscription
ai.erase_brain_factai:managePermanently erase something Era learned
ai.erase_brain_personai:manageErase everything Era learned about a person
ai.escalate_approvalai:readEscalate a waiting approval
ai.evaluate_skillai:writeRecord a skill evaluation
ai.forget_computer_folderai:handleForget a folder
ai.forget_learningai:writeForget something ("bunu unut")
ai.link_engine_agentai:manageLink an agent to an assistant
ai.mark_chat_seenai:readOpen a shared chat
ai.open_code_sessionai:handleStart a coding session
ai.pause_computerai:handleTurn off my cloud computer
ai.pause_computer_sessionai:handlePause a computer task
ai.promote_skillai:managePromote a skill version
ai.propose_learningai:writeAsk to remember something
ai.provision_computerai:handleSet up my cloud computer
ai.record_brain_insightai:writeRecord an insight
ai.record_code_sessionai:handleRecord a coding turn
ai.record_computer_fileai:handleSave a computer file
ai.record_computer_frameai:handleRecord a live frame
ai.record_computer_machineai:handleRecord cloud computer state
ai.record_computer_progressai:handleRecord computer progress
ai.record_decide_outcomeai:writeConfirm or correct one of Era’s decisions
ai.record_plan_limitsai:readRecord a subscription’s plan limits
ai.record_provider_checkai:manageRecord a provider health check
ai.record_provider_healthai:handleRecord a scheduled provider health check
ai.record_skill_runai:readRecord a skill run
ai.record_subscription_stateai:readRecord a subscription’s state
ai.record_template_installai:writeRecord a marketplace install
ai.record_turnai:writeRecord a turn
ai.record_usageai:readRecord AI usage
ai.refile_brain_factai:writeRe-file something Era learned
ai.remind_taskai:handleSend a task reminder
ai.remove_providerai:manageRemove an AI provider
ai.reopen_taskai:writeReopen a task
ai.resolve_erasure_candidateai:manageDecide a possible match of an erasure request
ai.resume_computer_sessionai:handleResume a computer task
ai.review_brain_factai:writeCorrect, forget or keep private something Era learned
ai.run_agentai:handleRun an agent
ai.save_computer_folderai:handleRemember a folder
ai.save_computer_policyai:manageSave computer rules
ai.set_action_capai:writeSet a daily allowance for Era
ai.set_agent_enabledai:manageSwitch an agent on or off
ai.set_brain_insight_statusai:writeMark an insight
ai.set_budgetai:manageSet an AI budget
ai.set_chat_memberai:writeShare a chat with a person
ai.set_connection_shareai:writeChoose who may use a connection
ai.set_model_policyai:manageChoose a model for a kind of work
ai.set_providerai:manageSave an AI provider
ai.set_skill_policyai:manageSet a skill’s permissions
ai.set_skill_releaseai:managePause, resume or record an install
ai.set_source_choiceai:writeChoose where AI runs
ai.set_subscription_useai:writeChoose where my subscription is used
ai.share_chatai:writeShare a chat
ai.snapshot_skillai:writeSave a skill version
ai.start_computerai:handleTurn on my cloud computer
ai.start_computer_sessionai:handleGive the computer a task
ai.start_conversationai:writeStart a conversation
ai.steer_computer_sessionai:handleTell a running computer task something
ai.stop_all_computer_sessionsai:handleEmergency stop
ai.stop_computer_sessionai:handleStop a computer task
ai.unbind_brainai:manageTake a brain away
ai.uninstall_skillai:deleteUninstall a skill
ai.update_agentai:manageChange an agent
ai.update_brainai:manageChange a brain
ai.update_knowledge_baseai:manageChange a knowledge space
ai.update_taskai:writeChange a task
ai.use_action_capai:readUse 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

POSThttps://app.getera.io/api/v1/brains/actions/archive_brain
API key or OAuth token · ai:manage
  • Canonical address: POST /api/v1/actions/ai.archive_brain

Input

FieldTypeRequiredNotes
iduuidyesBrain

Preconditions

The action is refused with 409 and one of these codes:

CodeRefused when
brain_not_foundThe brain must exist in this workspace.
not_your_brainSomeone else’s personal brain is theirs to archive.
archivedIt is already archived.
default_brainThe 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"}'
Response
{
  "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"
tools/call
{
  "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

POSThttps://app.getera.io/api/v1/knowledge_bases/actions/archive_knowledge_base
API key or OAuth token · ai:manage
  • Canonical address: POST /api/v1/actions/ai.archive_knowledge_base

Input

FieldTypeRequiredNotes
iduuidyesSpace

Preconditions

The action is refused with 409 and one of these codes:

CodeRefused when
knowledge_base_not_foundThe space must exist in this workspace.
archivedIt is already archived.
default_knowledge_baseThe 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"}'
Response
{
  "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"
tools/call
{
  "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

POSThttps://app.getera.io/api/v1/ai_tasks/{id}/actions/assign_task
API key or OAuth token · ai:write
  • Canonical address: POST /api/v1/actions/ai.assign_task

Input

FieldTypeRequiredNotes
iduuidyesFilled from the path {id} · Task · id of ai_task
assigneeUserIduuidPerson · id of app_user
assigneeAgentIduuidAgent · id of ai_agent
notestringNote · max 2000

Preconditions

The action is refused with 409 and one of these codes:

CodeRefused when
not_foundThe task must exist in this workspace.
not_memberThe person must be a member of this workspace.
unknown_agentThe agent must exist in this workspace.
agent_disabledA 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"}'
Response
{
  "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"
tools/call
{
  "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

POSThttps://app.getera.io/api/v1/brain_bindings/actions/bind_brain
API key or OAuth token · ai:manage
  • Canonical address: POST /api/v1/actions/ai.bind_brain

Input

FieldTypeRequiredNotes
subjectTypestringyesFor · agent · workflow · voice_agent · era_chat · meeting · team · role · max 20
subjectIdstringyesWhich one · max 120
brainIduuidyesBrain
knowledgeBaseIdsobject / arraySpaces (empty = all)
accessstring (enum)Access · Allowed values: read, read_write

Preconditions

The action is refused with 409 and one of these codes:

CodeRefused when
bad_subjectIt names an Era, workflow, voice agent, meeting or Era chat.
brain_not_foundThe brain must exist in this workspace.
not_your_brainSomeone else’s personal brain is theirs.
archivedAn archived brain is not given out.
personal_brainA personal brain serves only its owner’s own chat.
agent_not_foundThe Era must exist.
subject_not_foundA team or role must exist in this workspace.
knowledge_base_not_in_brainThe 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"}'
Response
{
  "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"
tools/call
{
  "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

POSThttps://app.getera.io/api/v1/ai_budgets/actions/check_budget
API key or OAuth token · ai:read
  • Canonical address: POST /api/v1/actions/ai.check_budget

Input

FieldTypeRequiredNotes
agentIduuidAgent · 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"}'
Response
{
  "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"
tools/call
{
  "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

POSThttps://app.getera.io/api/v1/ai_budgets/{id}/actions/clear_budget
API key or OAuth token · ai:manage
  • Canonical address: POST /api/v1/actions/ai.clear_budget

Input

FieldTypeRequiredNotes
iduuidyesFilled from the path {id} · Budget · id of ai_budget

Preconditions

The action is refused with 409 and one of these codes:

CodeRefused when
not_foundThe 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 '{}'
Response
{
  "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
tools/call
{
  "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

POSThttps://app.getera.io/api/v1/actions/ai.close_code_session
API key or OAuth token · ai:handle

Input

FieldTypeRequiredNotes
iduuidyesSession · id of code_session

Preconditions

The action is refused with 409 and one of these codes:

CodeRefused when
not_foundOnly 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"}'
Response
{
  "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"
tools/call
{
  "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

POSThttps://app.getera.io/api/v1/ai_tasks/{id}/actions/complete_task
API key or OAuth token · ai:write
  • Canonical address: POST /api/v1/actions/ai.complete_task

Input

FieldTypeRequiredNotes
iduuidyesFilled from the path {id} · Task · id of ai_task

Preconditions

The action is refused with 409 and one of these codes:

CodeRefused when
not_foundThe task must exist in this workspace.
already_doneA 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 '{}'
Response
{
  "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
tools/call
{
  "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

POSThttps://app.getera.io/api/v1/ai_providers/actions/connect_subscription
API key or OAuth token · ai:write
  • Canonical address: POST /api/v1/actions/ai.connect_subscription

Input

FieldTypeRequiredNotes
providerstring (enum)yesSubscription · 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
executionstring (enum)yesRuns · Allowed values: remote, local_device, cloud_computer
deviceIdstringComputer · max 64
secretRefstringVault sign-in · max 64
oauthSecretRefstringVault grant · max 64
keyHintstringKey (masked) · max 40
accountLabelstringAccount · max 160
statusstring (enum)Status · Allowed values: connecting, healthy
metaobject / arrayDetails

Preconditions

The action is refused with 409 and one of these codes:

CodeRefused when
unknown_subscriptionOnly a subscription the Harness Manager knows, in the places it can run.
bad_secret_refA cloud sign-in must be a vault secret of this workspace.
device_requiredA 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"}'
Response
{
  "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"
tools/call
{
  "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

POSThttps://app.getera.io/api/v1/ai_agents/actions/create_agent
API key or OAuth token · ai:manage
  • Canonical address: POST /api/v1/actions/ai.create_agent

Input

FieldTypeRequiredNotes
namestringyesName · max 160
instructionsstringInstructions · max 20000
descriptionstringDescription · max 2000
modelstringModel · max 120
allowedModulesobject / arrayLimited to these modules · A list of module codes. Empty means every module its author can already use.
wakesOnobject / arrayWakes up on · A list of event names — crm.lead_won, crm.* or *. Empty means it only runs when asked.
maxStepsnumberTool calls per run · min 1 · max 40

Preconditions

The action is refused with 409 and one of these codes:

CodeRefused when
empty_nameAn agent needs a name.
bad_modulesIt may only be limited to modules this platform registers.
bad_triggerA 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"}'
Response
{
  "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"
tools/call
{
  "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

POSThttps://app.getera.io/api/v1/brains/actions/create_brain
API key or OAuth token · ai:manage
  • REST alias: POST /api/v1/brains
  • Canonical address: POST /api/v1/actions/ai.create_brain

Input

FieldTypeRequiredNotes
namestringyesName · max 80
descriptionstringWhat it is for · max 500
kindstring (enum)Kind · Allowed values: company, personal, team, era, voice, brand, custom
scopestring (enum)Who uses it · Allowed values: workspace, team, era, voice_agent, person
scopeRefuuidWhose
memorystring (enum)Memory · Allowed values: long, short
shortTtlHoursnumberShort memory lasts (hours) · min 1 · max 720
embeddingSpacestring (enum)Where it understands meaning · Allowed values: bge-m3-1024, e5-small-384
learnFromobject / arrayLearns from
knowledgeBasesobject / arrayKnowledge spaces

Preconditions

The action is refused with 409 and one of these codes:

CodeRefused when
empty_nameA brain needs a name.
name_takenBrain names are unique in a workspace.
not_your_brainA personal brain can only be your own.
missing_scope_refA brain for a team, an Era or a voice agent names which one.
agent_not_foundAn Era’s brain belongs to an Era that exists.
team_not_foundA team’s brain belongs to a team of this workspace.
invalid_learn_fromWhat 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"}'
Response
{
  "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"
tools/call
{
  "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

POSThttps://app.getera.io/api/v1/knowledge_bases/actions/create_knowledge_base
API key or OAuth token · ai:manage
  • REST alias: POST /api/v1/knowledge_bases
  • Canonical address: POST /api/v1/actions/ai.create_knowledge_base

Input

FieldTypeRequiredNotes
brainIduuidyesBrain
namestringyesName · max 80
kindstring (enum)Kind · Allowed values: company, product, sales, marketing, customers, projects, personal, voice, industry, meetings, brand, finance, support, custom
descriptionstringWhat goes here · max 500

Preconditions

The action is refused with 409 and one of these codes:

CodeRefused when
brain_not_foundThe brain must exist in this workspace.
not_your_brainSomeone else’s personal brain is theirs.
archivedAn archived brain gets no new spaces.
empty_nameA space needs a name.
name_takenSpace 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"}'
Response
{
  "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"
tools/call
{
  "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

POSThttps://app.getera.io/api/v1/ai_tasks/actions/create_task
API key or OAuth token · ai:write
  • Canonical address: POST /api/v1/actions/ai.create_task

Input

FieldTypeRequiredNotes
titlestringyesTitle · max 300
descriptionstringDetails · max 10000
listNamestringList · max 80
prioritystring (enum)Priority · Allowed values: low, normal, high, urgent
dueAtdate-timeDue
recurrencestring (enum)Repeats · Allowed values: none, daily, weekly, monthly
assigneeUserIduuidPerson · id of app_user
assigneeAgentIduuidAgent · id of ai_agent
recordTypestring (enum)About · Allowed values: customer, lead, appointment, order, conversation
recordIduuidRecord id

Preconditions

The action is refused with 409 and one of these codes:

CodeRefused when
empty_titleA task needs a title.
not_memberThe person must be a member of this workspace.
unknown_agentThe agent must exist in this workspace.
agent_disabledA 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"}'
Response
{
  "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"
tools/call
{
  "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

POSThttps://app.getera.io/api/v1/actions/ai.decide_computer_step
API key or OAuth token · ai:handle

Input

FieldTypeRequiredNotes
iduuidyesSession · id of computer_session
approvalIduuidyesStep
decisionstring (enum)yesDecision · Allowed values: approve, deny
allowSimilarbooleanAllow similar steps for 15 minutes
notestringNote · max 500

Preconditions

The action is refused with 409 and one of these codes:

CodeRefused when
not_foundThe session must exist in this workspace.
no_pending_approvalThe 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"}'
Response
{
  "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"
tools/call
{
  "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

POSThttps://app.getera.io/api/v1/era_learnings/actions/decide_learning
API key or OAuth token · ai:write
  • Canonical address: POST /api/v1/actions/ai.decide_learning

Input

FieldTypeRequiredNotes
iduuidyesWhat Era asked
decisionstring (enum)yesAnswer · Allowed values: approve, reject
statementstringWording · max 4000
memoryKindstringCategory · fact · preference · rule · procedure · max 20
audiencestringFor · person · workspace · module · max 20
moduleCodestringModule · max 64
expiresAtdate-timeUntil
skillDescriptionstringWhat the skill is for · max 1024
skillContentstringThe skill’s steps · max 50000

Preconditions

The action is refused with 409 and one of these codes:

CodeRefused when
learning_not_foundEra must have asked about it here.
already_decidedA proposal is answered once.
not_yoursA proposal for one person is theirs to answer (or a manager’s).
empty_statementA re-worded memory still says something.
bad_memory_kindA memory is a fact, a preference, a rule or a procedure.
module_requiredA memory for one module names a module that exists.
already_expiredAn end date is in the future.
skill_incompleteAn 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"}'
Response
{
  "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"
tools/call
{
  "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

POSThttps://app.getera.io/api/v1/ai_agents/{id}/actions/delete_agent
API key or OAuth token · ai:delete
  • Canonical address: POST /api/v1/actions/ai.delete_agent

Input

FieldTypeRequiredNotes
iduuidyesFilled from the path {id} · Agent · id of ai_agent

Preconditions

The action is refused with 409 and one of these codes:

CodeRefused when
not_foundThe 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 '{}'
Response
{
  "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
tools/call
{
  "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

POSThttps://app.getera.io/api/v1/computer_machines/actions/delete_computer
API key or OAuth token · ai:handle
  • 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:

CodeRefused when
no_computerYou 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 '{}'
Response
{
  "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
tools/call
{
  "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

POSThttps://app.getera.io/api/v1/ai_conversations/{id}/actions/delete_conversation
API key or OAuth token · ai:delete
  • Canonical address: POST /api/v1/actions/ai.delete_conversation

Input

FieldTypeRequiredNotes
iduuidyesFilled from the path {id} · Conversation · id of ai_conversation

Preconditions

The action is refused with 409 and one of these codes:

CodeRefused when
not_foundThe 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 '{}'
Response
{
  "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
tools/call
{
  "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

POSThttps://app.getera.io/api/v1/ai_tasks/{id}/actions/delete_task
API key or OAuth token · ai:delete
  • Canonical address: POST /api/v1/actions/ai.delete_task

Input

FieldTypeRequiredNotes
iduuidyesFilled from the path {id} · Task · id of ai_task

Preconditions

The action is refused with 409 and one of these codes:

CodeRefused when
not_foundThe 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 '{}'
Response
{
  "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
tools/call
{
  "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

POSThttps://app.getera.io/api/v1/ai_providers/{id}/actions/disconnect_subscription
API key or OAuth token · ai:write
  • Canonical address: POST /api/v1/actions/ai.disconnect_subscription

Input

FieldTypeRequiredNotes
iduuidyesFilled from the path {id} · Subscription · id of ai_provider

Preconditions

The action is refused with 409 and one of these codes:

CodeRefused when
not_foundThe subscription must be connected in this workspace.
not_ownerIts 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 '{}'
Response
{
  "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
tools/call
{
  "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

POSThttps://app.getera.io/api/v1/brain_erasures/actions/erase_brain_fact
API key or OAuth token · ai:manage
  • Canonical address: POST /api/v1/actions/ai.erase_brain_fact

Input

FieldTypeRequiredNotes
memoryIduuidyesWhat Era learned
reasonstringWhy (e.g. a KVKK request’s reference) · max 500

Preconditions

The action is refused with 409 and one of these codes:

CodeRefused when
fact_not_foundEra 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"}'
Response
{
  "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"
tools/call
{
  "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

POSThttps://app.getera.io/api/v1/brain_erasures/actions/erase_brain_person
API key or OAuth token · ai:manage
  • Canonical address: POST /api/v1/actions/ai.erase_brain_person

Input

FieldTypeRequiredNotes
entityIduuidyesPerson
reasonstringRequest reference · max 500
requestedOnstringThe day they asked · max 10

Preconditions

The action is refused with 409 and one of these codes:

CodeRefused when
person_not_foundEra must know the person in this workspace.
bad_dateThe 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"}'
Response
{
  "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"
tools/call
{
  "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

Run by Era itself (machine-only). Listed so the reference is complete; an API key or a token is refused (403 machine_only).
POSThttps://app.getera.io/api/v1/actions/ai.escalate_approval
API key or OAuth token · ai:read

Input

FieldTypeRequiredNotes
approvalIdstringyesApproval · max 64
intentstringWhat it asks · max 300
toolstringTool · max 200
ageHoursnumberyesWaiting 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

POSThttps://app.getera.io/api/v1/ai_skill_versions/{id}/actions/evaluate_skill
API key or OAuth token · ai:write
  • Canonical address: POST /api/v1/actions/ai.evaluate_skill

Input

FieldTypeRequiredNotes
versionIduuidyesFilled from the path {id} · Version · id of ai_skill_version
passednumberyesPassed · min 0
totalnumberyesCases · min 0
notesstringNotes · max 10000

Preconditions

The action is refused with 409 and one of these codes:

CodeRefused when
not_foundThe 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}'
Response
{
  "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
tools/call
{
  "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

POSThttps://app.getera.io/api/v1/computer_folders/{id}/actions/forget_computer_folder
API key or OAuth token · ai:handle
  • Canonical address: POST /api/v1/actions/ai.forget_computer_folder

Input

FieldTypeRequiredNotes
iduuidyesFilled from the path {id} · Folder · id of computer_folder

Preconditions

The action is refused with 409 and one of these codes:

CodeRefused when
not_foundThe 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 '{}'
Response
{
  "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
tools/call
{
  "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

POSThttps://app.getera.io/api/v1/brain_fact_reviews/actions/forget_learning
API key or OAuth token · ai:write
  • Canonical address: POST /api/v1/actions/ai.forget_learning

Input

FieldTypeRequiredNotes
memoryIduuidMemory
aboutstringWhat to forget, in words · max 500
skillNamestringSkill to stop using · max 64

Preconditions

The action is refused with 409 and one of these codes:

CodeRefused when
nothing_to_forgetEra must remember it (or have that skill).
ambiguousWords 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"}'
Response
{
  "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"
tools/call
{
  "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

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

POSThttps://app.getera.io/api/v1/ai_agents/{id}/actions/link_engine_agent
API key or OAuth token · ai:manage
  • Canonical address: POST /api/v1/actions/ai.link_engine_agent
FieldTypeRequiredNotes
iduuidyesFilled from the path {id} · Agent · id of ai_agent
engineAgentIdstringAssistant · max 64

The action is refused with 409 and one of these codes:

CodeRefused when
not_foundThe agent must exist in this workspace.
already_linkedAn 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"}'
Response
{
  "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"
tools/call
{
  "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

POSThttps://app.getera.io/api/v1/era_chat_seens/actions/mark_chat_seen
API key or OAuth token · ai:read
  • Canonical address: POST /api/v1/actions/ai.mark_chat_seen

Input

FieldTypeRequiredNotes
conversationIduuidyesChat

Preconditions

The action is refused with 409 and one of these codes:

CodeRefused when
not_foundThe chat must exist in this workspace.
no_accessThe 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"}'
Response
{
  "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"
tools/call
{
  "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

POSThttps://app.getera.io/api/v1/computer_folders/{id}/actions/open_code_session
API key or OAuth token · ai:handle
  • Canonical address: POST /api/v1/actions/ai.open_code_session

Input

FieldTypeRequiredNotes
conversationIduuidConversation
folderIduuidFilled from the path {id} · Folder · id of computer_folder
folderNamestringyesFolder name · max 80
pathstringyesFull path · max 1000
harnessstringyesEngine · claude (Claude Code) or codex (Codex). · max 20
deviceIdstringComputer · max 80
surfacestringStarted from · max 40

Preconditions

The action is refused with 409 and one of these codes:

CodeRefused when
computer_access_requiredOnly the workspace owner, or a member given computer access, can reach a computer.
unknown_harnessA 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"}'
Response
{
  "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"
tools/call
{
  "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

POSThttps://app.getera.io/api/v1/computer_machines/actions/pause_computer
API key or OAuth token · ai:handle
  • 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:

CodeRefused when
no_computerYou need a cloud computer first.
not_runningOnly 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 '{}'
Response
{
  "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
tools/call
{
  "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

POSThttps://app.getera.io/api/v1/actions/ai.pause_computer_session
API key or OAuth token · ai:handle

Input

FieldTypeRequiredNotes
iduuidyesSession · id of computer_session

Preconditions

The action is refused with 409 and one of these codes:

CodeRefused when
not_foundThe session must exist in this workspace.
not_runningOnly 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"}'
Response
{
  "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"
tools/call
{
  "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

POSThttps://app.getera.io/api/v1/ai_skill_versions/{id}/actions/promote_skill
API key or OAuth token · ai:manage
  • Canonical address: POST /api/v1/actions/ai.promote_skill

Input

FieldTypeRequiredNotes
versionIduuidyesFilled from the path {id} · Version · id of ai_skill_version

Preconditions

The action is refused with 409 and one of these codes:

CodeRefused when
not_foundThe version must exist in this workspace.
not_evaluatedOnly 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 '{}'
Response
{
  "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
tools/call
{
  "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

POSThttps://app.getera.io/api/v1/era_learnings/actions/propose_learning
API key or OAuth token · ai:write
  • Canonical address: POST /api/v1/actions/ai.propose_learning

Input

FieldTypeRequiredNotes
kindstring (enum)What · Allowed values: memory, skill
statementstringWhat to remember (one self-contained sentence) · max 4000
memoryKindstringCategory · fact · preference · rule · procedure · max 20
audiencestringFor · person (only the person you talk to) · workspace (everyone) · module (only in one module) · max 20
moduleCodestringModule · For audience "module": retail, appointments, crm … · max 64
expiresAtdate-timeUntil
forUseruuidWhose approval
brainIduuidBrain
knowledgeBaseIduuidKnowledge space
confidencenumberHow sure · min 0 · max 1
skillIdstringSkill to update · max 64
skillNamestringSkill name (kebab-case) · max 64
skillDescriptionstringWhat the skill is for · max 1024
skillContentstringThe skill’s steps · max 50000
reasonstringWhy Era thinks so · max 1000
sourceobject / arrayWhere it came from · { kind: "conversation", ref, label, at, url }
evidenceCountnumberSeen this many times · min 1 · max 1000
dedupeKeystringSame-proposal key · max 200
proposedBystringProposed by · era · learning · skills · max 20
toldbooleanThe 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:

CodeRefused when
empty_statementA memory says what to remember.
bad_memory_kindA memory is a fact, a preference, a rule or a procedure.
module_requiredA memory for one module names a module that exists.
already_expiredAn end date is in the future.
already_knownEra does not ask about what it already remembers.
already_proposedEra asks about the same thing once until it is answered.
rejected_beforeEra does not ask again about what the owner said no to, or about a kind of thing the owner keeps refusing.
skill_incompleteA skill has a kebab-case name, a one-line purpose and its steps.
skill_not_foundA skill to update must exist here.
brain_not_foundA 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"}'
Response
{
  "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"
tools/call
{
  "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

POSThttps://app.getera.io/api/v1/computer_machines/actions/provision_computer
API key or OAuth token · ai:handle
  • Canonical address: POST /api/v1/actions/ai.provision_computer

Input

FieldTypeRequiredNotes
namestringName · max 80
providerstringProvider · max 40

Preconditions

The action is refused with 409 and one of these codes:

CodeRefused when
already_has_computerOne cloud computer per person.
computer_access_requiredOnly the workspace owner, or a member given computer access, can reach a computer.
unknown_providerA provider asked for must be boxd, e2b or digitalocean.
hours_used_upThe 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"}'
Response
{
  "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"
tools/call
{
  "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

POSThttps://app.getera.io/api/v1/brain_insights/actions/record_brain_insight
API key or OAuth token · ai:write
  • Canonical address: POST /api/v1/actions/ai.record_brain_insight

Input

FieldTypeRequiredNotes
rolestringFor · sales · marketing · finance · operations · support · management · general · max 20
titlestringyesTitle · max 200
bodystringDetails · max 4000
severitystring (enum)Kind · Allowed values: info, opportunity, warning
brainIduuidBrain
sourcesobject / arraySources
reasoningstringWhy · max 2000
suggestedActionobject / arraySuggested next step
generatedByobject / arrayMade by
dedupeKeystringSame-insight key · max 200
originstring (enum)Noticed by · Allowed values: learning, outcome, era, person
kindstringKind of insight · max 64

Preconditions

The action is refused with 409 and one of these codes:

CodeRefused when
bad_roleAn insight is for a known role.
empty_titleAn insight needs a title.
brain_not_foundA named brain must exist.
not_your_brainSomeone else’s personal brain is theirs.
invalid_sourcesEach source is an object naming where it came from.
already_notedThe 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"}'
Response
{
  "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"
tools/call
{
  "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

POSThttps://app.getera.io/api/v1/actions/ai.record_code_session
API key or OAuth token · ai:handle

Input

FieldTypeRequiredNotes
iduuidyesSession · id of code_session
turnStatestringState · max 20
currentJobIdstringJob · max 80
providerSessionIdstringResume cursor · max 200
harnessstringEngine · max 20
deviceIdstringComputer · max 80
lastPromptstringLast prompt · max 4000
lastSummarystringLast summary · max 8000
filesobject / arrayFiles touched
diffobject / arrayDiff summary
testsobject / arrayTest result
addTurnbooleanA turn ended
pushApprovedbooleanPush approved
pushPendingbooleanPush waits for OK

Preconditions

The action is refused with 409 and one of these codes:

CodeRefused when
not_foundThe session must be yours.
invalid_stateOnly known states, and files as a list.
unknown_harnessA 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"}'
Response
{
  "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"
tools/call
{
  "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

POSThttps://app.getera.io/api/v1/actions/ai.record_computer_file
API key or OAuth token · ai:handle

Input

FieldTypeRequiredNotes
iduuidyesSession · id of computer_session
namestringyesName · max 200
mimestringType · max 100
contentstringyesContent (base64) · max 14000000

Preconditions

The action is refused with 409 and one of these codes:

CodeRefused when
not_foundThe session must exist in this workspace.
too_largeA 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)"}'
Response
{
  "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)"
tools/call
{
  "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

POSThttps://app.getera.io/api/v1/actions/ai.record_computer_frame
API key or OAuth token · ai:handle

Input

FieldTypeRequiredNotes
iduuidyesSession · id of computer_session
imagestringyesImage (base64) · max 3000000
mimestringType · max 40
widthnumberWidth · min 1
heightnumberHeight · min 1

Preconditions

The action is refused with 409 and one of these codes:

CodeRefused when
not_foundThe session must exist in this workspace.
invalid_frameA 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)"}'
Response
{
  "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)"
tools/call
{
  "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

POSThttps://app.getera.io/api/v1/computer_machines/{id}/actions/record_computer_machine
API key or OAuth token · ai:handle
  • Canonical address: POST /api/v1/actions/ai.record_computer_machine

Input

FieldTypeRequiredNotes
iduuidyesFilled from the path {id} · Computer · id of computer_machine
statestringyesState · max 20
externalIdstringProvider id · max 200
viewerSecretRefstringViewer secret · max 200
viewerUrlstringViewer address · max 2000
errorstringError · max 500
addSecondsnumberSeconds used · min 0
metadataobject / arrayDetails

Preconditions

The action is refused with 409 and one of these codes:

CodeRefused when
no_computerThe machine must exist.
invalid_stateOnly 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"}'
Response
{
  "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"
tools/call
{
  "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

POSThttps://app.getera.io/api/v1/actions/ai.record_computer_progress
API key or OAuth token · ai:handle

Input

FieldTypeRequiredNotes
iduuidyesSession · id of computer_session
workerstringyesWorker · max 200
statusstringStatus · max 40
activitystringActivity · max 300
providerstringProvider · max 60
stepCountnumberSteps · min 0
costUsdnumberCost · min 0
currentUrlstringPage · max 2000
approvalobject / arrayApproval
clearApprovalbooleanClear approval
resultstringResult · max 20000
successbooleanSuccess
eventsobject / arrayEvents

Preconditions

The action is refused with 409 and one of these codes:

CodeRefused when
not_foundThe session must exist in this workspace.
not_your_sessionOnly the worker that claimed a session reports on it.
already_stoppedA finished session takes no more progress.
invalid_eventsTimeline 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"}'
Response
{
  "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"
tools/call
{
  "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

POSThttps://app.getera.io/api/v1/decide_decisions/actions/record_decide_outcome
API key or OAuth token · ai:write
  • Canonical address: POST /api/v1/actions/ai.record_decide_outcome

Input

FieldTypeRequiredNotes
decisionIduuidyesDecision
outcomestring (enum)yesVerdict · Allowed values: confirmed, corrected
correctedAnswerobject / arrayWhat was right
notestringNote · max 500
fromstring (enum)Judged by · Allowed values: person, workflow, era

Preconditions

The action is refused with 409 and one of these codes:

CodeRefused when
decision_not_foundThe decision must exist in this workspace.
bad_correctionA correction names yes or no, one of the options, or one of the levels.
same_answerA 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"}'
Response
{
  "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"
tools/call
{
  "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

POSThttps://app.getera.io/api/v1/ai_providers/{id}/actions/record_plan_limits
API key or OAuth token · ai:read
  • Canonical address: POST /api/v1/actions/ai.record_plan_limits

Input

FieldTypeRequiredNotes
iduuidyesFilled from the path {id} · Subscription · id of ai_provider
limitsobject / arrayyesPlan limits

Preconditions

The action is refused with 409 and one of these codes:

CodeRefused when
not_foundThe subscription must be connected in this workspace.
not_ownerOnly its owner’s computer reports its limits.
bad_plan_limitsPlan 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":{}}'
Response
{
  "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":{}}'
tools/call
{
  "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

POSThttps://app.getera.io/api/v1/ai_providers/{id}/actions/record_provider_check
API key or OAuth token · ai:manage
  • Canonical address: POST /api/v1/actions/ai.record_provider_check

Input

FieldTypeRequiredNotes
iduuidyesFilled from the path {id} · Provider · id of ai_provider
okbooleanyesAnswered
errorstringError · max 2000

Preconditions

The action is refused with 409 and one of these codes:

CodeRefused when
not_foundThe 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}'
Response
{
  "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
tools/call
{
  "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

Run by Era itself (machine-only). Listed so the reference is complete; an API key or a token is refused (403 machine_only).
POSThttps://app.getera.io/api/v1/ai_providers/{id}/actions/record_provider_health
API key or OAuth token · ai:handle
  • Canonical address: POST /api/v1/actions/ai.record_provider_health

Input

FieldTypeRequiredNotes
iduuidyesFilled from the path {id} · Provider · id of ai_provider
okbooleanyesAnswered
errorstringError · max 2000
latencyMsnumberLatency (ms) · min 0

Preconditions

The action is refused with 409 and one of these codes:

CodeRefused when
not_foundThe 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

Run by Era itself (machine-only). Listed so the reference is complete; an API key or a token is refused (403 machine_only).
POSThttps://app.getera.io/api/v1/ai_skill_runs/actions/record_skill_run
API key or OAuth token · ai:read
  • Canonical address: POST /api/v1/actions/ai.record_skill_run

Input

FieldTypeRequiredNotes
skillIdstringyesSkill · max 64
skillNamestringName · max 200
versionIduuidVersion · id of ai_skill_version
modestring (enum)yesMode · Allowed values: load, exec, eval, compiled
okbooleanyesSucceeded
durationMsnumberDuration (ms) · min 0
costUsdnumberCost (USD) · min 0
errorstringError · 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

POSThttps://app.getera.io/api/v1/ai_providers/{id}/actions/record_subscription_state
API key or OAuth token · ai:read
  • Canonical address: POST /api/v1/actions/ai.record_subscription_state

Input

FieldTypeRequiredNotes
iduuidyesFilled from the path {id} · Subscription · id of ai_provider
statusstring (enum)yesStatus · Allowed values: unchecked, healthy, failing, connecting, limited, relogin, offline, not_eligible
detailstringDetail · max 2000
resetsAtstringLimit resets at · max 40
accountLabelstringAccount · max 160
usedbooleanWas used

Preconditions

The action is refused with 409 and one of these codes:

CodeRefused when
not_foundThe subscription must be connected in this workspace.
not_ownerOnly 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"}'
Response
{
  "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"
tools/call
{
  "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

POSThttps://app.getera.io/api/v1/ai_template_installs/actions/record_template_install
API key or OAuth token · ai:write
  • Canonical address: POST /api/v1/actions/ai.record_template_install

Input

FieldTypeRequiredNotes
templateIdstringyesTemplate · max 120
templateNamestringyesTemplate name · max 200
kindstring (enum)yesKind · Allowed values: agent, skill, workflow
instanceIdstringyesInstalled as · max 120
requiredAppsobject / arrayApps 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"}'
Response
{
  "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"
tools/call
{
  "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

POSThttps://app.getera.io/api/v1/ai_conversations/{id}/actions/record_turn
API key or OAuth token · ai:write
  • Canonical address: POST /api/v1/actions/ai.record_turn

Input

FieldTypeRequiredNotes
conversationIduuidyesFilled from the path {id} · Conversation · id of ai_conversation
rolestring (enum)yesFrom · Allowed values: user, assistant, system
contentstringText · max 200000
toolCallsobject / arrayWhat 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:

CodeRefused when
not_foundThe conversation must exist in this workspace.
bad_tool_callsThe 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"}'
Response
{
  "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"
tools/call
{
  "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

Run by Era itself (machine-only). Listed so the reference is complete; an API key or a token is refused (403 machine_only).
POSThttps://app.getera.io/api/v1/ai_usages/actions/record_usage
API key or OAuth token · ai:read
  • Canonical address: POST /api/v1/actions/ai.record_usage

Input

FieldTypeRequiredNotes
sourcestring (enum)yesSource · Allowed values: agent_run, console, era, skill_eval
refstringReference · max 120
agentIduuidAgent · id of ai_agent
runIduuidRun · id of ai_run
conversationIduuidConversation · id of ai_conversation
modelstringModel · max 120
modelCallsnumberModel calls · min 0
promptTokensnumberPrompt tokens · min 0
completionTokensnumberCompletion tokens · min 0
cacheReadTokensnumberCache read tokens · min 0
cacheWriteTokensnumberCache write tokens · min 0
toolCallsnumberTool calls · min 0
toolResultCharsnumberTool result characters · min 0
costUsdnumberCost (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

POSThttps://app.getera.io/api/v1/brain_fact_reviews/actions/refile_brain_fact
API key or OAuth token · ai:write
  • Canonical address: POST /api/v1/actions/ai.refile_brain_fact

Input

FieldTypeRequiredNotes
memoryIduuidyesWhat Era learned
kindstringCategory · fact · preference · rule · procedure · max 20
audiencestringFor · person · workspace · module · max 20
moduleCodestringModule · max 64
expiresAtdate-timeUntil
noExpirybooleanNo end date

Preconditions

The action is refused with 409 and one of these codes:

CodeRefused when
fact_not_foundEra must know it, and it must not be someone else’s private fact.
not_currentOnly what Era knows now can be changed.
bad_memory_kindA memory is a fact, a preference, a rule or a procedure.
module_requiredA memory for one module names a module that exists.
already_expiredAn end date is in the future.
unchangedA 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"}'
Response
{
  "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"
tools/call
{
  "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

Run by Era itself (machine-only). Listed so the reference is complete; an API key or a token is refused (403 machine_only).
POSThttps://app.getera.io/api/v1/ai_tasks/{id}/actions/remind_task
API key or OAuth token · ai:handle
  • Canonical address: POST /api/v1/actions/ai.remind_task

Input

FieldTypeRequiredNotes
iduuidyesFilled from the path {id} · Task · id of ai_task

Preconditions

The action is refused with 409 and one of these codes:

CodeRefused when
not_foundThe task must exist in this workspace.
not_dueOnly an open task due within a day, or past due, is reminded.
already_remindedEach 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

POSThttps://app.getera.io/api/v1/ai_providers/{id}/actions/remove_provider
API key or OAuth token · ai:manage
  • Canonical address: POST /api/v1/actions/ai.remove_provider

Input

FieldTypeRequiredNotes
iduuidyesFilled from the path {id} · Provider · id of ai_provider

Preconditions

The action is refused with 409 and one of these codes:

CodeRefused when
not_foundThe 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 '{}'
Response
{
  "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
tools/call
{
  "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

POSThttps://app.getera.io/api/v1/ai_tasks/{id}/actions/reopen_task
API key or OAuth token · ai:write
  • Canonical address: POST /api/v1/actions/ai.reopen_task

Input

FieldTypeRequiredNotes
iduuidyesFilled from the path {id} · Task · id of ai_task

Preconditions

The action is refused with 409 and one of these codes:

CodeRefused when
not_foundThe 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 '{}'
Response
{
  "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
tools/call
{
  "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

POSThttps://app.getera.io/api/v1/brain_erasures/actions/resolve_erasure_candidate
API key or OAuth token · ai:manage
  • Canonical address: POST /api/v1/actions/ai.resolve_erasure_candidate

Input

FieldTypeRequiredNotes
iduuidyesPossible match
decisionstring (enum)yesDecision · Allowed values: erase, dismiss

Preconditions

The action is refused with 409 and one of these codes:

CodeRefused when
candidate_not_foundThe possible match must exist in this workspace.
already_resolvedA 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"}'
Response
{
  "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"
tools/call
{
  "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

POSThttps://app.getera.io/api/v1/actions/ai.resume_computer_session
API key or OAuth token · ai:handle

Input

FieldTypeRequiredNotes
iduuidyesSession · id of computer_session

Preconditions

The action is refused with 409 and one of these codes:

CodeRefused when
not_foundThe session must exist in this workspace.
not_pausedOnly 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"}'
Response
{
  "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"
tools/call
{
  "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

POSThttps://app.getera.io/api/v1/brain_fact_reviews/actions/review_brain_fact
API key or OAuth token · ai:write
  • Canonical address: POST /api/v1/actions/ai.review_brain_fact

Input

FieldTypeRequiredNotes
memoryIduuidyesWhat Era learned
decisionstring (enum)yesDecision · Allowed values: correct, forget, keep_private, confirm, move
correctedTextstringWhat is right · max 4000
knowledgeBaseIduuidMove to

Preconditions

The action is refused with 409 and one of these codes:

CodeRefused when
fact_not_foundEra must know it, and it must not be someone else’s private fact.
not_currentOnly what Era knows now can be changed.
empty_correctionA correction says what is right.
unchangedA correction changes the wording; a move changes the space.
knowledge_base_not_in_brainA 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"}'
Response
{
  "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"
tools/call
{
  "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

POSThttps://app.getera.io/api/v1/actions/ai.run_agent
API key or OAuth token · ai:handle

Input

FieldTypeRequiredNotes
agentIduuidyesAgent · id of ai_agent
promptstringWhat to do · max 20000

Preconditions

The action is refused with 409 and one of these codes:

CodeRefused when
not_foundThe agent must exist in this workspace.
agent_disabledA switched-off agent cannot be run.
budget_exceededThe 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"}'
Response
{
  "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"
tools/call
{
  "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

POSThttps://app.getera.io/api/v1/computer_folders/actions/save_computer_folder
API key or OAuth token · ai:handle
  • Canonical address: POST /api/v1/actions/ai.save_computer_folder

Input

FieldTypeRequiredNotes
namestringyesName · max 80
pathstringyesFull path · max 1000
aliasesobject / arrayOther names · Other ways you say it: ["era reposu", "era projesi"].

Preconditions

The action is refused with 409 and one of these codes:

CodeRefused when
computer_access_requiredOnly the workspace owner, or a member given computer access, can reach a computer.
invalid_folderA folder needs a name and a full path.
invalid_aliasesOther 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"}'
Response
{
  "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"
tools/call
{
  "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

POSThttps://app.getera.io/api/v1/computer_policies/actions/save_computer_policy
API key or OAuth token · ai:manage
  • Canonical address: POST /api/v1/actions/ai.save_computer_policy

Input

FieldTypeRequiredNotes
allowDomainsobject / arrayOnly these sites
denyDomainsobject / arrayNever these sites
denyAppsobject / arrayNever these apps
approvalModestring (enum)Ask before · Allowed values: risky, every_action, never
maxStepsnumberMost steps per task · min 1 · max 200
maxMinutesnumberLongest task (minutes) · min 1 · max 1440
monthlyCloudHoursnumberCloud hours per person per month · min 0 · max 744
defaultModelstringDefault model · max 200
providerstring (enum)Cloud computer provider · Allowed values: ``, boxd, e2b, digitalocean

Preconditions

The action is refused with 409 and one of these codes:

CodeRefused when
invalid_domainSites are written like example.com or *.example.com.
unknown_providerThe 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":{}}'
Response
{
  "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":{}}'
tools/call
{
  "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

POSThttps://app.getera.io/api/v1/era_action_caps/actions/set_action_cap
API key or OAuth token · ai:write
  • Canonical address: POST /api/v1/actions/ai.set_action_cap

Input

FieldTypeRequiredNotes
kindstringyesWhat · max 80
dailyLimitnumberyesTimes a day · min 0 · max 1000

Preconditions

The action is refused with 409 and one of these codes:

CodeRefused when
not_cappableOnly 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}'
Response
{
  "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
tools/call
{
  "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

POSThttps://app.getera.io/api/v1/ai_agents/{id}/actions/set_agent_enabled
API key or OAuth token · ai:manage
  • Canonical address: POST /api/v1/actions/ai.set_agent_enabled

Input

FieldTypeRequiredNotes
iduuidyesFilled from the path {id} · Agent · id of ai_agent
enabledbooleanyesRunning

Preconditions

The action is refused with 409 and one of these codes:

CodeRefused when
not_foundThe agent must exist in this workspace.
no_instructionsAn 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}'
Response
{
  "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
tools/call
{
  "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

POSThttps://app.getera.io/api/v1/brain_insights/actions/set_brain_insight_status
API key or OAuth token · ai:write
  • Canonical address: POST /api/v1/actions/ai.set_brain_insight_status

Input

FieldTypeRequiredNotes
iduuidyesInsight
statusstringyesStatus · new · seen · done · dismissed · max 20

Preconditions

The action is refused with 409 and one of these codes:

CodeRefused when
bad_statusThe status is new, seen, done or dismissed.
insight_not_foundThe 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"}'
Response
{
  "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"
tools/call
{
  "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

POSThttps://app.getera.io/api/v1/ai_budgets/actions/set_budget
API key or OAuth token · ai:manage
  • Canonical address: POST /api/v1/actions/ai.set_budget

Input

FieldTypeRequiredNotes
agentIduuidAgent · Empty = the whole workspace. · id of ai_agent
dailyUsdnumber (money)Daily cap (USD) · min 0
monthlyUsdnumber (money)Monthly cap (USD) · min 0
alertPctnumberAlert at (%) · min 1 · max 100

Preconditions

The action is refused with 409 and one of these codes:

CodeRefused when
unknown_agentThe 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"}'
Response
{
  "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"
tools/call
{
  "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

POSThttps://app.getera.io/api/v1/era_chat_members/actions/set_chat_member
API key or OAuth token · ai:write
  • Canonical address: POST /api/v1/actions/ai.set_chat_member

Input

FieldTypeRequiredNotes
conversationIduuidyesChat
userIduuidyesPerson
accessstring (enum)yesAccess · Allowed values: view, act, none
canApprovebooleanCan approve

Preconditions

The action is refused with 409 and one of these codes:

CodeRefused when
not_foundThe chat must exist in this workspace.
not_ownerOnly the person who started the chat (or an admin) can share it.
owner_is_memberThe person who started the chat cannot be added to it.
not_a_memberOnly active members of the workspace can be added.
approve_needs_actCan approve requires can act.
not_an_approverCan 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"}'
Response
{
  "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"
tools/call
{
  "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)

POSThttps://app.getera.io/api/v1/ai_providers/{id}/actions/set_connection_share
API key or OAuth token · ai:write
  • Canonical address: POST /api/v1/actions/ai.set_connection_share

Input

FieldTypeRequiredNotes
iduuidyesFilled from the path {id} · Connection · id of ai_provider
scopestring (enum)yesWho may use it · Allowed values: me, team, workspace
teamIduuidTeam

Preconditions

The action is refused with 409 and one of these codes:

CodeRefused when
not_foundThe connection must exist here.
not_ownerIts owner, or a manager for a workspace-level one.
team_requiredSharing 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"}'
Response
{
  "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"
tools/call
{
  "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

POSThttps://app.getera.io/api/v1/ai_model_policies/actions/set_model_policy
API key or OAuth token · ai:manage
  • Canonical address: POST /api/v1/actions/ai.set_model_policy

Input

FieldTypeRequiredNotes
taskClassstring (enum)yesKind of work · Allowed values: default, chat, agent, classify, summarize, extract, build, research
modelstringModel · max 120
fallbackModelstringFallback 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"}'
Response
{
  "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"
tools/call
{
  "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

POSThttps://app.getera.io/api/v1/ai_providers/actions/set_provider
API key or OAuth token · ai:manage
  • Canonical address: POST /api/v1/actions/ai.set_provider

Input

FieldTypeRequiredNotes
providerstring (enum)yesProvider · 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
secretRefstringVault key · vault:<id> from apps.store_secret · max 64
keyHintstringKey (masked) · max 40
baseUrlstringBase URL · max 300
labelstringLabel · max 120
makeDefaultbooleanUse by default
personalbooleanOnly for me · My own key: only my requests use it.

Preconditions

The action is refused with 409 and one of these codes:

CodeRefused when
bad_secret_refThe key must be a vault secret of this workspace.
subscription_providerA subscription (ChatGPT, Claude, Antigravity plan) is connected by signing in, not with a key.
base_url_requiredAzure 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"}'
Response
{
  "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"
tools/call
{
  "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

POSThttps://app.getera.io/api/v1/ai_skill_releases/actions/set_skill_policy
API key or OAuth token · ai:manage
  • Canonical address: POST /api/v1/actions/ai.set_skill_policy

Input

FieldTypeRequiredNotes
skillIdstringyesSkill · max 64
publishedbooleanPublished
allowedIntegrationsobject / arrayApps it may call · ["gmail", "crm"]
allowedDomainsobject / arrayHosts it may reach · ["api.example.com", "*.example.org"]
secretsobject / arraySecrets it may read · [{ "name": "API_KEY", "ref": "vault:<id>" }]

Preconditions

The action is refused with 409 and one of these codes:

CodeRefused when
bad_policyApps, hosts and secret names must be well-formed lists.
bad_secret_refA 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"}'
Response
{
  "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"
tools/call
{
  "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

POSThttps://app.getera.io/api/v1/ai_skill_releases/actions/set_skill_release
API key or OAuth token · ai:manage
  • Canonical address: POST /api/v1/actions/ai.set_skill_release

Input

FieldTypeRequiredNotes
skillIdstringyesSkill · max 64
pausedbooleanPaused
sourceTemplatestringTemplate · max 120
sourceVersionstringTemplate 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"}'
Response
{
  "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"
tools/call
{
  "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

POSThttps://app.getera.io/api/v1/ai_source_choices/actions/set_source_choice
API key or OAuth token · ai:write
  • Canonical address: POST /api/v1/actions/ai.set_source_choice

Input

FieldTypeRequiredNotes
subjectTypestring (enum)yesFor · Allowed values: chat, agent, workflow, brain, voice_agent, creative, computer
subjectIdstringyesWhich one · max 120
modestring (enum)AI source · Allowed values: auto, byok, byos, connection
connectionIduuidConnection · id of ai_provider
modelstringModel · max 160
allowSharedbooleanA colleague’s shared connection
allowByokbooleanCompany keys
whenOfflinestring (enum)If the computer is off · Allowed values: wait, fallback

Preconditions

The action is refused with 409 and one of these codes:

CodeRefused when
bad_subjectAn Era, a workflow, a brain, a voice agent, creative, computer or chat.
not_ownerA person’s chat default is set by that person.
connection_not_usableOnly 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"}'
Response
{
  "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"
tools/call
{
  "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

POSThttps://app.getera.io/api/v1/ai_providers/{id}/actions/set_subscription_use
API key or OAuth token · ai:write
  • Canonical address: POST /api/v1/actions/ai.set_subscription_use

Input

FieldTypeRequiredNotes
iduuidyesFilled from the path {id} · Subscription · id of ai_provider
chatbooleanEra chat
agentsbooleanMy Eras
workflowsbooleanWorkflows
computerbooleanComputer
brainbooleanBrain
embeddingsbooleanSearch memory
creativebooleanCreative studio
voicebooleanVoice

Preconditions

The action is refused with 409 and one of these codes:

CodeRefused when
not_foundThe subscription must be connected in this workspace.
not_ownerOnly 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}'
Response
{
  "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
tools/call
{
  "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)

POSThttps://app.getera.io/api/v1/era_chat_shares/actions/share_chat
API key or OAuth token · ai:write
  • Canonical address: POST /api/v1/actions/ai.share_chat

Input

FieldTypeRequiredNotes
conversationIduuidyesChat
visibilitystring (enum)Who sees it · Allowed values: private, workspace
linkstring (enum)Read-only link · Allowed values: keep, new, off
linkExpiresAtdate-timeLink expires

Preconditions

The action is refused with 409 and one of these codes:

CodeRefused when
not_foundThe chat must exist in this workspace.
not_ownerOnly the person who started the chat (or an admin) can share it.
bad_expiryA 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"}'
Response
{
  "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"
tools/call
{
  "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

POSThttps://app.getera.io/api/v1/ai_skill_versions/actions/snapshot_skill
API key or OAuth token · ai:write
  • Canonical address: POST /api/v1/actions/ai.snapshot_skill

Input

FieldTypeRequiredNotes
skillIdstringyesSkill · max 64
definitionobject / arrayyesDefinition · { kind, content, code, language, inputSchema, enrichOp, enrichConfig, description }
notestringNote · max 2000

Preconditions

The action is refused with 409 and one of these codes:

CodeRefused when
bad_definitionThe 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":{}}'
Response
{
  "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":{}}'
tools/call
{
  "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

POSThttps://app.getera.io/api/v1/computer_machines/actions/start_computer
API key or OAuth token · ai:handle
  • 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:

CodeRefused when
no_computerYou need a cloud computer first.
already_runningIt is already on.
computer_access_requiredOnly the workspace owner, or a member given computer access, can reach a computer.
hours_used_upThe 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 '{}'
Response
{
  "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
tools/call
{
  "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

POSThttps://app.getera.io/api/v1/actions/ai.start_computer_session
API key or OAuth token · ai:handle

Input

FieldTypeRequiredNotes
titlestringName · max 200
objectivestringWhat should it do? · max 4000
kindstring (enum)Kind · Allowed values: browser, desktop
targetstring (enum)Where · Allowed values: server, cloud, device
startUrlstringStart page · max 2000
modelstringModel · max 200
maxStepsnumberMost steps · min 1 · max 200
deviceIdstringDevice · max 100
agentIduuidAgent
sourcestring (enum)Asked by · Allowed values: person, era, workflow, agent
sourceRefstringSource reference · max 300

Preconditions

The action is refused with 409 and one of these codes:

CodeRefused when
empty_titleA task needs a clear purpose.
blocked_start_urlThe start page must be allowed by the workspace computer rules.
no_cloud_computerA cloud task needs the person’s cloud computer.
no_deviceA task on your own PC must name the device.
too_many_runningAt most three computer tasks run at once in a workspace.
computer_access_requiredOnly 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"}'
Response
{
  "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"
tools/call
{
  "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

POSThttps://app.getera.io/api/v1/ai_conversations/actions/start_conversation
API key or OAuth token · ai:write
  • Canonical address: POST /api/v1/actions/ai.start_conversation

Input

FieldTypeRequiredNotes
titlestringTitle · max 200
agentIduuidAgent · id of ai_agent

Preconditions

The action is refused with 409 and one of these codes:

CodeRefused when
unknown_agentThe 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"}'
Response
{
  "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"
tools/call
{
  "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

POSThttps://app.getera.io/api/v1/actions/ai.steer_computer_session
API key or OAuth token · ai:handle

Input

FieldTypeRequiredNotes
iduuidyesSession · id of computer_session
textstringyesMessage · max 4000

Preconditions

The action is refused with 409 and one of these codes:

CodeRefused when
not_foundThe session must exist in this workspace.
not_runningOnly a task that is still running takes new instructions.
empty_messageThe 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"}'
Response
{
  "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"
tools/call
{
  "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

POSThttps://app.getera.io/api/v1/actions/ai.stop_all_computer_sessions
API key or OAuth token · ai:handle

Input

This action takes no input.

Preconditions

The action is refused with 409 and one of these codes:

CodeRefused when
nothing_runningSomething 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 '{}'
Response
{
  "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
tools/call
{
  "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

POSThttps://app.getera.io/api/v1/actions/ai.stop_computer_session
API key or OAuth token · ai:handle

Input

FieldTypeRequiredNotes
iduuidyesSession · id of computer_session

Preconditions

The action is refused with 409 and one of these codes:

CodeRefused when
not_foundThe session must exist in this workspace.
already_stoppedA 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"}'
Response
{
  "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"
tools/call
{
  "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

POSThttps://app.getera.io/api/v1/brain_bindings/actions/unbind_brain
API key or OAuth token · ai:manage
  • Canonical address: POST /api/v1/actions/ai.unbind_brain

Input

FieldTypeRequiredNotes
subjectTypestringyesFor · agent · workflow · voice_agent · era_chat · meeting · team · role · max 20
subjectIdstringyesWhich one · max 120
brainIduuidyesBrain

Preconditions

The action is refused with 409 and one of these codes:

CodeRefused when
bad_subjectIt names an Era, workflow, voice agent, meeting or Era chat.
brain_not_foundThe brain must exist in this workspace.
not_boundThe 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"}'
Response
{
  "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"
tools/call
{
  "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

POSThttps://app.getera.io/api/v1/ai_skill_releases/actions/uninstall_skill
API key or OAuth token · ai:delete
  • Canonical address: POST /api/v1/actions/ai.uninstall_skill

Input

FieldTypeRequiredNotes
skillIdstringyesSkill · 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"}'
Response
{
  "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"
tools/call
{
  "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

POSThttps://app.getera.io/api/v1/ai_agents/{id}/actions/update_agent
API key or OAuth token · ai:manage
  • Canonical address: POST /api/v1/actions/ai.update_agent

Input

FieldTypeRequiredNotes
iduuidyesFilled from the path {id} · Agent · id of ai_agent
namestringName · max 160
instructionsstringInstructions · max 20000
descriptionstringDescription · max 2000
modelstringModel · max 120
allowedModulesobject / arrayLimited to these modules · A list of module codes. Empty means every module its author can already use.
wakesOnobject / arrayWakes up on · A list of event names — crm.lead_won, crm.* or *. Empty means it only runs when asked.
maxStepsnumberTool calls per run · min 1 · max 40

Preconditions

The action is refused with 409 and one of these codes:

CodeRefused when
not_foundThe agent must exist in this workspace.
empty_nameAn agent needs a name.
bad_modulesIt may only be limited to modules this platform registers.
bad_triggerA 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"}'
Response
{
  "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"
tools/call
{
  "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

POSThttps://app.getera.io/api/v1/brains/actions/update_brain
API key or OAuth token · ai:manage
  • Canonical address: POST /api/v1/actions/ai.update_brain

Input

FieldTypeRequiredNotes
iduuidyesBrain
namestringName · max 80
descriptionstringWhat it is for · max 500
shortTtlHoursnumberShort memory lasts (hours) · min 1 · max 720
embeddingSpacestring (enum)Where it understands meaning · Allowed values: bge-m3-1024, e5-small-384
learnFromobject / arrayLearns from
rememberThresholdnumberHow sure before remembering · min 0 · max 1
askBeforeRememberingbooleanAsk before remembering what it hears in chats

Preconditions

The action is refused with 409 and one of these codes:

CodeRefused when
brain_not_foundThe brain must exist in this workspace.
not_your_brainSomeone else’s personal brain is theirs to change.
archivedAn archived brain does not change.
empty_nameA brain needs a name.
name_takenBrain names are unique in a workspace.
space_lockedWhere a brain understands meaning is fixed once it knows something.
invalid_learn_fromWhat 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"}'
Response
{
  "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"
tools/call
{
  "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

POSThttps://app.getera.io/api/v1/knowledge_bases/actions/update_knowledge_base
API key or OAuth token · ai:manage
  • Canonical address: POST /api/v1/actions/ai.update_knowledge_base

Input

FieldTypeRequiredNotes
iduuidyesSpace
namestringName · max 80
descriptionstringWhat goes here · max 500
makeDefaultbooleanMake it the main space

Preconditions

The action is refused with 409 and one of these codes:

CodeRefused when
knowledge_base_not_foundThe space must exist in this workspace.
archivedAn archived space does not change.
empty_nameA space needs a name.
name_takenSpace 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"}'
Response
{
  "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"
tools/call
{
  "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

POSThttps://app.getera.io/api/v1/ai_tasks/{id}/actions/update_task
API key or OAuth token · ai:write
  • Canonical address: POST /api/v1/actions/ai.update_task

Input

FieldTypeRequiredNotes
iduuidyesFilled from the path {id} · Task · id of ai_task
titlestringTitle · max 300
descriptionstringDetails · max 10000
listNamestringList · max 80
prioritystring (enum)Priority · Allowed values: low, normal, high, urgent
dueAtdate-timeDue
recurrencestring (enum)Repeats · Allowed values: none, daily, weekly, monthly
statusstring (enum)Status · Allowed values: open, in_progress, cancelled

Preconditions

The action is refused with 409 and one of these codes:

CodeRefused when
not_foundThe task must exist in this workspace.
empty_titleA 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"}'
Response
{
  "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"
tools/call
{
  "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

POSThttps://app.getera.io/api/v1/era_action_caps/actions/use_action_cap
API key or OAuth token · ai:read
  • Canonical address: POST /api/v1/actions/ai.use_action_cap

Input

FieldTypeRequiredNotes
kindstringyesWhat · max 80
opstring (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"}'
Response
{
  "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"
tools/call
{
  "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_agents
  • GET /api/v1/ai_agents/{id}
ColumnTypeNullableAllowed valuesReferences
idstring (uuid) · uuid
organization_idstring (uuid) · uuidorganization
workspace_idstring (uuid) · uuidworkspace
namestring · text
descriptionstring · textyes
instructionsstring · text
modelstring · text
allowed_modulesstring[] · text[]
wakes_onstring[] · text[]
max_stepsinteger · int4
is_enabledboolean · bool
acts_as_user_idstring (uuid) · uuidapp_user
engine_agent_idstring · textyes
last_run_atstring (date-time) · timestamptzyes
run_countinteger · int4
failure_countinteger · int4
created_atstring (date-time) · timestamptz
updated_atstring (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_budgets
  • GET /api/v1/ai_budgets/{id}
ColumnTypeNullableAllowed valuesReferences
idstring (uuid) · uuid
organization_idstring (uuid) · uuidorganization
workspace_idstring (uuid) · uuidworkspace
agent_idstring (uuid) · uuidyesai_agent
daily_usdstring (decimal) · numericyes
monthly_usdstring (decimal) · numericyes
alert_pctinteger · int4
last_alert_keystring · textyes
updated_atstring (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_conversations
  • GET /api/v1/ai_conversations/{id}
ColumnTypeNullableAllowed valuesReferences
idstring (uuid) · uuid
organization_idstring (uuid) · uuidorganization
workspace_idstring (uuid) · uuidworkspace
agent_idstring (uuid) · uuidyesai_agent
created_bystring (uuid) · uuidapp_user
titlestring · textyes
message_countinteger · int4
last_message_atstring (date-time) · timestamptzyes
created_atstring (date-time) · timestamptz
updated_atstring (date-time) · timestamptz
deleted_atstring (date-time) · timestamptzyes

Primary key: id

AiMessage

Table ai_message · Resource ai_messages

  • GET /api/v1/ai_messages
  • GET /api/v1/ai_messages/{id}
ColumnTypeNullableAllowed valuesReferences
idstring (uuid) · uuid
organization_idstring (uuid) · uuidorganization
workspace_idstring (uuid) · uuidworkspace
conversation_idstring (uuid) · uuidai_conversation
positioninteger · int4
rolestring · textuser, assistant, system
contentstring · text
tool_callsobject · jsonb
created_atstring (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_policies
  • GET /api/v1/ai_model_policies/{id}
ColumnTypeNullableAllowed valuesReferences
idstring (uuid) · uuid
organization_idstring (uuid) · uuidorganization
workspace_idstring (uuid) · uuidworkspace
task_classstring · textdefault, chat, agent, classify, summarize, extract, build, research
modelstring · text
fallback_modelstring · textyes
updated_atstring (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_providers
  • GET /api/v1/ai_providers/{id}
ColumnTypeNullableAllowed valuesReferences
idstring (uuid) · uuid
organization_idstring (uuid) · uuidorganization
workspace_idstring (uuid) · uuidworkspace
providerstring · text
labelstring · textyes
key_hintstring · textyes
base_urlstring · textyes
is_defaultboolean · bool
statusstring · textunchecked, healthy, failing, connecting, limited, relogin, offline, not_eligible
last_checked_atstring (date-time) · timestamptzyes
last_errorstring · textyes
created_bystring (uuid) · uuidyesapp_user
created_atstring (date-time) · timestamptz
updated_atstring (date-time) · timestamptz
key_set_atstring (date-time) · timestamptzyes
consecutive_failuresinteger · int4
last_latency_msinteger · int4yes
rotation_reminded_atstring (date-time) · timestamptzyes
connection_kindstring · textapi_key, subscription
owner_user_idstring (uuid) · uuidyesapp_user
executionstring · textremote, local_device, cloud_computer
device_idstring · textyes
capabilitiesstring[] · text[]
account_labelstring · textyes
limit_resets_atstring (date-time) · timestamptzyes
use_forobject · jsonb
last_used_atstring (date-time) · timestamptzyes
metaobject · jsonb
share_scopestring · text
share_team_idstring (uuid) · uuidyesteam
plan_limitsobject · jsonbyes

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_runs
  • GET /api/v1/ai_runs/{id}
ColumnTypeNullableAllowed valuesReferences
idstring (uuid) · uuid
organization_idstring (uuid) · uuidorganization
workspace_idstring (uuid) · uuidworkspace
agent_idstring (uuid) · uuidai_agent
event_idstring (int64) · int8yes
event_namestring · textyes
conversation_idstring (uuid) · uuidyesai_conversation
statusstring · textrunning, succeeded, failed, skipped, refused
started_atstring (date-time) · timestamptz
finished_atstring (date-time) · timestamptzyes
stepsobject · jsonb
errorstring · textyes
modelstring · textyes
model_callsinteger · int4
cost_usdstring (decimal) · numeric
repairsinteger · int4
answerstring · textyes
touched_recordsobject · jsonb
approval_idsstring[] · uuid[]

Primary key: id

AiSkillRelease

Table ai_skill_release · Resource ai_skill_releases

  • GET /api/v1/ai_skill_releases
  • GET /api/v1/ai_skill_releases/{id}
ColumnTypeNullableAllowed valuesReferences
idstring (uuid) · uuid
organization_idstring (uuid) · uuidorganization
workspace_idstring (uuid) · uuidworkspace
skill_idstring · text
pausedboolean · bool
source_templatestring · textyes
source_versionstring · textyes
installed_atstring (date-time) · timestamptzyes
updated_atstring (date-time) · timestamptz
publishedboolean · bool
allowed_integrationsstring[] · text[]
allowed_domainsstring[] · text[]

Primary key: id

Unique: workspace_id, skill_id

AiSkillRun

Table ai_skill_run · Resource ai_skill_runs

  • GET /api/v1/ai_skill_runs
  • GET /api/v1/ai_skill_runs/{id}
ColumnTypeNullableAllowed valuesReferences
idstring (uuid) · uuid
organization_idstring (uuid) · uuidorganization
workspace_idstring (uuid) · uuidworkspace
skill_idstring · text
skill_namestring · textyes
version_idstring (uuid) · uuidyesai_skill_version
modestring · textload, exec, eval, compiled
statusstring · textok, error
duration_msinteger · int4yes
cost_usdstring (decimal) · numeric
errorstring · textyes
created_atstring (date-time) · timestamptz

Primary key: id

AiSkillVersion

Table ai_skill_version · Resource ai_skill_versions

  • GET /api/v1/ai_skill_versions
  • GET /api/v1/ai_skill_versions/{id}
ColumnTypeNullableAllowed valuesReferences
idstring (uuid) · uuid
organization_idstring (uuid) · uuidorganization
workspace_idstring (uuid) · uuidworkspace
skill_idstring · text
versioninteger · int4
definitionobject · jsonb
notestring · textyes
statusstring · textdraft, active, retired
eval_scorestring (decimal) · numericyes
eval_passedinteger · int4yes
eval_totalinteger · int4yes
eval_notesstring · textyes
evaluated_atstring (date-time) · timestamptzyes
was_activeboolean · bool
created_bystring (uuid) · uuidyesapp_user
created_atstring (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_choices
  • GET /api/v1/ai_source_choices/{id}
ColumnTypeNullableAllowed valuesReferences
idstring (uuid) · uuid
organization_idstring (uuid) · uuidorganization
workspace_idstring (uuid) · uuidworkspace
subject_typestring · textchat, agent, workflow, brain, voice_agent, creative, computer
subject_idstring · text
connection_idstring (uuid) · uuidyesai_provider
modelstring · textyes
allow_sharedboolean · bool
allow_byokboolean · bool
when_offlinestring · textwait, fallback
created_bystring (uuid) · uuidyesapp_user
created_atstring (date-time) · timestamptz
updated_atstring (date-time) · timestamptz
source_modestring · textauto, byok, byos, connection

Primary key: id

Unique: workspace_id, subject_type, subject_id

AiTask

Table ai_task · Resource ai_tasks

  • GET /api/v1/ai_tasks
  • GET /api/v1/ai_tasks/{id}
ColumnTypeNullableAllowed valuesReferences
idstring (uuid) · uuid
organization_idstring (uuid) · uuidorganization
workspace_idstring (uuid) · uuidworkspace
titlestring · text
descriptionstring · textyes
list_namestring · text
statusstring · textopen, in_progress, done, cancelled
prioritystring · textlow, normal, high, urgent
due_atstring (date-time) · timestamptzyes
assignee_user_idstring (uuid) · uuidyesapp_user
assignee_agent_idstring (uuid) · uuidyesai_agent
recurrencestring · textnone, daily, weekly, monthly
recurrence_ofstring (uuid) · uuidyesai_task
handoffsobject · jsonb
created_bystring (uuid) · uuidapp_user
completed_atstring (date-time) · timestamptzyes
created_atstring (date-time) · timestamptz
updated_atstring (date-time) · timestamptz
deleted_atstring (date-time) · timestamptzyes
record_typestring · textyes
record_idstring (uuid) · uuidyes
due_reminded_atstring (date-time) · timestamptzyes
overdue_reminded_atstring (date-time) · timestamptzyes

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_installs
  • GET /api/v1/ai_template_installs/{id}
ColumnTypeNullableAllowed valuesReferences
idstring (uuid) · uuid
organization_idstring (uuid) · uuidorganization
workspace_idstring (uuid) · uuidworkspace
template_idstring · text
template_namestring · text
kindstring · textagent, skill, workflow
instance_idstring · text
required_appsstring[] · text[]
installed_bystring (uuid) · uuidyesapp_user
created_atstring (date-time) · timestamptz

Primary key: id

Unique: workspace_id, kind, instance_id

AiUsage

Table ai_usage · Resource ai_usages

  • GET /api/v1/ai_usages
  • GET /api/v1/ai_usages/{id}
ColumnTypeNullableAllowed valuesReferences
idstring (uuid) · uuid
organization_idstring (uuid) · uuidorganization
workspace_idstring (uuid) · uuidworkspace
agent_idstring (uuid) · uuidyesai_agent
run_idstring (uuid) · uuidyesai_run
conversation_idstring (uuid) · uuidyesai_conversation
sourcestring · textagent_run, console, era, skill_eval, router
refstring · textyes
modelstring · textyes
model_callsinteger · int4
tool_callsinteger · int4
tool_result_charsinteger · int4
cost_usdstring (decimal) · numeric
created_atstring (date-time) · timestamptz
surfacestring · textyes
capabilitystring · textyes
source_kindstring · textyes
providerstring · textyes
unitsstring (decimal) · numericyes
unitstring · textyes
user_idstring (uuid) · uuidyes
connection_idstring (uuid) · uuidyesai_provider
latency_msinteger · int4yes
attemptsobject · jsonbyes
gateway_request_idstring · textyes

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_bindings
  • GET /api/v1/brain_bindings/{id}
ColumnTypeNullableAllowed valuesReferences
idstring (uuid) · uuid
organization_idstring (uuid) · uuidorganization
workspace_idstring (uuid) · uuidworkspace
subject_typestring · textagent, workflow, voice_agent, era_chat, meeting, team, role
subject_idstring · text
brain_idstring (uuid) · uuidbrain
knowledge_base_idsstring[] · uuid[]
accessstring · textread, read_write
created_bystring (uuid) · uuidyesapp_user
created_atstring (date-time) · timestamptz
updated_atstring (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_erasures
  • GET /api/v1/brain_erasures/{id}
ColumnTypeNullableAllowed valuesReferences
idstring (uuid) · uuid
organization_idstring (uuid) · uuidorganization
workspace_idstring (uuid) · uuidworkspace
kindstring · textfact, person
subject_labelstring · text
subject_refstring · textyes
privacy_request_idstring (uuid) · uuidyes
reasonstring · textyes
requested_onstring (date) · dateyes
countsobject · jsonb
erased_bystring (uuid) · uuidyesapp_user
created_atstring (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_reviews
  • GET /api/v1/brain_fact_reviews/{id}
ColumnTypeNullableAllowed valuesReferences
idstring (uuid) · uuid
organization_idstring (uuid) · uuidorganization
workspace_idstring (uuid) · uuidworkspace
memory_idstring (uuid) · uuid
decisionstring · textcorrect, forget, keep_private, confirm, move, refile
corrected_textstring · textyes
applied_memory_idstring (uuid) · uuidyes
reviewed_bystring (uuid) · uuidyesapp_user
created_atstring (date-time) · timestamptz
target_knowledge_base_idstring (uuid) · uuidyesknowledge_base
new_kindstring · textyes
new_audiencestring · textyes
new_module_codestring · textyes
new_expires_atstring (date-time) · timestamptzyes
clear_expiryboolean · 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_insights
  • GET /api/v1/brain_insights/{id}
ColumnTypeNullableAllowed valuesReferences
idstring (uuid) · uuid
organization_idstring (uuid) · uuidorganization
workspace_idstring (uuid) · uuidworkspace
brain_idstring (uuid) · uuidyesbrain
rolestring · textsales, marketing, finance, operations, support, management, general
titlestring · text
bodystring · text
severitystring · textinfo, opportunity, warning
sourcesobject · jsonb
reasoningstring · textyes
suggested_actionobject · jsonbyes
generated_byobject · jsonb
statusstring · textnew, seen, done, dismissed
dedupe_keystring · textyes
status_bystring (uuid) · uuidyesapp_user
created_atstring (date-time) · timestamptz
updated_atstring (date-time) · timestamptz
originstring · textlearning, outcome, era, person
kindstring · textyes

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/brains
  • GET /api/v1/brains/{id}
  • POST /api/v1/brains → ai.create_brain
ColumnTypeNullableAllowed valuesReferences
idstring (uuid) · uuid
organization_idstring (uuid) · uuidorganization
workspace_idstring (uuid) · uuidworkspace
namestring · text
descriptionstring · textyes
kindstring · textcompany, personal, team, era, voice, brand, custom
scopestring · textworkspace, team, era, voice_agent, person
scope_refstring (uuid) · uuidyes
memorystring · textlong, short
short_ttl_hoursinteger · int4yes
embedding_spacestring · textbge-m3-1024, e5-small-384
learn_fromobject · jsonb
remember_thresholdnumber · float4
is_defaultboolean · bool
archived_atstring (date-time) · timestamptzyes
created_bystring (uuid) · uuidyesapp_user
created_atstring (date-time) · timestamptz
updated_atstring (date-time) · timestamptz
ask_before_rememberingboolean · 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_folders
  • GET /api/v1/computer_folders/{id}
ColumnTypeNullableAllowed valuesReferences
idstring (uuid) · uuid
organization_idstring (uuid) · uuidorganization
workspace_idstring (uuid) · uuidworkspace
owner_user_idstring (uuid) · uuidapp_user
namestring · text
aliasesstring[] · text[]
pathstring · text
visibilitystring · textprivate, everyone
last_used_atstring (date-time) · timestamptzyes
created_atstring (date-time) · timestamptz
updated_atstring (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_machines
  • GET /api/v1/computer_machines/{id}
ColumnTypeNullableAllowed valuesReferences
idstring (uuid) · uuid
organization_idstring (uuid) · uuidorganization
workspace_idstring (uuid) · uuidworkspace
owner_user_idstring (uuid) · uuidapp_user
namestring · text
providerstring · text
external_idstring · textyes
statestring · textrequested, provisioning, running, pausing, paused, failed, deleting, deleted
resolution_winteger · int4
resolution_hinteger · int4
viewer_urlstring · textyes
last_errorstring · textyes
seconds_usedstring (int64) · int8
month_seconds_usedstring (int64) · int8
usage_monthstring · textyes
started_atstring (date-time) · timestamptzyes
paused_atstring (date-time) · timestamptzyes
deleted_atstring (date-time) · timestamptzyes
metadataobject · jsonb
created_atstring (date-time) · timestamptz
updated_atstring (date-time) · timestamptz

Primary key: id

ComputerPolicy

Table computer_policy · Resource computer_policies

  • GET /api/v1/computer_policies
  • GET /api/v1/computer_policies/{id}
ColumnTypeNullableAllowed valuesReferences
workspace_idstring (uuid) · uuidworkspace
organization_idstring (uuid) · uuidorganization
allow_domainsstring[] · text[]
deny_domainsstring[] · text[]
deny_appsstring[] · text[]
approval_modestring · textrisky, every_action, never
max_stepsinteger · int4
max_minutesinteger · int4
monthly_cloud_hoursstring (decimal) · numeric
default_modelstring · textyes
updated_bystring (uuid) · uuidyesapp_user
created_atstring (date-time) · timestamptz
updated_atstring (date-time) · timestamptz
providerstring · textyes

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_decisions
  • GET /api/v1/decide_decisions/{id}
ColumnTypeNullableAllowed valuesReferences
idstring (uuid) · uuid
organization_idstring (uuid) · uuidorganization
workspace_idstring (uuid) · uuidworkspace
question_keystring · text
questionobject · jsonb
focusobject · jsonbyes
answerobject · jsonb
confidencenumber · float4yes
providerstring · textyes
modelstring · textyes
needs_reviewboolean · bool
refstring · textyes
outcomestring · textyes
corrected_answerobject · jsonbyes
outcome_sourcestring · textyes
outcome_notestring · textyes
outcome_bystring (uuid) · uuidyesapp_user
outcome_atstring (date-time) · timestamptzyes
created_atstring (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_caps
  • GET /api/v1/era_action_caps/{id}
ColumnTypeNullableAllowed valuesReferences
idstring (uuid) · uuid
organization_idstring (uuid) · uuidorganization
workspace_idstring (uuid) · uuidworkspace
user_idstring (uuid) · uuidapp_user
kindstring · text
daily_limitinteger · int4
usedinteger · int4
used_onstring (date) · dateyes
created_atstring (date-time) · timestamptz
updated_atstring (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_members
  • GET /api/v1/era_chat_members/{id}
ColumnTypeNullableAllowed valuesReferences
idstring (uuid) · uuid
organization_idstring (uuid) · uuidorganization
workspace_idstring (uuid) · uuidworkspace
conversation_idstring (uuid) · uuidconversations
user_idstring (uuid) · uuidapp_user
accessstring · textview, act
can_approveboolean · bool
added_bystring (uuid) · uuidyesapp_user
last_seen_atstring (date-time) · timestamptzyes
created_atstring (date-time) · timestamptz
updated_atstring (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_seens
  • GET /api/v1/era_chat_seens/{id}
ColumnTypeNullableAllowed valuesReferences
idstring (uuid) · uuid
organization_idstring (uuid) · uuidorganization
workspace_idstring (uuid) · uuidworkspace
conversation_idstring (uuid) · uuidconversations
user_idstring (uuid) · uuidapp_user
seen_atstring (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_shares
  • GET /api/v1/era_chat_shares/{id}
ColumnTypeNullableAllowed valuesReferences
idstring (uuid) · uuid
organization_idstring (uuid) · uuidorganization
workspace_idstring (uuid) · uuidworkspace
conversation_idstring (uuid) · uuidconversations
created_bystring (uuid) · uuidapp_user
visibilitystring · textprivate, workspace
link_expires_atstring (date-time) · timestamptzyes
created_atstring (date-time) · timestamptz
updated_atstring (date-time) · timestamptz

Primary key: id

Unique: conversation_id · link_token_hash

EraLearning

Table era_learning · Resource era_learnings

  • GET /api/v1/era_learnings
  • GET /api/v1/era_learnings/{id}
ColumnTypeNullableAllowed valuesReferences
idstring (uuid) · uuid
organization_idstring (uuid) · uuidorganization
workspace_idstring (uuid) · uuidworkspace
kindstring · textmemory, skill
statusstring · textproposed, approved, rejected
proposed_bystring · textera, learning, skills
for_userstring (uuid) · uuidyesapp_user
statementstring · textyes
memory_kindstring · textyes
audiencestring · textperson, workspace, module
module_codestring · textyes
expires_atstring (date-time) · timestamptzyes
brain_idstring (uuid) · uuidyesbrain
knowledge_base_idstring (uuid) · uuidyesknowledge_base
confidencenumber · float4yes
skill_idstring · textyes
skill_namestring · textyes
skill_descriptionstring · textyes
skill_contentstring · textyes
reasonstring · textyes
sourceobject · jsonb
evidence_countinteger · int4
dedupe_keystring · textyes
decided_bystring (uuid) · uuidyesapp_user
decided_atstring (date-time) · timestamptzyes
result_refstring · textyes
created_atstring (date-time) · timestamptz
updated_atstring (date-time) · timestamptz
scorenumber · float4yes
lowered_byobject · 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_bases
  • GET /api/v1/knowledge_bases/{id}
  • POST /api/v1/knowledge_bases → ai.create_knowledge_base
ColumnTypeNullableAllowed valuesReferences
idstring (uuid) · uuid
organization_idstring (uuid) · uuidorganization
workspace_idstring (uuid) · uuidworkspace
brain_idstring (uuid) · uuidbrain
namestring · text
kindstring · textcompany, product, sales, marketing, customers, projects, personal, voice, industry, meetings, brand, finance, support, custom
descriptionstring · textyes
is_defaultboolean · bool
archived_atstring (date-time) · timestamptzyes
created_bystring (uuid) · uuidyesapp_user
created_atstring (date-time) · timestamptz
updated_atstring (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.

EventWhat happensPayload
ai.agent_createdAn agent was created.id, name
ai.agent_deletedAn agent was removed.id, name
ai.agent_disabledAn agent stopped listening.id, name
ai.agent_enabledAn agent started listening.id, name
ai.agent_linkedAn agent was linked to (or unlinked from) an assistant.id, engineAgentId
ai.agent_requestedSomebody or something asked an agent to run.id, prompt
ai.agent_updatedAn agent’s brief, model or triggers changed.id, name
ai.approval_escalatedA request for approval has waited too long.approvalId, intent, tool, ageHours
ai.brain_archivedA brain was archived.id, name
ai.brain_boundAn Era, workflow or voice agent now uses a brain.id, subjectType, subjectId, brainId, access
ai.brain_createdA brain was created.id, name, kind
ai.brain_fact_erasedSomething Era learned was permanently erased.id, facts
ai.brain_fact_reviewedA person corrected, forgot, kept private or confirmed something Era learned.id, memoryId, decision, appliedMemoryId
ai.brain_insight_createdEra noticed something for a role.id, role, title, severity
ai.brain_insight_updatedAn insight was seen, done or dismissed.id, status
ai.brain_person_erasedEverything Era learned about a person was permanently erased.id, facts, entities
ai.brain_unboundAn Era, workflow or voice agent stopped using a brain.subjectType, subjectId, brainId
ai.brain_updatedA brain’s name, memory or what it learns from changed.id, name
ai.budget_alertAI spend crossed a budget alert threshold or its cap. Point a notification rule at it.budgetId, scope, agentId, period, capUsd, spentUsd, level
ai.budget_updatedAn AI budget was set or removed.id, agentId
ai.chat_sharedA chat was shared with a person (or their access changed).conversationId, title, access, canApprove, recipientUserId
ai.chat_visibility_changedA chat became private or visible to the workspace, or its link changed.conversationId, visibility, link
ai.code_session_closedA live coding session was closed.id
ai.code_session_openedA live coding session started in a folder on the person’s computer.id, folderName, harness, conversationId
ai.computer_approval_requestedA computer task is waiting for a person to approve a step.id, summary, risk, recipientUserId
ai.computer_machine_changedA cloud computer changed state.id, state, recipientUserId
ai.computer_machine_requestedA person asked their cloud computer to be created, started, paused or deleted.id, op
ai.computer_policy_savedThe workspace computer rules changed.approvalMode
ai.computer_session_createdA computer session was prepared.id, title, needsProvider
ai.computer_session_finishedA computer task finished, failed or was stopped.id, status, success, result, sourceRef
ai.computer_session_queuedA computer task was queued for the computer worker.id, title, kind, target
ai.computer_session_startedA computer task started running.id, provider
ai.computer_session_stoppedA computer session was stopped.id
ai.connection_sharedWho may use an AI connection changed.id, provider, scope
ai.conversation_deletedA thread was deleted.id
ai.conversation_startedA thread with Era was opened.id, agentId
ai.decide_outcome_recordedA person confirmed or corrected one of Era’s decisions.id, questionKey, outcome
ai.erasure_candidate_resolvedA manager erased or dismissed a possible match of an erasure request.id, decision, facts
ai.key_rotation_dueA provider key is older than the rotation period.id, provider, ageDays, recipientUserId
ai.knowledge_base_archivedA knowledge space was archived.id, brainId, name
ai.knowledge_base_createdA knowledge space was created.id, brainId, name
ai.knowledge_base_updatedA knowledge space changed.id, brainId, name
ai.learning_decidedA person approved or rejected what Era asked to keep.id, kind, decision, resultRef
ai.learning_forgottenA person told Era to forget something, or to stop using a skill.kind, ref
ai.learning_proposedEra asked to remember something, or to keep a skill.id, kind, proposedBy
ai.memory_refiledA person changed a memory’s category, who it is for or when it ends.id, memoryId
ai.model_policy_updatedThe model for a kind of work changed.taskClass, model
ai.provider_checkedAn AI provider health check ran.id, ok
ai.provider_recoveredA failing provider answered again.id, provider, recipientUserId
ai.provider_removedAn AI provider was removed.id, provider
ai.provider_unhealthyA provider failed its scheduled check; runs route around it.id, provider, error, recipientUserId
ai.provider_updatedAn AI provider or its key was saved.id, provider
ai.skill_evaluatedA skill version was evaluated.id, skillId, score
ai.skill_installedA skill was installed from a template.skillId
ai.skill_pausedA skill was paused.skillId
ai.skill_policy_updatedA skill’s published state or permissions changed.skillId, published
ai.skill_promotedA skill version went live (or was rolled back to).id, skillId, version
ai.skill_resumedA skill was resumed.skillId
ai.skill_uninstalledA skill was uninstalled.skillId
ai.skill_version_createdA skill version was saved.id, skillId, version
ai.source_choice_updatedWhere an Era, workflow, brain or other AI-using thing runs changed.id, subjectType, subjectId
ai.subscription_connectedA person connected their own AI subscription.id, provider, execution, recipientUserId
ai.subscription_disconnectedA person disconnected their own AI subscription.id, provider, recipientUserId
ai.subscription_limitedA person’s own subscription reached its plan limit.id, provider, resetsAt, recipientUserId
ai.subscription_needs_loginA person’s own subscription signed out; they need to sign in again.id, provider, recipientUserId
ai.subscription_recoveredA person’s own subscription works again.id, provider, recipientUserId
ai.task_assignedA task was handed to a person or an agent.id, assigneeUserId, assigneeAgentId, recipientUserId
ai.task_cancelledA task was cancelled (its status set to cancelled).id
ai.task_completedA task was completed.id, nextId
ai.task_createdA task was created.id, title, recordType, recordId, recipientUserId
ai.task_deletedA task was deleted.id
ai.task_dueA 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_overdueA 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_reopenedA task was reopened.id
ai.task_updatedA task changed.id
ai.template_installedAn agent, skill or workflow was installed from the marketplace.id, kind, instanceId, templateId, requiredApps
Was this page helpful?