Skip to content

Memory API

Base path: /api (Sanctum bearer + X-Organization-Id or token ability organization:{uuid}).

Ingest

POST /api/memories

Body: content, optional metadata.

Content safety (OB-045)

When OPENBRAIN_CONTENT_SCAN_ENABLED=true (default in production), ingest, upsert, update, and batch items are scanned for high-risk patterns (API keys, payment card-like sequences, email addresses). Rejected content returns 422:

json
{ "error": "...", "code": "content_rejected" }

Disable in local/test with OPENBRAIN_CONTENT_SCAN_ENABLED=false.

outcomeHTTPMeaning
created201New row stored
deduplicated200Exact content_hash replay; metadata unchanged after shallow merge
merged_metadata200Exact or semantic near-duplicate; incoming metadata keys merged (dedupe: exact or semantic)

Keyed upsert (OB-019)

PUT /api/memories

Idempotent sync by external key.

FieldRequiredDescription
externalKeyyesStable id from an external system
contentyesMemory body (NFC-normalized server-side)
metadatanoJSON metadata merged into the row
scopenosource, project — part of uniqueness with externalKey
outcomeHTTPMeaning
created201New row for this key scope
deduplicated200Same content replay; metadata merged
updated200Content changed; re-embedded

Errors: 404 if the key matches a soft-deleted row; 409 if content_hash belongs to another row.

Semantic near-duplicate merge is not applied on this path.

Batch ingest (OB-020)

POST /api/memories/batch

FieldRequiredDescription
itemsyesArray of { content, metadata?, externalKey?, scope? }
continueOnErrornoDefault true; stop after first failure when false

Response 200: results (per-row success fields + index, or { index, error: { code, message } }) and summary: { ok, failed }.

413 when items.length exceeds OPENBRAIN_BATCH_INGEST_MAX (default 50).

Items with externalKey use keyed upsert; others use standard ingest (including dedupe).

Update

PATCH /api/memories/{id} ( PUT alias for backward compatibility)

Requires memory:admin.

FieldRequiredDescription
contentno*Replaces body; re-embeds when changed
metadatano*Merged into existing metadata by default
metadataReplacenoWhen true, replaces metadata instead of merging

* At least one of content or metadata is required.

Response 200 with outcome: updated. 409 when new content hashes to another row’s content_hash.

Delete

DELETE /api/memories/{id}

Requires memory:admin. Soft-deletes the row. Response 204 with an empty body.

Export (OB-035)

GET /api/memories/export

Requires memory:search. Returns NDJSON (application/x-ndjson) with one memory per line: id, content, metadata, createdAt, updatedAt, optional deletedAt (no embedding vectors).

Query: limit (default 100, max 500), cursor (from X-Next-Cursor on the previous page), optional filter, includeDeleted.

Rows are ordered by created_at ascending for stable pagination.

Stats (OB-034)

GET /api/memories/stats

Requires memory:search. Returns facet counts for metadata keys agentId, source, surface, project, kind, plus meta.total and meta.filtered.

Changes / delta (OB-064)

GET /api/memories/changes

Requires memory:search. Returns memories created, updated, or (with includeDeleted) soft-deleted since an ISO-8601 since timestamp.

Query: since (required), limit (default 100, max 500), cursor (from nextCursor in the prior response), optional filter, includeDeleted.

Response 200:

json
{
  "changes": [
    { "id": "...", "content": "...", "metadata": {}, "change": "created", "createdAt": "...", "updatedAt": "..." },
    { "id": "...", "deletedAt": "...", "change": "deleted" }
  ],
  "meta": { "count": 2 },
  "nextCursor": "2026-05-22T12:00:00+00:00|uuid"
}

Active rows use the same fields as single-record reads (no embeddings). Deleted rows omit content.

Large documents (OB-044)

Chunk large inputs across multiple ingest or batch rows using metadata:

KeyTypeDescription
documentIdstringStable id for the document
chunkIndexintZero-based index
chunkTotalintTotal chunks

If any chunk field is set, all three are required and 0 <= chunkIndex < chunkTotal.

Read concatenated chunks via MCP resource brain://{organizationId}/document/{documentId}.

Recent list (OB-032)

GET /api/memories/recent

Requires memory:search. Query: limit (default 20, max 50), optional filter (metadata key/value), includeDeleted.

Response 200: { "results": [...], "meta": { "count": N } } — newest created_at first.

MCP

ToolREST equivalent
memory_ingestPOST /api/memories
memory_upsertPUT /api/memories
memory_ingest_batchPOST /api/memories/batch
memory_searchPOST /api/memories/search
memory_statsGET /api/memories/stats
memory_changesGET /api/memories/changes
memory_recentGET /api/memories/recent
memory_getGET /api/memories/{id}
memory_updatePATCH /api/memories/{id}
memory_deleteDELETE /api/memories/{id}
openbrain_healthreadiness checks (MCP) — see health.md