recall · Getting started · SDKs
Everything the app does, your agents can do. This page is the surface a customer integrates against: reading memory, writing to it, shipping conversations, and settling what conflicts. Workspace administration, billing and platform operations are not listed and are not part of the supported surface.
Every path below is under /api on your workspace's host. Send a key as a bearer token:
curl https://<your host>/api/buckets \ -H "Authorization: Bearer rk_..."
An agent key (rk_…) is bound to one workspace and carries a ceiling it can never exceed. A user token also needs the workspace slug as X-Tenant: acme, because a person may belong to several. Make and revoke keys under Developers → Keys; a key can be read-only. Every call is answered under the caller's access to that space, so a record outside your scope is not there rather than refused.
Errors are JSON: {"detail": "..."} with the ordinary status codes. A refusal explains itself in words.
| Call | What it answers |
|---|---|
GET /buckets/{id}/context?task= | Everything worth reading before a task, under one character budget: the brief for the subject, the records that bear on it with their reasons, open contradictions, and quotes from sources. text is ready to paste into a prompt. |
GET /context?task= | The same across every space you can reach. Each hit names its space. |
GET /buckets/{id}/brief | The context for a session: who this is, the facets in play, what matters, what changed lately. |
GET /buckets/{id}/search?q= | Search. deep=1 spreads over the graph, so the lesson behind a decision is reached by a link rather than a keyword. as_of= answers from what was valid on a date. |
GET /buckets/{id}/memory?type=&title= | One record in full. By query, because a title is free text and may carry a slash. |
GET /buckets/{id}/memory/expand?type=&title= | What this record links to, and the edge that links them. |
POST /buckets/{id}/plan-check | What memory knows before you act: prior decisions, the constraints in force, and any recorded contradiction among them. Advisory — it hides nothing and ranks nothing away. |
GET /buckets/{id}/timeline | What was recorded, in the order it happened. |
| Call | What it does |
|---|---|
POST /buckets/{id}/memories | Save a record. Reusing a title updates it; supersedes retires another and links the two. A Decision needs a reason — the shape gate refuses one without. A Constraint may only be written by a person. |
POST /buckets/{id}/ingest | Ship a conversation for extraction. Returns a job; poll GET /ingest/{job_id}. The text is read, resolved against what is stored, filed by charter, and discarded. |
PUT /buckets/{id}/memories/{type}/{title}/outcome | How a decision turned out: held, reversed, regret. This is what makes a decision judgeable later rather than merely stored. |
POST /buckets/{id}/memories/{type}/{title}/forget | Stop recalling a record and scrub its text. The title and its edges stay as a tombstone — nothing is deleted. |
POST /buckets/{id}/memories/move | Re-home a record: it leaves this space. |
POST /buckets/{id}/memories/promote | COPY a record into another space with provenance both ways. The original stays. A Constraint is refused: a boundary is imposed where it applies, not copied. |
POST /route | Where each of these would be filed, by charter, without saving anything. |
When two records disagree, recall does not pick a winner. It records the pair and puts it in front of somebody.
GET /buckets/{id}/contradictions | Every recorded pair, both sides naming their author, and whoever it is assigned to. |
POST /buckets/{id}/contradictions/assign | Ask one person to settle it. Without a user_id it goes to the author of the newer record. |
POST /buckets/{id}/contradictions/resolve | keep_a, keep_b, both (each gains the condition under which it holds) or dismiss. |
GET /buckets/{id}/constraints | The rules in force: own set here, inherited from the workspace. Any reader sees both; may_steward says whether you may add or lift one. |
POST /buckets/{id}/constraints/{title}/lift | Lift a rule, with a reason. Takes an owner, an admin, or administer on the space, and is audited. |
A rule is written through the ordinary save with type: "Constraint" and an imposed_by. An agent cannot write one, and only a rule from the same person can replace it — that is enforced on the server, not asked for in a prompt.
GET /buckets | The spaces you reach, with your capability on each. |
GET /buckets/{id}/export?format= | json, md, zip or ndjson. Only ndjson pages to the end and closes with a line saying it is complete; the others stop at a cap and report truncated. |
GET /buckets/{id}/analytics?days= | What is used, what it cost, and how the resolver settled what it was told. |
GET /tenant/vocabulary | The types, edges, areas and tiers this workspace accepts. Served as data, never as a tool-schema enum, so every client sees the same tools. |
GET /tenant/events is the feed, newest first, with a cursor — poll it, or register a URL with POST /tenant/webhooks. The secret is shown once; every delivery carries X-Recall-Signature, a SHA-256 HMAC of the body. The SDKs ship verify_signature; check it before trusting a delivery.
A page of the feed can be empty and still not be the end: what may be returned is decided per event, so a page can be spent entirely on events you may not read. Follow the cursor until exhausted, which is what the SDK helpers do.
Point a harness's base URL at /proxy/v1/chat/completions (OpenAI shape) or /proxy/v1/messages (Anthropic shape) and it has memory: the brief goes in, the turn is captured on the way out, and nothing else about the request changes. Ask about entitlement — it is off unless your workspace has it.
Or connect over MCP at https://<your host>/mcp, which is the same surface as a set of tools. See Getting started.
Python and TypeScript clients wrap all of the above, including the cursor-following event helpers and signature verification. See SDKs. Try any call first in Developers → Playground.