Native Memory API
Native memory records conversations for a peer, derives claims asynchronously,
and returns cited context for later work. Direct HTTP, marrowid==1.0.11
imported as marrow, @marrowid/sdk@1.0.11, and @marrowid/cli@1.0.11 use the
same API operations. Hosted MCP at https://mcp.marrow.id and local
marrow mcp expose those operations through the same 14 memory tools.
These integrations run inside a trusted application process. Keeping the API key in that process protects the credential, but it does not provide prompt-injection isolation for untrusted messages or retrieved text. Treat returned context as data and preserve its status, citations, conflicts, and warnings when another model consumes it.
See the complete machine-readable OpenAPI document.
Core concepts
- A Source is a URL or supported file submitted through the Ingest API.
- A Record is one stored unit derived from a source: a source excerpt, fact,
or relationship link. In an ingest result,
records.totalis the sum ofsourceExcerpts,facts, andlinks. - Memory is the current, account-scoped information Marrow can return for later work. It includes source-backed records and native memory written by an application.
- A Peer is the person, agent, or group that native memory is about.
- A Session is an interaction thread containing peer-attributed messages.
- A Claim is one current statement derived from a session message or explicitly corrected by the user. Claims retain citations, lifecycle state, and history.
Credential and scope contract
Every route below accepts only a customer API key in
Authorization: Bearer $MARROW_API_KEY. Browser cookies and CLI session tokens
do not authenticate native memory routes. Workspace, peer, session, claim, and
event identifiers are labels or public handles inside the account selected by
the key; they are not ownership credentials.
| Scope | Minimum use |
|---|---|
memory.write |
Get or create workspace, peer, and session labels; add messages; correct or withdraw claims. |
memory.read |
List and fetch workspace, peer, session, message, representation, claim, write-event, and queue state. |
Use both scopes for a process that writes a message, polls its event, and then
reads the resulting memory. The current OpenAPI contract admits the default
workspace label.
Lifecycle
- Get or create the workspace, peer, and session labels with
memory.write. - Add one or more peer-attributed messages. The receipt has
status: "processing"and anevent_id. - Poll
GET /v1/workspaces/{ws}/events/{id}withmemory.readuntilEventStatus.statusissucceeded,failed, orquarantined. - After
succeeded, call the canonical Query API in Evidence, Context, or Answer mode. A non-ready result is not permission to invent context. - Read the current claim or its history before a user-approved change. Correct
with
PUT; withdraw withDELETE. Send the claim's currenthead_revisionwith either mutation, retain the stable claim id, and inspect history forADD,UPDATE, andDELETEevents.
Complete native-memory example
This example creates a peer and session, writes one message, waits for claim derivation, reads the result, and removes the example resources.
export MARROW_API_BASE_URL="https://api.marrow.id"
export MARROW_API_KEY="<copy-once key with memory.read and memory.write>"
curl -sS -X POST "$MARROW_API_BASE_URL/v1/workspaces/default/peers" \
-H "Authorization: Bearer $MARROW_API_KEY" \
-H "Content-Type: application/json" \
-d '{"id":"quickstart-riley"}'
curl -sS -X POST "$MARROW_API_BASE_URL/v1/workspaces/default/sessions" \
-H "Authorization: Bearer $MARROW_API_KEY" \
-H "Content-Type: application/json" \
-d '{"id":"quickstart-launch"}'
curl -sS -X POST "$MARROW_API_BASE_URL/v1/workspaces/default/sessions/quickstart-launch/messages" \
-H "Authorization: Bearer $MARROW_API_KEY" \
-H "Content-Type: application/json" \
-d '{"peer_id":"quickstart-riley","messages":[{"role":"user","content":"Launch updates should begin with the decision."}]}'
The message receipt returns event_id. Omitting infer is equivalent to
"infer": true, so Marrow derives a claim. Poll the event until it succeeds:
curl -sS "$MARROW_API_BASE_URL/v1/workspaces/default/events/<event-id>" \
-H "Authorization: Bearer $MARROW_API_KEY"
Then retrieve Context through the canonical Query operation:
curl -sS -X POST "$MARROW_API_BASE_URL/v1/query" \
-H "Authorization: Bearer $MARROW_API_KEY" \
-H "Content-Type: application/json" \
-d '{"idempotencyKey":"quickstart-launch-context","mode":"context","query":"How should launch updates begin?","workspace":"default","peer_ids":["quickstart-riley"],"session_ids":["quickstart-launch"]}'
A usable result has execution: "ready", a non-null context, and its cited
support. Finish by deleting the session and peer, then poll each returned event
id until succeeded:
curl -sS -X DELETE "$MARROW_API_BASE_URL/v1/workspaces/default/sessions/quickstart-launch" \
-H "Authorization: Bearer $MARROW_API_KEY"
curl -sS -X DELETE "$MARROW_API_BASE_URL/v1/workspaces/default/peers/quickstart-riley" \
-H "Authorization: Bearer $MARROW_API_KEY"
Exact routes
| Scope | Route | Request | Success response |
|---|---|---|---|
memory.write |
POST /v1/workspaces |
No request fields | Workspace |
memory.read |
POST /v1/workspaces/list |
No request fields | PageWorkspace |
memory.write |
POST /v1/workspaces/{ws}/peers |
LabelUpsertRequest |
Peer |
memory.read |
POST /v1/workspaces/{ws}/peers/list |
No request fields | PagePeer |
memory.read |
GET /v1/workspaces/{ws}/peers/{peer} |
Path labels | Peer |
memory.write |
DELETE /v1/workspaces/{ws}/peers/{peer} |
Path labels | EventStatus |
memory.read |
POST /v1/workspaces/{ws}/peers/{peer}/representation |
No request fields | RepresentationResponse |
memory.write |
POST /v1/workspaces/{ws}/sessions |
LabelUpsertRequest |
Session |
memory.read |
POST /v1/workspaces/{ws}/sessions/list |
No request fields | PageSession |
memory.read |
GET /v1/workspaces/{ws}/sessions/{s} |
Path labels | Session |
memory.write |
DELETE /v1/workspaces/{ws}/sessions/{s} |
Path labels | EventStatus |
memory.write |
POST /v1/workspaces/{ws}/sessions/{s}/messages |
MessagesCreateRequest |
MessagesCreateReceipt |
memory.read |
POST /v1/workspaces/{ws}/sessions/{s}/messages/list |
No request fields | PageMessage |
memory.read |
POST /v1/workspaces/{ws}/claims/list |
ClaimsListRequest |
PageClaim |
memory.read |
GET /v1/workspaces/{ws}/claims/{id} |
Claim id | Claim |
memory.read |
GET /v1/workspaces/{ws}/claims/{id}/history |
Claim id | ClaimHistoryResponse |
memory.write |
PUT /v1/workspaces/{ws}/claims/{id} |
ClaimUpdateRequest |
ClaimUpdateResult |
memory.write |
DELETE /v1/workspaces/{ws}/claims/{id} |
ClaimDeleteRequest |
ClaimDeleteReceipt |
memory.read |
GET /v1/workspaces/{ws}/events/{id} |
Event id | EventStatus |
memory.read |
GET /v1/workspaces/{ws}/queue/status |
Workspace label | QueueStatus |
Credits and limits
Evidence, Context, and Answer retrieval uses POST /v1/query. It costs one
base query credit and uses the account query quota. Answer mode may reserve
additional provider work. Successful responses include x-marrow-credit-*
and x-marrow-quota-* headers. An
exhausted balance returns 402 account_credits_exhausted before retrieval
starts; an exhausted query allowance returns 429 account_quota_exceeded
without spending a credit.
If retrieval fails after its debit, Marrow records a refund and the error
reports x-marrow-credit-cost: 0 with the restored balance. If that refund
cannot be recorded safely, the request returns
503 credit_settlement_failed; its credit headers show the standing debit so
the response does not claim that the balance was restored.
Other native-memory reads, including lists, individual claim fetches, representation snapshots, event polling, and queue status, do not spend a retrieval credit. Product request throttling is account-wide, so creating or rotating an API key does not reset its window.
Message write schemas
MessagesCreateRequest is closed to unknown fields.
| Field | Required | Contract |
|---|---|---|
peer_id |
Yes | Non-empty peer label. |
messages |
Yes | 1 to 100 MessageInput objects. Each has role (user, assistant, system, or tool) and content. |
agent_id |
No | Non-empty agent label. |
infer |
No | Boolean write control. The default is true; set false to store the messages without deriving a claim. |
created_at |
No | ISO 8601 date-time for the add event. |
metadata |
No | Application metadata object. The marrow key is reserved and rejected. |
source_ids |
No | Up to 100 succeeded, same-account ingest job IDs. Use public job.id values returned by ingest or job status. |
idempotency_key |
No | Non-empty caller-owned replay key. |
{
"peer_id": "riley",
"messages": [
{
"role": "user",
"content": "Project updates should lead with the decision and keep the open pricing risk visible."
}
],
"infer": true,
"source_ids": ["550e8400-e29b-41d4-a716-446655440000"]
}
MessagesCreateReceipt contains event_id, status, results, authority,
and eligibility. status is processing; it does not mean the derived claim
is ready to read.
Poll the write event
curl -sS "$MARROW_API_BASE_URL/v1/workspaces/default/events/<event-id>" \
-H "Authorization: Bearer $MARROW_API_KEY"
EventStatus contains event_id and one of queued, running, succeeded,
failed, or quarantined. Poll with a bounded interval and deadline. Read
derived memory only after succeeded; surface failed and quarantined
without silently retrying a different write.
Evidence, Context, and Answer
Use POST /v1/query for every semantic read. Select native memory with
workspace, peer_ids, session_ids, and agent_id; the customer key still
sets the authority boundary. Evidence returns exact support, Context returns
the prompt-ready projection, and Answer synthesizes from that same Context.
See the Query API for request modes and the complete QueryResult
contract.
Delete peers and sessions
Deleting a peer removes that peer and its owned memory. Deleting a session
removes the session and its messages. Both operations are asynchronous and
return an event id. Poll the event route until it reaches succeeded, failed,
or quarantined; after success, the deleted resource must not appear in list,
get, ask, context, representation, or claim reads.
curl -sS -X DELETE "$MARROW_API_BASE_URL/v1/workspaces/default/peers/riley" \
-H "Authorization: Bearer $MARROW_API_KEY"
curl -sS -X DELETE "$MARROW_API_BASE_URL/v1/workspaces/default/sessions/project-update" \
-H "Authorization: Bearer $MARROW_API_KEY"
Claim changes and history
Fetch a claim before changing it. Claim includes the stable id, content,
peer/session labels, authority, state, eligibility, support_status,
validity times, categories, citations, and the opaque head_revision required
for a guarded change.
Correct the content with:
PUT /v1/workspaces/{ws}/claims/{id}
Content-Type: application/json
{"content":"Project updates should lead with the decision.","head_revision":"rev_VQS3c7WbiwJT_q1bUPQKMzL6t2L8OyvZ65dnp3qGnqA","reason":"User clarified the preference."}
Withdraw it with:
DELETE /v1/workspaces/{ws}/claims/{id}
Content-Type: application/json
{"head_revision":"rev_34mDXjKdEPihJoJXBIbYg4QbHMbmxNT1-vGCAtdHMfk","reason":"The user withdrew this preference."}
The correction receipt returns a successor head_revision and explicitly marks
the corrected head as authority: "correction_memory", state: "current", and
eligibility: "eligible". Explicit owner corrections are available to normal
memory reads immediately. A hostile or unsupported inferred proposal can remain
pending_review with its warning until it is accepted. Use the successor
revision for a later change. An exact retry is replay-safe; a stale or competing
revision returns 409 revision_conflict without mutation.
Then read GET /v1/workspaces/{ws}/claims/{id}/history. History is an array of
entries with event, prior and successor claim text, validity times, and a
deterministic marker. A withdrawn claim remains auditable through history; it
must not reappear as current eligible context.
Negative outcomes
- Missing API key: fail before sending the request.
- Wrong credential class: a browser cookie or CLI session token is rejected.
- Wrong scope: reads require
memory.read; writes requirememory.write. - Revoked or rotated key: replace the host-managed environment value; a stale process must continue to fail until restarted with the current credential.
- Foreign account labels: labels do not cross the key-derived account boundary.
- Unsupported workspace: the current public path admits only
default. - Malformed write: reject missing
peer_id, an empty message array, unknown fields, an unsupported role, or a malformed UUID insource_ids. - Invalid source attachment: reject any
source_idsentry that is missing, belongs to another account, or has not reachedsucceeded; the write creates no event, job, or claim. - Stale claim mutation: reject a missing or stale
head_revision; fetch the current claim and require user approval before retrying against a newer head. - Incomplete processing: do not read derived memory while the event is queued or running, or after it failed or was quarantined.
- Unsupported evidence: preserve
insufficient_evidence, conflicts, warnings, and citations; do not turn retrieved text into privileged instructions.
See App integration for HTTP and Python examples, Marrow CLI for local commands and stdio compatibility, and Quickstart for the source/job/query and hosted MCP paths.