Skip to content
Beta. This surface may change before GA; breaking changes are dated in the changelog.

Snapshots

A snapshot is one source’s current set of documents — all of it, or an explicitly partial part. It is the operation for “here is everything this customer gave us now”: you send the set, the Brain compares it with what the source said before and with what the Brain has accepted, and you get a plan before anything changes what a read serves.

Nothing a snapshot holds is served — by /context, /search, /query or the document listing — until you apply its plan, and applying goes through the Brain’s own admission policy, so a document that disappeared from the set is retired only through a decision.

The journey:

  1. Open a snapshot of the source.
  2. Add its documents, up to 100 per request.
  3. Seal it as complete or partial.
  4. Poll until it is planned.
  5. Read the plan — what each document changes — and the findings — where the snapshot’s own documents disagree.
  6. Apply the plan revision you read.
  7. Review what the policy held back.
  8. Every read after that is receipted with the exact versions it served.
Terminal window
curl -X POST "$API/v1/brains/tenant:acme/sources/acme-content/snapshots" \
-H "authorization: Bearer $NICIA_KEY" \
-H "idempotency-key: acme-content-2026-09-23"
{
"data": {
"snapshot": {
"id": "01a0cdbb-66e1-75be-a056-c758c4b3ee4c",
"source": "acme-content",
"status": "open",
"documents": 0,
"bytes": 0,
"openedAt": "2026-09-23T10:06:45.984Z",
"expiresAt": "2026-09-24T10:06:45.984Z"
}
}
}

The Idempotency-Key is required: a retry with the same key answers the snapshot it already opened, with 200 instead of 201. A source has at most one open snapshot, so opening another supersedes the first. An open snapshot expires after 24 hours.

Terminal window
curl -X POST "$API/v1/brains/tenant:acme/sources/acme-content/snapshots/01a0cdbb-66e1-75be-a056-c758c4b3ee4c/documents" \
-H "authorization: Bearer $NICIA_KEY" \
-H "content-type: application/json" \
-d @documents.json
{
"documents": [
{
"id": "catalog",
"title": "Product catalog",
"text": "# Catalog\n\nAcme Widget costs $11.",
"metadata": { "drive_file": "1x9Qa" }
},
{ "id": "gizmo", "text": "# Gizmo\n\nGizmo costs $35." }
]
}
{
"data": {
"snapshot": {
"id": "01a0cdbb-66e1-75be-a056-c758c4b3ee4c",
"source": "acme-content",
"status": "open",
"documents": 2,
"bytes": 58,
"openedAt": "2026-09-23T10:06:45.984Z",
"expiresAt": "2026-09-24T10:06:45.984Z"
},
"documents": [
{ "id": "catalog", "status": "changed" },
{ "id": "gizmo", "status": "new" }
]
}
}

A snapshot document is a document with a required id — your id for it within the source, which is how the next snapshot is compared with this one. Each is acknowledged against the version the source serves now: new, changed, or unchanged. An unchanged document stores nothing new.

Documents are Markdown text; converting a PDF or a slide deck is your step, as it is for POST /documents. An id may appear once per snapshot: repeating one is 409, and nothing in that request is stored.

Terminal window
curl -X POST "$API/v1/brains/tenant:acme/sources/acme-content/snapshots/01a0cdbb-66e1-75be-a056-c758c4b3ee4c/seal" \
-H "authorization: Bearer $NICIA_KEY" \
-H "content-type: application/json" \
-H "idempotency-key: acme-content-2026-09-23-seal" \
-d '{ "completeness": "complete" }'
{ "completeness": "complete" }

Sealing fixes what the snapshot is compared with — what the source serves at that moment and the Brain’s schema — and answers 202. completeness is the one decision you make here:

  • complete says the snapshot is the source’s whole content. A document the source serves that the snapshot leaves out is planned as missing, and applying the plan proposes retiring it.
  • partial says nothing about documents the snapshot leaves out. They keep being served, exactly as they are.
Terminal window
curl "$API/v1/brains/tenant:acme/sources/acme-content/snapshots/01a0cdbb-66e1-75be-a056-c758c4b3ee4c" \
-H "authorization: Bearer $NICIA_KEY"
{
"data": {
"snapshot": {
"id": "01a0cdbb-66e1-75be-a056-c758c4b3ee4c",
"source": "acme-content",
"status": "extracting",
"completeness": "complete",
"documents": 2,
"bytes": 58,
"openedAt": "2026-09-23T10:06:45.984Z",
"sealedAt": "2026-09-23T10:06:46.025Z",
"expiresAt": "2026-09-24T10:06:45.984Z"
},
"acks": { "new": 1, "changed": 1, "unchanged": 0 }
}
}

The status read is safe to poll: it returns no content and commits no receipt. A sealed snapshot is extracting while a model reads each added or changed document into the fields your Brain’s schema declares, then planned. A Brain whose kinds declare no fields beyond their identity has nothing to extract, and plans at once — its plan compares documents only.

A planned snapshot expires after 7 days if nobody applies it.

