Brain API reference
Every Era Brain endpoint and MCP tool: address, scope, parameters, responses, SDK, CLI and errors — generated from the Brain API's own declaration.
Every endpoint below is declared once in Era's kernel; the server, the OpenAPI document (tag brain in /api/v1/openapi.json), the SDKs, the CLI and this page are all built from that declaration. Authenticate with an API key (Authorization: Bearer era_…) or an OAuth access token. A credential never sees more than the person behind it sees in the Era app.
Scopes
| Scope | What it does |
|---|---|
brain | Read and write memories (everything the person may do with Brain). |
brain:read | Search, graph, list, get, explain, sources, job status. |
brain:write | Also add, correct and forget. Implies brain:read. |
*, ai, ai:read, ai:write | Reach Brain too (Brain belongs to the ai module). |
A memory-only credential sees memories that belong to no module. Facts derived from a module (CRM, finance …) are recalled only when the credential may also read that module — add crm:read to a key or token to recall CRM-derived facts.
Endpoints
| Address | Needs | What it does | |
|---|---|---|---|
POST | /api/v1/brain/memories | brain:write | Add memory |
GET | /api/v1/brain/jobs/{id} | brain:read | Ingestion status |
POST | /api/v1/brain/search | brain:read | Search memory |
GET | /api/v1/brain/memories | brain:read | List memories |
GET | /api/v1/brain/memories/{id} | brain:read | Get a memory |
PATCH | /api/v1/brain/memories/{id} | brain:write | Correct a memory |
DELETE | /api/v1/brain/memories/{id} | brain:write | Forget a memory |
GET | /api/v1/brain/entities | brain:read | List entities |
GET | /api/v1/brain/entities/{id} | brain:read | Get an entity and its neighbours |
GET | /api/v1/brain/graph | brain:read | Graph paths for a question |
GET | /api/v1/brain/paths | brain:read | Path between two entities |
GET | /api/v1/brain/sources | brain:read | Sources |
POST | /api/v1/brain/explain | brain:read | Explain a result |
Every error has one shape: { "error": { "code", "message", "status", "problems"?, "request_id" } }. A missing record and a record you may not see answer the same 404, so ids cannot be probed.
Add memory
Give Brain something to remember: free text, a conversation, ready-made facts or a record. Era’s ingestion worker extracts self-contained facts, links the people, companies and products they name, deduplicates against what it already knows (latest value wins) and embeds them locally. Send exactly one of text, messages, facts or record. Pass wait (seconds) to get the stored memories back in the same call.
https://app.getera.io/api/v1/brain/memoriesBody
| Field | Type | Required | Notes |
|---|---|---|---|
text | string | Free text: a note, an email, a transcript. 20–24 000 characters. · min 20 · max 24000 | |
messages | array of object | A conversation; each message is kept with its speaker. · ≤ 200 items | |
facts | array of object | Ready-made facts: stored as given (no extraction). · ≤ 40 items | |
record | object | A structured record (a ticket, a contact, an order from your system). | |
source | object | Where this came from. Shown with every recalled fact. Default: a note by the caller. | |
visibility | workspace · private | private: only you will ever recall it. · default "workspace" | |
module | string | Keep it to the readers of one module you can read (e.g. crm). · max 64 | |
wait | integer | Seconds to wait for the memories to be stored (0 = return at once). · default 0 · ≥ 0 · ≤ 20 |
Example
curl -X POST "https://app.getera.io/api/v1/brain/memories" \
-H "Authorization: Bearer $ERA_API_KEY" \
-H "Content-Type: application/json" \
-d '{"text":"Ada Lovelace from Analytical Engines Ltd prefers invoices in EUR, sent on the 1st of each month.","source":{"kind":"note","label":"Call notes"},"wait":10}'import { createBrain } from '@getera/brain' // or: createEra(...).brain
const brain = createBrain({ apiKey: process.env.ERA_API_KEY })
await brain.add({ text: 'Ada Lovelace prefers invoices in EUR, sent on the 1st.', wait: 10 })era brain add "Ada Lovelace prefers invoices in EUR, sent on the 1st." --waitTool add_memory — input:
{
"text": {
"type": "string",
"description": "What to remember (or use facts)"
},
"facts": {
"type": "array",
"description": "Ready-made facts: [{ statement, kind?, about?: [{ name, type }] }]",
"items": {
"type": "object"
}
},
"visibility": {
"type": "string",
"enum": [
"workspace",
"private"
],
"description": "Default workspace"
},
"source_label": {
"type": "string",
"description": "Where it came from, e.g. \"Claude Code session\""
}
}Response
Answers 202
{
"job": {
"id": "6b1d…",
"status": "done"
},
"memories": [
{
"id": "0f3a…",
"content": "Ada Lovelace prefers invoices in EUR.",
"kind": "preference",
"visibility": "workspace",
"entities": [
{
"id": "91c2…",
"name": "Ada Lovelace",
"type": "person"
}
],
"created_at": "2026-10-22T09:12:03Z"
}
]
}Errors: 401 unauthorized · 404 not_found (Brain is outside this credential) · 403 forbidden (read-only credential) · 409 no_brain · learning_off · 422 invalid_input
Ingestion status
Where a memory you added is: queued, running, done or failed — and, once done, the memories it stored that you can see.
https://app.getera.io/api/v1/brain/jobs/{id}Example
curl "https://app.getera.io/api/v1/brain/jobs/JOB_ID" \
-H "Authorization: Bearer $ERA_API_KEY"import { createBrain } from '@getera/brain' // or: createEra(...).brain
const brain = createBrain({ apiKey: process.env.ERA_API_KEY })
await brain.job('6b1d…')era brain job 6b1d…Response
Answers 200
{
"job": {
"id": "6b1d…",
"status": "done",
"error": null
},
"memories": []
}Errors: 401 unauthorized · 404 not_found
Search memory
Hybrid recall: a keyword leg (PostgreSQL full text, Turkish and English) and a semantic leg (local e5 embeddings) run side by side and are fused by rank; a newer fact about the same thing is placed above an older one. With graph: true the typed relationship paths between the entities the question names are returned too. Only what this caller may see is searched.
https://app.getera.io/api/v1/brain/searchFor a quick look from a browser or curl: GET /api/v1/brain/search?q=…&limit=…&graph=true.
Body
| Field | Type | Required | Notes |
|---|---|---|---|
query | string | yes | The question, in any language. · min 1 · max 500 |
limit | integer | Results, 1–30. · default 10 · ≥ 1 · ≤ 30 | |
graph | boolean | Also return typed relationship paths. · default false |
Example
curl -X POST "https://app.getera.io/api/v1/brain/search" \
-H "Authorization: Bearer $ERA_API_KEY" \
-H "Content-Type: application/json" \
-d '{"query":"How does Ada want to be invoiced?","limit":5}'import { createBrain } from '@getera/brain' // or: createEra(...).brain
const brain = createBrain({ apiKey: process.env.ERA_API_KEY })
const { results } = await brain.search('How does Ada want to be invoiced?')era brain search "How does Ada want to be invoiced?"Tool search_memory — input:
{
"query": {
"type": "string",
"description": "The question, in any language"
},
"limit": {
"type": "number",
"description": "1-30, default 10"
},
"graph": {
"type": "boolean",
"description": "Also return typed relationship paths"
}
}Response
Answers 200
{
"query": "How does Ada want to be invoiced?",
"used_vector": true,
"results": [
{
"id": "0f3a…",
"content": "Ada Lovelace prefers invoices in EUR.",
"kind": "preference",
"score": 0.0331,
"created_at": "2026-10-22T09:12:03Z"
}
]
}Errors: 401 unauthorized · 404 not_found (Brain is outside this credential) · 422 invalid_input
List memories
What Brain knows now, newest first, with sources and the entities each fact names. Filter by words, kind, entity or source kind.
https://app.getera.io/api/v1/brain/memoriesQuery parameters
| Field | Type | Required | Notes |
|---|---|---|---|
q | string | Words to look for. | |
kind | fact · preference · decision · commitment · episode | ||
entity_id | string (uuid) | Only facts naming this entity. | |
source | note · conversation · record · file · web · meeting · call · chat · document · connector · workflow_run · research | Only facts from this kind of source. | |
limit | integer | 1–100. · default 25 · ≥ 1 · ≤ 100 | |
cursor | string | next_cursor of the previous page. |
Example
curl "https://app.getera.io/api/v1/brain/memories?q=invoice&limit=10" \
-H "Authorization: Bearer $ERA_API_KEY"import { createBrain } from '@getera/brain' // or: createEra(...).brain
const brain = createBrain({ apiKey: process.env.ERA_API_KEY })
const { data } = await brain.list({ q: 'invoice' })era brain list --q invoiceResponse
Answers 200
{
"data": [
{
"id": "0f3a…",
"content": "Ada Lovelace prefers invoices in EUR.",
"kind": "preference",
"visibility": "workspace",
"source": {
"kind": "note",
"label": "Call notes"
},
"entities": [],
"created_at": "2026-10-22T09:12:03Z"
}
],
"next_cursor": null
}Errors: 401 unauthorized · 404 not_found · 422 invalid_input
Get a memory
One fact with its source, the entities it names and its history (the facts it replaced).
https://app.getera.io/api/v1/brain/memories/{id}Example
curl "https://app.getera.io/api/v1/brain/memories/MEMORY_ID" \
-H "Authorization: Bearer $ERA_API_KEY"import { createBrain } from '@getera/brain' // or: createEra(...).brain
const brain = createBrain({ apiKey: process.env.ERA_API_KEY })
await brain.get('0f3a…')era brain get 0f3a…Response
Answers 200
{
"data": {
"id": "0f3a…",
"content": "Ada Lovelace prefers invoices in EUR.",
"kind": "preference",
"visibility": "workspace",
"history": []
}
}Errors: 401 unauthorized · 404 not_found (absent and not-yours answer the same)
Correct a memory
Correct the wording (the old version is kept as history and no longer recalled), confirm it, change its category, or keep it private to you. Runs the same actions as the Brain screen (ai.review_brain_fact, ai.refile_brain_fact).
https://app.getera.io/api/v1/brain/memories/{id}Body
| Field | Type | Required | Notes |
|---|---|---|---|
content | string | The right wording. · min 3 · max 4000 | |
confirm | boolean | Mark it as confirmed by a person. | |
visibility | private | Keep it to yourself from now on. | |
category | preference · rule · procedure · fact |
Example
curl -X PATCH "https://app.getera.io/api/v1/brain/memories/MEMORY_ID" \
-H "Authorization: Bearer $ERA_API_KEY" \
-H "Content-Type: application/json" \
-d '{"content":"Ada Lovelace prefers invoices in GBP since October."}'import { createBrain } from '@getera/brain' // or: createEra(...).brain
const brain = createBrain({ apiKey: process.env.ERA_API_KEY })
await brain.update('0f3a…', { content: 'Ada prefers invoices in GBP since October.' })era brain correct 0f3a… "Ada prefers invoices in GBP since October."Response
Answers 200
{
"ok": true,
"id": "0f3a…"
}Errors: 401 unauthorized · 403 forbidden · 404 not_found · 409 fact_not_found · not_current · unchanged · 422 invalid_input
Forget a memory
Era stops using it at once (it is no longer recalled by anyone). The audit trail keeps that it was forgotten, by whom. Permanent erasure for a data-subject request stays on the Brain screen for managers.
https://app.getera.io/api/v1/brain/memories/{id}Example
curl -X DELETE "https://app.getera.io/api/v1/brain/memories/MEMORY_ID" \
-H "Authorization: Bearer $ERA_API_KEY"import { createBrain } from '@getera/brain' // or: createEra(...).brain
const brain = createBrain({ apiKey: process.env.ERA_API_KEY })
await brain.forget('0f3a…')era brain forget 0f3a…Tool forget_memory — input:
{
"memory_id": {
"type": "string",
"description": "Memory id"
},
"about": {
"type": "string",
"description": "Or: what to forget, in words"
}
}Response
Answers 200
{
"ok": true
}Errors: 401 unauthorized · 403 forbidden · 404 not_found · 409 nothing_to_forget
List entities
The people, companies, products and topics Brain knows, with how many visible facts name each.
https://app.getera.io/api/v1/brain/entitiesQuery parameters
| Field | Type | Required | Notes |
|---|---|---|---|
q | string | Name or alias contains. | |
type | string | person, customer, company, product, project, topic … | |
limit | integer | 1–100. · default 25 · ≥ 1 · ≤ 100 |
Example
curl "https://app.getera.io/api/v1/brain/entities?q=Ada" \
-H "Authorization: Bearer $ERA_API_KEY"import { createBrain } from '@getera/brain' // or: createEra(...).brain
const brain = createBrain({ apiKey: process.env.ERA_API_KEY })
await brain.entities({ q: 'Ada' })era brain entities --q AdaResponse
Answers 200
{
"data": [
{
"id": "91c2…",
"name": "Ada Lovelace",
"type": "person",
"aliases": [
"Ada"
],
"facts": 4
}
]
}Errors: 401 unauthorized · 404 not_found
Get an entity and its neighbours
One entity, its typed relations (works_at, supplies, owns …) to other entities, and the latest facts that name it.
https://app.getera.io/api/v1/brain/entities/{id}Example
curl "https://app.getera.io/api/v1/brain/entities/ENTITY_ID" \
-H "Authorization: Bearer $ERA_API_KEY"import { createBrain } from '@getera/brain' // or: createEra(...).brain
const brain = createBrain({ apiKey: process.env.ERA_API_KEY })
await brain.entity('91c2…')era brain entity 91c2…Response
Answers 200
{
"data": {
"id": "91c2…",
"name": "Ada Lovelace",
"type": "person",
"relations": [
{
"direction": "out",
"relation": "works_at",
"entity": {
"id": "7aa0…",
"name": "Analytical Engines Ltd",
"type": "company"
}
}
],
"facts": []
}
}Errors: 401 unauthorized · 404 not_found
Graph paths for a question
The read path Era’s own chat uses: anchors the entities the question names, walks typed relations up to three hops (not through hub fans), and returns the best paths, each hop backed by the memory that states it, plus a compact cited context for an LLM.
https://app.getera.io/api/v1/brain/graphQuery parameters
| Field | Type | Required | Notes |
|---|---|---|---|
q | string | The question. · min 1 · max 500 | |
limit | integer | Paths, 1–12. · default 6 · ≥ 1 · ≤ 12 |
Example
curl "https://app.getera.io/api/v1/brain/graph?q=Who%20supplies%20the%20company%20Ada%20works%20at%3F" \
-H "Authorization: Bearer $ERA_API_KEY"import { createBrain } from '@getera/brain' // or: createEra(...).brain
const brain = createBrain({ apiKey: process.env.ERA_API_KEY })
await brain.graph('Who supplies the company Ada works at?')era brain graph "Who supplies the company Ada works at?"Tool graph_paths — input:
{
"query": {
"type": "string",
"description": "A question naming the entities"
},
"from": {
"type": "string",
"description": "An entity name (with to)"
},
"to": {
"type": "string",
"description": "Another entity name"
}
}Response
Answers 200
{
"query": "Who supplies the company Ada works at?",
"anchors": [
{
"id": "91c2…",
"name": "Ada Lovelace",
"type": "person"
}
],
"paths": [
{
"score": 2.4,
"hops": [
{
"from": "Ada Lovelace",
"relation": "works_at",
"to": "Analytical Engines Ltd"
},
{
"from": "Babbage Parts",
"relation": "supplies",
"to": "Analytical Engines Ltd"
}
]
}
],
"context": "…"
}Errors: 401 unauthorized · 404 not_found · 422 invalid_input
Path between two entities
The shortest chain of typed relations between two named entities (deterministic; no model is called).
https://app.getera.io/api/v1/brain/pathsQuery parameters
| Field | Type | Required | Notes |
|---|---|---|---|
from | string | An entity name. | |
to | string | Another entity name. | |
max_depth | integer | Hops, 1–6. · default 4 · ≥ 1 · ≤ 6 |
Example
curl "https://app.getera.io/api/v1/brain/paths?from=Ada%20Lovelace&to=Babbage%20Parts" \
-H "Authorization: Bearer $ERA_API_KEY"import { createBrain } from '@getera/brain' // or: createEra(...).brain
const brain = createBrain({ apiKey: process.env.ERA_API_KEY })
await brain.paths('Ada Lovelace', 'Babbage Parts')era brain path "Ada Lovelace" "Babbage Parts"Response
Answers 200
{
"found": true,
"from": {
"id": "91c2…",
"name": "Ada Lovelace",
"type": "person"
},
"to": {
"id": "3c1e…",
"name": "Babbage Parts",
"type": "company"
},
"hops": [
{
"from": "Ada Lovelace",
"relation": "works_at",
"to": "Analytical Engines Ltd"
},
{
"from": "Babbage Parts",
"relation": "supplies",
"to": "Analytical Engines Ltd"
}
]
}Errors: 401 unauthorized · 404 not_found · 422 invalid_input
Sources
Where what Brain knows came from: the connected sources of this workspace (Google Drive, Notion …) and, per kind of source, how many visible facts it gave and when last.
https://app.getera.io/api/v1/brain/sourcesExample
curl "https://app.getera.io/api/v1/brain/sources" \
-H "Authorization: Bearer $ERA_API_KEY"import { createBrain } from '@getera/brain' // or: createEra(...).brain
const brain = createBrain({ apiKey: process.env.ERA_API_KEY })
await brain.sources()era brain sourcesResponse
Answers 200
{
"connected": [],
"kinds": [
{
"kind": "note",
"memories": 12,
"last_at": "2026-10-22T09:12:03Z"
}
]
}Errors: 401 unauthorized · 404 not_found
Explain a result
Why a fact was (or was not) returned for a question: its rank in the keyword and semantic legs, the fused score, recency and importance, the entities it names that the question also names, and the visibility rule that let you see it.
https://app.getera.io/api/v1/brain/explainBody
| Field | Type | Required | Notes |
|---|---|---|---|
query | string | yes | The question. · min 1 · max 500 |
memory_id | string (uuid) | yes | The fact to explain. |
Example
curl -X POST "https://app.getera.io/api/v1/brain/explain" \
-H "Authorization: Bearer $ERA_API_KEY" \
-H "Content-Type: application/json" \
-d '{"query":"How does Ada want to be invoiced?","memory_id":"0f3a…"}'import { createBrain } from '@getera/brain' // or: createEra(...).brain
const brain = createBrain({ apiKey: process.env.ERA_API_KEY })
await brain.explain('How does Ada want to be invoiced?', '0f3a…')era brain explain "How does Ada want to be invoiced?" 0f3a…Response
Answers 200
{
"returned": true,
"rank": 1,
"score": 0.0331,
"keyword": {
"matched": true,
"terms": [
"ada",
"invoic"
]
},
"semantic": {
"similarity": 0.87
},
"shared_entities": [
{
"id": "91c2…",
"name": "Ada Lovelace",
"type": "person"
}
],
"recency_days": 0.2,
"importance": 0.6,
"superseded": false,
"visible_because": "Shared with the workspace; you can read Brain."
}Errors: 401 unauthorized · 404 not_found · 422 invalid_input
MCP tools
On Era's MCP server, https://app.getera.io/api/mcp?tools=brain lists only these (without ?tools=brain they sit next to the business tools).
| Tool | Needs | What it does |
|---|---|---|
search_memory | brain:read | Search Era Brain, the business's long-term memory, before answering anything about people, customers, preferences, decisions or past work. Hybrid keyword + semantic recall, newest fact first when two disagree. Only what the signed-in person may see. |
add_memory | brain:write | Save something worth remembering beyond this session: a stable preference, a decision and its reason, a commitment, a fact about a person, customer or project. One self-contained statement per fact. Do not save secrets, passwords or one-off chatter. visibility "private" keeps it to the signed-in person. |
graph_paths | brain:read | How things are connected: typed relationship paths (works_at, supplies, owns …) between the entities a question names, each hop with the memory that states it. Give "from" and "to" for the shortest path between two named entities instead. |
forget_memory | brain:write | Stop Era using a memory: by its id (from search_memory), or by describing it ("about"). Use when the person says something is wrong or no longer true; prefer add_memory with the new fact when it changed. |