API reference

REST surface for Sankofa — ingestion, decisions, exposures, and per-product management. Auth via x-api-key for ingestion, Authorization Bearer JWT for dashboard / management.

The Sankofa API is the wire that every SDK is implemented against. If your platform doesn't have an SDK, or if you need direct control (server-to-server flows, custom pipelines, mainframes), you call the API directly.

This section is the canonical reference. Each page documents one endpoint or one cross-cutting concern. The pages map 1:1 to the engine's HTTP handlers — when something on this site says "POST /api/v1/track returns 200 + commands array," it's because the handler at cmd/sankofa/ingest_handlers.go:49 does exactly that.

Base URL

Endpoint typeURLUsed by
Productionhttps://api.sankofa.devLive + test ingestion, decisions, dashboard / management API
Region-pinned (Enterprise)Routed at the ingress layer; same URL — region selection happens at API-key resolutionEnterprise customers with data-residency requirements

There are no region-suffixed URLs. Regional projects use the same base URL; the ingress layer routes by API key.

Authentication at a glance

Two auth schemes, used by different endpoint groups:

EndpointsAuthHeader
Ingestion (/api/v1/{track,people,alias,batch})Project API keyx-api-key: sk_live_… (or sk_test_…)
Decision handshake, Switch / Config / Pulse / Catch reads from SDKsProject API keyx-api-key: sk_live_… (or sk_test_…)
Dashboard / management API (CRUD on flags, configs, surveys, projects, members, etc.)User JWTAuthorization: Bearer <jwt>
Deploy operations (release, patch, etc.)Deploy tokenAuthorization: Bearer sk_deploy_…

Full details on each scheme + key types: Authentication.

Environments

The engine resolves environment (live vs test) from the API key on every request. There's no environment header, no project ID in the URL — the key alone determines routing:

  • sk_live_…live environment of the matching project
  • sk_test_…test environment of the matching project

This means: the same code path works for dev and prod; you just use a different key. See Environments and API keys.

Response format

Every endpoint returns JSON. The shape varies by endpoint, but two conventions hold across all of them:

Successful responses

Most endpoints return:

JSON
{
"ok": true,
"...": "endpoint-specific fields"
}

Specific ingestion endpoints add fields like commands (heatmap self-healing hints) or events_received (batch counts).

Error responses

Every error follows the same shape:

JSON
{
"ok": false,
"error": "Human-readable message"
}

The HTTP status code carries the type of failure; the error field carries the message. There's no machine-readable error code today — match on HTTP status.

Full status-code table + common messages: Errors.

Rate limits

Ingestion endpoints (per API key, or per IP if no key):

  • 500 requests per minute
  • Returns 429 Too Many Requests with {ok: false, error: "Rate limit exceeded. Please wait a moment."}
  • No Retry-After or X-RateLimit-* headers — back off client-side

Full details: Rate limits.

Endpoint groups

Per-product endpoints

These endpoints exist and are partially documented in the SDK pages but don't yet have their own dedicated reference pages — they'll get full coverage in a follow-up phase:

  • Decision handshakeGET /api/v1/handshake (called by every client SDK on session start; carries Switch + Config + Deploy + Catch + Analytics)
  • SwitchGET/POST/PUT/DELETE /api/v1/switch/flags/..., POST /api/switch/halt-webhook, POST /api/switch/exposures
  • ConfigGET/POST/PUT/DELETE /api/v1/config/items/...
  • PulseGET/POST /api/v1/pulse/surveys/...
  • DeployPOST /api/deploy/check, /api/deploy/report, /api/v1/deploy/releases/...
  • CatchPOST /api/catch/{events,transactions,vitals,profiles}, GET /api/v1/catch/issues, POST /api/v1/catch/symbols (upload)
  • VisionGET/POST /api/v1/vision/{boards,pages,roadmap,okr,initiatives,docs,...} (full surface listed in Vision overview)
  • PlanGET/POST /api/v1/plan/{boards,tickets,sprints,releases,workflows,pages,...} (full surface listed in Plan overview)

Versioning

The wire is versioned via the URL prefix — /api/v1/.... We have not broken v1 since launch and we don't intend to. When we eventually need an incompatible wire change, we'll ship v2 alongside v1 and run both for at least 18 months. See SDK versioning policy — the same rules apply to the engine.

What's next

Edit this page on GitHub