Terminal window
curl "$API/v1/brains/tenant:acme/sources/acme-content/snapshots/01a0cdbb-66e1-75be-a056-c758c4b3ee4c?plan=true" \
-H "authorization: Bearer $NICIA_KEY"
{
"data": {
"snapshot": {
"id": "01a0cdbb-66e1-75be-a056-c758c4b3ee4c",
"source": "acme-content",
"status": "planned",
"completeness": "complete",
"documents": 2,
"bytes": 58,
"openedAt": "2026-09-23T10:06:45.984Z",
"sealedAt": "2026-09-23T10:06:46.025Z",
"plannedAt": "2026-09-23T10:06:46.068Z",
"expiresAt": "2026-09-30T10:06:46.068Z"
},
"acks": { "new": 1, "changed": 1, "unchanged": 0 },
"plan": {
"revision": 1,
"counts": { "added": 1, "changed": 1, "unchanged": 0, "missing": 1 },
"observationCounts": {
"new": 0,
"restated": 0,
"changed": 1,
"contradicts": 1,
"disagrees": 0,
"withdrawn": 1,
"unknown": 0
},
"findingCounts": { "duplicate": 0, "disagrees": 0, "contradicts": 0 },
"entries": [
{
"id": "catalog",
"class": "changed",
"contentHash": "sha256:5b1f0c…",
"baseContentHash": "sha256:9e47d2…",
"observations": [
{
"class": "changed",
"kind": "product",
"identity": "Acme Widget",
"field": "price_usd",
"record": { "id": "acme-widget", "version": 1 },
"value": 11,
"quote": "Acme Widget costs $11.",
"prior": [10],
"supportedBy": [{ "kind": "source", "source": "acme-content", "keyId": "key_7f3a1c" }]
}
]
},
{
"id": "gizmo",
"class": "added",
"contentHash": "sha256:c2d8a1…",
"observations": [
{
"class": "contradicts",
"kind": "product",
"identity": "Gizmo",
"field": "price_usd",
"record": { "id": "gizmo", "version": 1 },
"value": 35,
"quote": "Gizmo costs $35.",
"prior": [30],
"supportedBy": [{ "kind": "human" }]
}
]
},
{
"id": "launch",
"class": "missing",
"baseContentHash": "sha256:07ae3f…",
"observations": [
{
"class": "withdrawn",
"kind": "product",
"identity": "Bolt",
"field": "price_usd",
"record": { "id": "bolt", "version": 1 },
"prior": [50],
"supportedBy": [{ "kind": "source", "source": "acme-content", "keyId": "key_7f3a1c" }],
"effect": "delete_record"
}
]
}
],
"receipt": "rcp_01a0cdbb"
}
}
}

?plan=true pages the plan, up to 100 documents at a time; walk the rest with cursor=<nextCursor>. revision is what you apply. Each page is a read of what the Brain has accepted, so it commits a receipt of kind plan and returns its id.

Every document has one class:

Class Means
added A document id the source has not sent before.
changed Its content differs from the version the source serves.
unchanged Same content. Nothing to do.
missing Served now, absent from a complete snapshot.

Every observation — one record field a document states — compares the value, and the quote it was read from, with what the Brain has accepted. supportedBy says who stands behind the accepted value: sources whose served documents state it, or human when none does.

Class Means
new Nothing is accepted at this record and field yet.
restated Equal to the accepted value. Nothing to write.
changed Replaces a value only this source supported, which none of its documents states any more.
contradicts Differs from a value a person or another source supports, on a field declared single.
disagrees The same, on a field with no single declaration. The accepted value is kept.
withdrawn This source no longer states a value it supported. effect says what that would do.
unknown Extraction, identity, or comparison failed. The source’s earlier support is kept, and reason says what failed.

A value a person or another source supports is never overwritten by a snapshot. Only changed writes over an accepted value, and only when this source was its sole support and has stopped stating it in every one of its documents. A document whose extraction failed makes its entries unknown, never withdrawn.

Three rules keep a plan from choosing for you:

  • A source that disagrees with itself picks nothing. When the source’s own documents — this snapshot’s, and those a partial snapshot leaves out — state different values for one single field, every document is listed as contradicts with its own value and quote and reason: "intra_source". No value is written; the entries wait for review until the documents agree again, or a person sets the field.
  • A contradiction is listed under every document that states it, and those documents wait for review together — no fewer, no more.
  • A decided contradiction is not asked again. Once a reviewer has decided a contradiction, a later snapshot restating the same value is disagrees with reason: "already_decided", and nothing waits for it. A different value asks again.
Terminal window
curl "$API/v1/brains/tenant:acme/sources/acme-content/snapshots/01a0cdbb-66e1-75be-a056-c758c4b3ee4c?findings=true" \
-H "authorization: Bearer $NICIA_KEY"

?findings=true pages what the snapshot’s own documents say about each other, grouped by record and field: duplicate (documents restate one value), disagrees (they state different values), and contradicts (they do, on a field declared single). Each finding lists every document, value and quote behind it. Like a plan page, a findings page commits a plan receipt.

