Reference

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

ScopeWhat it does
brainRead and write memories (everything the person may do with Brain).
brain:readSearch, graph, list, get, explain, sources, job status.
brain:writeAlso add, correct and forget. Implies brain:read.
*, ai, ai:read, ai:writeReach 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

AddressNeedsWhat it does
POST/api/v1/brain/memoriesbrain:writeAdd memory
GET/api/v1/brain/jobs/{id}brain:readIngestion status
POST/api/v1/brain/searchbrain:readSearch memory
GET/api/v1/brain/memoriesbrain:readList memories
GET/api/v1/brain/memories/{id}brain:readGet a memory
PATCH/api/v1/brain/memories/{id}brain:writeCorrect a memory
DELETE/api/v1/brain/memories/{id}brain:writeForget a memory
GET/api/v1/brain/entitiesbrain:readList entities
GET/api/v1/brain/entities/{id}brain:readGet an entity and its neighbours
GET/api/v1/brain/graphbrain:readGraph paths for a question
GET/api/v1/brain/pathsbrain:readPath between two entities
GET/api/v1/brain/sourcesbrain:readSources
POST/api/v1/brain/explainbrain:readExplain 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.

POSThttps://app.getera.io/api/v1/brain/memories
API key or OAuth token · brain:write

Body

FieldTypeRequiredNotes
textstringFree text: a note, an email, a transcript. 20–24 000 characters. · min 20 · max 24000
messagesarray of objectA conversation; each message is kept with its speaker. · ≤ 200 items
factsarray of objectReady-made facts: stored as given (no extraction). · ≤ 40 items
recordobjectA structured record (a ticket, a contact, an order from your system).
sourceobjectWhere this came from. Shown with every recalled fact. Default: a note by the caller.
visibilityworkspace · privateprivate: only you will ever recall it. · default "workspace"
modulestringKeep it to the readers of one module you can read (e.g. crm). · max 64
waitintegerSeconds 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." --wait

Tool 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.

GEThttps://app.getera.io/api/v1/brain/jobs/{id}
API key or OAuth token · brain:read

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

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.

POSThttps://app.getera.io/api/v1/brain/search
API key or OAuth token · brain:read

For a quick look from a browser or curl: GET /api/v1/brain/search?q=…&limit=…&graph=true.

Body

FieldTypeRequiredNotes
querystringyesThe question, in any language. · min 1 · max 500
limitintegerResults, 1–30. · default 10 · ≥ 1 · ≤ 30
graphbooleanAlso 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.

GEThttps://app.getera.io/api/v1/brain/memories
API key or OAuth token · brain:read

Query parameters

FieldTypeRequiredNotes
qstringWords to look for.
kindfact · preference · decision · commitment · episode
entity_idstring (uuid)Only facts naming this entity.
sourcenote · conversation · record · file · web · meeting · call · chat · document · connector · workflow_run · researchOnly facts from this kind of source.
limitinteger1–100. · default 25 · ≥ 1 · ≤ 100
cursorstringnext_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 invoice

Response

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).

GEThttps://app.getera.io/api/v1/brain/memories/{id}
API key or OAuth token · brain:read

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).

PATCHhttps://app.getera.io/api/v1/brain/memories/{id}
API key or OAuth token · brain:write

Body

FieldTypeRequiredNotes
contentstringThe right wording. · min 3 · max 4000
confirmbooleanMark it as confirmed by a person.
visibilityprivateKeep it to yourself from now on.
categorypreference · 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.

DELhttps://app.getera.io/api/v1/brain/memories/{id}
API key or OAuth token · brain:write

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.

GEThttps://app.getera.io/api/v1/brain/entities
API key or OAuth token · brain:read

Query parameters

FieldTypeRequiredNotes
qstringName or alias contains.
typestringperson, customer, company, product, project, topic …
limitinteger1–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 Ada

Response

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.

GEThttps://app.getera.io/api/v1/brain/entities/{id}
API key or OAuth token · brain:read

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.

GEThttps://app.getera.io/api/v1/brain/graph
API key or OAuth token · brain:read

Query parameters

FieldTypeRequiredNotes
qstringThe question. · min 1 · max 500
limitintegerPaths, 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).

GEThttps://app.getera.io/api/v1/brain/paths
API key or OAuth token · brain:read

Query parameters

FieldTypeRequiredNotes
fromstringAn entity name.
tostringAnother entity name.
max_depthintegerHops, 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.

GEThttps://app.getera.io/api/v1/brain/sources
API key or OAuth token · brain:read

Example

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 sources

Response

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.

POSThttps://app.getera.io/api/v1/brain/explain
API key or OAuth token · brain:read

Body

FieldTypeRequiredNotes
querystringyesThe question. · min 1 · max 500
memory_idstring (uuid)yesThe 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).

ToolNeedsWhat it does
search_memorybrain:readSearch 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_memorybrain:writeSave 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_pathsbrain:readHow 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_memorybrain:writeStop 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.
Was this page helpful?