GET /v1/jobs/{job_id}.
200 application/json
What it is
Job, the unit of work an ingest becomes (in practice, the id you poll to find out what your content turned into, not merely whether the upload landed). Warm layer, a part of the cognitive state that the background cycle fills in after ingestion (in practice, domains, phases, the identity manifold and the insight queue: each one appears on its own schedule and is empty until it does). Tombstone, a node that has been forgotten but whose shell is kept for a 30-day window (in practice, the node’s text is erased immediately and irreversibly while its position in the graph stays restorable). Most memory APIs can add. Fewer can revise without losing the old version. Very few can forget in a way that survives a privacy audit, because forgetting properly means erasing the retrievable text rather than hiding a row. Exo separates those three verbs and gives each one its own semantics.The two clocks
The fast clock finishes in one job. The slow clock runs on its own schedule over the whole graph, which is why the recall views can be empty for a while after a successful ingest. Nothing is wrong: the content is retrievable, the discovered structure is not built yet.Stage by stage
1. Ingest
POST /v1/ingest takes text and returns 202 with a jobId. POST /v1/import takes a file the same way. Both are accept-then-work: nothing is embedded inside the request.
Send an Idempotency-Key header and a retry returns the original jobId rather than a second copy of the content. See Idempotency.
2. Poll
GET /v1/ingest/{job_id}/status gives progress while it runs (status, phase, percent, completedSteps). GET /v1/jobs/{job_id} gives the finished interpretation: what the content became in the graph. Poll the first for a progress bar and read the second for the result.
status moves through pending, running, then a terminal value. Treat it as a string rather than a closed set, so a future internal status does not break your reader.
3. Warm
The background cycle fills in the discovered layers. Watch them by reading the recall views rather than by waiting a fixed interval:GET /v1/recall/{recall_type} returns empty collections until a layer exists, and populated ones once it does. Insights, phases and the manifold each say what their own layer needs before it can appear.
4. Edit
PATCH /v1/graph/nodes/{node_id} changes a node in place. Setting content re-embeds it. metadata merges into the node’s frontmatter, and title replaces the title. Use this when the stored text was wrong. Use supersession instead when the text was right at the time and the person has since changed their mind.
5. Supersede
POST /v1/graph/nodes/{node_id}/supersede records that one belief replaced another, keeps both, and moves the authority. This is the default verb for a wrong belief. Belief and supersession covers it in full.
6. Forget
DELETE /v1/graph/nodes/{node_id} is the erasure verb, and it does two separate things.
200 application/json
POST /v1/retrieve and POST /v1/search rather than merely hidden behind a filter. Graph reads, recall, retrieve and brain training all filter the tombstone, so a forgotten node stops surfacing everywhere at once.
Forgetting needs the memory:forget scope. A write key qualifies; graph:write alone does not, so a key minted for an integration that edits the graph cannot destroy content. See Scopes.
7. Undelete
POST /v1/graph/nodes/{node_id}/undelete restores a node inside the 30-day window.
200 application/json
contentRestored is always false. That is not a bug and not a degraded mode: forget deleted the text, and nothing can undo that. What comes back is the node’s graph position, title, metadata and authority. The restored node is visible and linkable but contributes no retrievable text until you write new content into it with PATCH.
8. Purge
POST /v1/purge is the two-phase administrative erase for a whole subject or a whole org. Phase one is a dry run that counts the exact impact and mints a confirmToken. Phase two spends the token and reports the rows it actually deleted, under the same keys. DELETE /v1/subjects/{subject_id} is the narrower path for one end user, and DELETE /v1/me tears down the account.
How to use it
Ingest, then poll until the job settles.job.completed arrives on GET /v1/events and on webhooks. See Reacting to change.
Details worth knowing
Why my retrieve works but every recall view is empty
Why my retrieve works but every recall view is empty
Ingestion and the cognition cycle are separate clocks. Ingestion makes content retrievable. The cycle builds the discovered layers, and each layer has its own preconditions: phases need enough dated content to cluster, the manifold needs enough identity signals to decompose, insights need pairs of high-authority nodes that are related but not already linked. Empty is the honest answer for a layer that does not exist yet, and it is why the recall views return empty collections rather than an error.
Why undelete does not bring the text back
Why undelete does not bring the text back
Because a forget that could be undone is not an erasure. If the text were merely hidden it would still be sitting in the store, and a privacy request would not actually be satisfied. Exo erases the chunks at forget time and keeps only the shell, so
contentRestored is false by construction. If you want a reversible hide, do not use forget: patch the node, or supersede it.What happens after the 30 days
What happens after the 30 days
The tombstone is physically purged. Past the window,
undelete returns exactly the same 404 as a node that never existed, whether or not the collector has removed the row yet, so the contract does not leak the difference between “gone” and “about to be gone”.Whether re-running a delete or an undelete is safe
Whether re-running a delete or an undelete is safe
Both are idempotent. Re-deleting an already-tombstoned node is a no-op success. Undeleting a node that is not tombstoned returns
restored: false and changes nothing, so a retried call after a network timeout never surprises you.What an ingest failure looks like
What an ingest failure looks like
The job reaches
status: "failed" with a human-readable error, and result stays null. A corrupt file or an embedding failure is terminal rather than retried forever. Cancel a job that has not started yet with POST /v1/jobs/{job_id}/cancel; a job already running returns job_not_cancelable.Limits
- Edges removed around a node when it was forgotten stay removed. Undelete restores the node, not its former neighbourhood.
PATCHwithcontentcollapses the node to a single chunk. Splitting long content into multiple chunks is the ingest pipeline’s job, so send large replacements as a new ingest.- Forgetting a node does not retrain the org’s ExoBrain. The brain marks itself stale and retrieval says so through
degradationReason. See Brain path and hybrid path. - There is no bulk forget. Erasing everything for one end user is
DELETE /v1/subjects/{subject_id}; everything else is node by node.
Next
Belief and supersession
The verb to reach for when the content was right and the person changed their mind.
Forgetting and portability
The task guide: tombstones, the GDPR path, the purge ceremony and export.