Every error — validation, auth, domain — is an
RFC 7807 problem document
(application/problem+json) whose detail is always one plain-language
sentence:
Render detail to humans; branch on status and errors[].field in code.
Status
When
Notes
400
a value is unusable
malformed uri, non-IRI theme, unknown expand path — detail says what to send instead
401
missing credentials
no X-API-Key; on /keys, no bearer token
403
wrong credentials
invalid/revoked key, or a key not authorized for the requested namespace
404
unknown resource
entity, capsule, or namespace (namespaces are never lazily created)
422
body missing/mistypes a field
errors[] lists every offending field by name
The one exception is deliberate: POST /capsules accepts with 202 and
reports validation problems asynchronously in the capsule’s status — poll
GET /capsules/{id}.
Organizations cannot be updated or deleted via CRUD — outcomes and
indicators support PUT and DELETE; organizations do not yet. Capsule
rollback removes capsule-sourced org data as normal.
Entity identity is the exact IRI — the same organization under two
IRIs is two organizations; agree on one IRI per entity across intake
paths (details).
Fund identity is exact-string matching on sff:forFunder.
Namespace export of CRUD-created reports uses Graph Cast’s compact
vocabulary rather than the full i72:Measure structure;
capsule-ingested reports export in official CIDS form.
Aggregation is client-side for now — rows are denormalized to make
that trivial; server-side rollups are on the roadmap.