API
Bearer authentication, scopes, idempotency, rate limits, and pagination for the public REST API.
Authentication and scopes
Create scoped API keys from Dashboard → Settings → Developer → API keys. Raw keys are shown once at creation or rotation and are never recoverable afterward.
Send the key as `Authorization: Bearer <key>` — keys are never accepted as a query parameter.
Each key is granted an explicit list of scopes (e.g. projects:read, images:upload, metadata:generate, exports:create) from a fixed allow-list; requests missing a required scope fail with API_KEY_SCOPE_INSUFFICIENT.
Keys are bound to exactly one workspace (personal or a single organization) and can never reach another workspace's data.
Idempotency
Every write (POST) request requires an `Idempotency-Key` header (8-128 chars).
Retrying the same key replays the original response byte-for-byte; reusing a key with a different request body is rejected.
Long-running operations (processing jobs, AI metadata generation, exports) respond 202 Accepted and continue asynchronously via background workers — poll the returned resource to see completion.
Rate limits and pagination
Each API key has a per-minute request limit determined by the workspace's plan; exceeding it returns API_RATE_LIMITED with a 429 status.
List endpoints are cursor-paginated: pass the opaque `cursor` value from a response's `meta.nextCursor` to fetch the next page. Cursors are signed and bound to the issuing key's workspace.
Every response is a JSON envelope with `ok`, `data`, an optional `meta`, and a `requestId` for support correlation.
Reference
The full OpenAPI 3.1 document for every implemented route is served at /api/v1/openapi.
See the Webhooks documentation for outbound event notifications and signature verification.