Statements
A statement records what one connected source reported about a subject.
The authenticated key supplies source identity; the request cannot impersonate
another source. sourceKey is optional and identifies a stable row or field inside
that source. Writing a statement does not promote it to curated Brain truth.
Use POST /v1/brains/{handle}/statements to report one.
curl -X POST "$API/v1/brains/tenant:acme/statements" \ -H "authorization: Bearer $NICIA_KEY" \ -H "content-type: application/json" \ -H "idempotency-key: stmt-salesforce-arr" \ -d '{ "subject": "acme", "predicate": "contract_value_usd", "value": 120000, "sourceKey": "salesforce-renewal" }'{ "data": { "statementIds": ["stmt_91ab01"], "outcome": { "kind": "admitted", "batchId": "batch_44a1e0", "policyVersionId": "pol_nicia_open", "acceptedSnapshot": "snap_6f1e4d6b", "changeIds": ["brn_9c2a1f:12:0:0"] }, "statements": [ { "id": "stmt_91ab01", "subject": "acme", "predicate": "contract_value_usd", "value": 120000, "validFrom": "2026-08-14T09:20:00.000Z", "sourceKey": "salesforce-renewal", "assertedBy": { "kind": "service", "id": "key_7f3a1c" }, "status": "active" } ] }}The returned source is the server-bound producer identity. Credential
rotation preserves it. assertedBy is projected from the accepted change; callers
cannot set either field.
A statement without sourceKey is valid when the producer has no durable row key:
curl -X POST "$API/v1/brains/tenant:acme/statements" \ -H "authorization: Bearer $NICIA_KEY" \ -H "content-type: application/json" \ -H "idempotency-key: stmt-handbook-pto" \ -d '{ "subject": "acme", "predicate": "pto_starts_on", "value": "day-one", }'A statement can cite the document it was read from, exactly as a
record write does: evidence names a
document the Brain holds, a quote that must occur in its current version, and
your own locator. The citation grounds the statement only, not the subject it
is about. Add an anchor (§ <heading> or L12-L14) to rest the statement on
a part of the document; the Brain resolves it, and a
standing answer that
depends on the statement is then monitored.
{ "subject": "sunfield", "predicate": "migratory_route", "value": "Pacific Flyway", "evidence": [ { "document": { "id": "environmental-report" }, "quote": "within the Pacific Flyway", "locator": { "page": 14 } } ]}Sources disagree
Section titled “Sources disagree”A later report for the same source stream supersedes. Another stream or source
disagreeing over an overlapping window does not: both statements stay, and the
next /context names it. You do not call GET /findings to find out. That
list is the operator inbox.
curl -X POST "$API/v1/brains/tenant:acme/statements" \ -H "authorization: Bearer $NICIA_KEY" \ -H "content-type: application/json" \ -H "idempotency-key: stmt-netsuite-arr" \ -d '{ "subject": "acme", "predicate": "contract_value_usd", "value": 145000, "sourceKey": "netsuite-renewal" }'curl -X POST "$API/v1/brains/tenant:acme/context" \ -H "authorization: Bearer $NICIA_KEY" \ -H "content-type: application/json" \ -d '{ "prompt": "What is the Acme contract value?", "maxTokens": 2000, "format": "items" }'{ "data": { "text": "", "citations": [], "items": [ { "kind": "record", "id": "stmt-salesforce-arr", "fields": { "contract_value_usd": 120000 }, "status": "contested" }, { "kind": "record", "id": "stmt-netsuite-arr", "fields": { "contract_value_usd": 145000 }, "status": "contested" } ], "staged": 0, "warnings": [ { "kind": "contested", "subject": "acme", "predicate": "contract_value_usd", "count": 2, "detail": "Two sources disagree about acme.contract_value_usd." } ], "receipt": "rcp_contested", "truncated": false }}warnings[] kind contested names the subject and predicate. Per-item
status: "contested" marks the statements in this answer. There is no
conflicts[] field on /context.
Resolve
Section titled “Resolve”GET /findings is the inbox. POST /v1/brains/{handle}/findings/{findingId}/decide
keeps one statement or writes a corrected value. The loser is retained, not
deleted. The call needs review and an Idempotency-Key.
curl "$API/v1/brains/tenant:acme/findings?resolved=false" \ -H "authorization: Bearer $NICIA_KEY"{ "data": { "findings": [ { "id": "fnd_91ab", "subject": "acme", "predicate": "contract_value_usd", "statements": [ { "id": "stmt_91ab01", "subject": "acme", "predicate": "contract_value_usd", "value": 120000, "validFrom": "2026-08-14T09:20:00.000Z", "sourceKey": "salesforce-renewal", "assertedBy": { "kind": "service", "id": "key_7f3a1c" }, "status": "conflicted" }, { "id": "stmt_91ab02", "subject": "acme", "predicate": "contract_value_usd", "value": 145000, "validFrom": "2026-08-14T09:21:00.000Z", "sourceKey": "netsuite-renewal", "assertedBy": { "kind": "service", "id": "key_7f3a1c" }, "status": "conflicted" } ], "detectedAt": "2026-08-14T09:21:01.000Z", "classification": "contradiction", "coverage": "complete", "reasons": ["declared-single-value-conflict"], "supportFingerprint": "sha256:finding-support", "analysisAsOf": "2026-08-14T09:21:01.000Z" } ], "receipt": "rcp_findings" }}curl -X POST "$API/v1/brains/tenant:acme/findings/fnd_91ab/decide" \ -H "authorization: Bearer $NICIA_KEY" \ -H "content-type: application/json" \ -H "idempotency-key: resolve-acme-arr" \ -d '{ "keep": "stmt_91ab02", "reviewedReceipt": "rcp_findings", "reviewedFingerprint": "sha256:finding-support" }'{ "data": { "outcome": { "kind": "admitted", "batchId": "batch_91ab03", "policyVersionId": "pol_nicia_open", "acceptedSnapshot": "snap_91ab03", "changeIds": ["brn_9c2a1f:15:0:0"] } }}Or send "value": 145000 instead of keep to supersede both with a
corrected number.