Skip to content

Errors & endpoint reference

Every error — validation, auth, domain — is an RFC 7807 problem document (application/problem+json) whose detail is always one plain-language sentence:

{"type": "about:blank", "title": "Validation Error", "status": 422,
"detail": "Invalid request: body.uri: Field required.",
"errors": [{"field": "body.uri", "message": "Field required", "type": "missing"}]}

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}.

Header Required on Value
X-API-Key every data endpoint your API key (minted in the console under API → Settings)
X-Namespace every data endpoint except /namespaces target namespace slug — explicit, no default

Key management (/keys) is used by the console and authenticates with your Common Approach account (Firebase bearer token), not an API key.

Method Path Notes
POST /namespaces {"namespace", "label?"} → 201; idempotent
GET /namespaces list this tenant’s namespaces
DELETE /namespaces/{ns}?confirm={ns} drops all data in the namespace; confirmation required → 200 with graphs_dropped count
Method Path Notes
POST /orgs {"uri", "name", "description?"} → 201
GET /orgs list
GET /orgs/{id} add ?expand= for a tree read
GET /orgs/{id}/everything full theory-of-change tree
GET /orgs/{id}/export?format=jsonld|nquads that organization’s subgraph
Method Path Notes
POST /orgs/{org}/outcomes {"uri", "name", "description?", "themes?": [IRI]} → 201
GET /orgs/{org}/outcomes · /orgs/{org}/outcomes/{id}
PUT /orgs/{org}/outcomes/{id} properties only — no uri; identity never changes
DELETE /orgs/{org}/outcomes/{id} → 204
Method Path Notes
POST /orgs/{org}/indicators {"uri", "name", "description?", "unit?", "outcome_id?"} → 201 — set outcome_id so reports roll up to themes
GET /orgs/{org}/indicators · /orgs/{org}/indicators/{id}
PUT /orgs/{org}/indicators/{id} properties only — no uri
DELETE /orgs/{org}/indicators/{id} → 204
Method Path Notes
POST /indicators/{id}/reports {"uri", "value", "unit?", "period_start", "period_end"} → 201; same uri again replaces the value
GET /indicators/{id}/reports every report carries value (decimal or null) + value_text (verbatim string)
Method Path Notes
POST /capsules raw JSON-LD body ≤ 10 MiB → 202 {capsule_id, status}
GET /capsules · /capsules/{id} list / status + plain-language validation report
DELETE /capsules/{id} atomic rollback of everything that capsule asserted → 204
Method Path Notes
GET /rows/indicator-reports filters: theme, fund, org, period[from], period[to]; cursor pagination
GET /rows/themes · /rows/funds facets with counts — filter-picker feeds
GET /export?format=jsonld|nquads whole namespace as CIDS
Method Path Notes
GET /healthz unauthenticated liveness check
GET /docs interactive OpenAPI documentation
  • 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.