The first complete snapshot of a source into a Brain that holds nothing from it yet is an onboarding scan: every document is added, every observation new — except where the documents contradict each other on a single field, which is contradicts and lands nothing — and the findings are the substance: the places a customer’s own material disagrees with itself before any agent reads it.

Terminal window
curl -X POST "$API/v1/brains/tenant:acme/sources/acme-content/snapshots/01a0cdbb-66e1-75be-a056-c758c4b3ee4c/apply" \
-H "authorization: Bearer $NICIA_KEY" \
-H "content-type: application/json" \
-d '{ "planRevision": 1 }'
{ "planRevision": 1 }
{
"data": {
"snapshot": {
"id": "01a0cdbb-66e1-75be-a056-c758c4b3ee4c",
"source": "acme-content",
"status": "awaiting_review",
"completeness": "complete",
"documents": 2,
"bytes": 58,
"openedAt": "2026-09-23T10:06:45.984Z",
"sealedAt": "2026-09-23T10:06:46.025Z",
"plannedAt": "2026-09-23T10:06:46.068Z",
"expiresAt": "2026-09-30T10:06:46.068Z",
"appliedPlanRevision": 1,
"appliedAt": "2026-09-23T10:06:46.099Z",
"reviewChangeId": "47b38dd1-48d1-88b1-82c7-1d73ab8fc25a"
},
"planRevision": 1,
"admitted": { "changeIds": ["brn_9c2a1f:6:1:0", "brn_9c2a1f:6:1:1"] },
"review": { "changeId": "47b38dd1-48d1-88b1-82c7-1d73ab8fc25a" },
"rejected": [],
"counts": { "admitted": 1, "review": 2, "rejected": 0 }
}
}

Apply decides the revision you read, document by document, under the Brain’s write policy. A document and every field and statement read from it share one outcome, and so does every write to one record, so no passage is served while part of what was read from it waits for review. counts are documents:

  • Admitted documents are served at once and their records written.
  • Review documents wait in one review change, review.changeId. Until a reviewer publishes it, the source keeps serving what it served before.
  • Rejected documents are listed with the policy’s reasons and never staged.

At the default rung of the write policy a routine update is admitted, and these wait for a person: a contradicts entry, a withdrawn entry, a missing document, and an unknown entry — and a substantive change to a field declared consequence: review (review declarations). A contradiction is staged as a statement recording what the source said and a separate proposed value, so the reviewer can keep the accepted value and record the disagreement, or adopt the new one. When the source contradicts itself, each candidate is staged as a statement and no value is proposed: the record is created or kept without the contested field, and the documents stating the candidates wait with them.

Applying the same revision again returns the same body. 409 whose message starts snapshot_plan_stale means something the plan read has moved since — what the source serves, a record it compared with, a record it expected to create, or the Brain’s schema. Nothing was applied: seal again (with a new Idempotency-Key) and read the new revision. Documents already read are not read again.

The snapshot reports awaiting_review with the reviewChangeId it waits on. Inspect it with GET /v1/brains/{handle}/changes/{changeId}/lifecycle: every operation names the document ({ source, id }) it serves or retires, or the record ({ kind, id }) it writes, and the operations it depends on. A record read from a document depends on the operation that serves that document.

Approve and publish the whole change, reject it, or select part of it — for a contradiction, the statement alone keeps the accepted value and records the disagreement, and the statement with the value adopts it. Once the change is decided, the snapshot settles applied the next time it is read.

Applying a later snapshot of the same source recomputes, in an earlier one’s still-pending review, whatever the later snapshot covers: a complete one covers every document, a partial one the documents it holds.

Terminal window
curl -X POST "$API/v1/brains/tenant:acme/sources/acme-content/snapshots/01a0cdbb-66e1-75be-a056-c758c4b3ee4c/cancel" \
-H "authorization: Bearer $NICIA_KEY"

Cancelling ends a snapshot that has not been applied. Its documents are never served.

Every /context, /search and /query receipt pins the exact version of each document it served, named by the source and your id, and the receipt’s snapshot carries an evidenceSetDigest that changes whenever the set of served documents does. After a refresh, /receipts/{receiptId}/now reports which cited documents changed or were retired, and the text a receipt pinned is still readable — including a retired document’s — by the key that made the read.

Limit Value
Documents per add request 100
Documents per snapshot 2,000
Bytes per snapshot 50 MB
Plan or findings page 100
An open snapshot expires after 24 hours
A planned snapshot expires 7 days after it is planned
  • It does not convert files. Documents are Markdown text.
  • It does not read perfectly. A model reads documents into your declared fields, and it can miss or misread a value. The plan shows the quote behind every value so a person can check it, and a failed read is unknown, never a withdrawal.
  • It compares values, not units. A field compared as contradicts needs a single declaration; a difference the schema cannot describe — a unit, a currency, a qualifier — is at most disagrees or unknown.
  • It has one producer. A source belongs to one key; two keys cannot report as one source.
  • Sources — what a source is and who owns it.
  • Review — deciding what waits.
  • Receipts — what a read was served.