Backend API, API keys, introspection
Server-to-server surface for first-party relying parties. The REST part is a subset of the Clerk Backend API (2026-08-20); token checks use the OAuth standards. Anything without a Clerk or Auth0 equivalent lives in GraphQL.
Enabling a client
Two GraphQL mutations on manage { client(clientId: ...) { ... } }, both on the client settings page:
setAllOrganizations(enabled: Boolean!)-
Admin only ("All organizations (first-party)" section). Eligible organizations of a user are all of their memberships. No per-organization client access (
oauth_client_organizations), no organization consent, no access-management screen;prompt=consentdoes not show it either. Covers the authorize flow, theorgsclaim, refresh re-checks and the account pages. Useorganization_usage=noneplus theorganizationsscope for a silentorgslist. setBackendApi(enabled: Boolean!)-
Anyone who can manage the client (owner, or
org:clientsfor organization clients; "Backend API" section). Enables the REST API below for this client's secret, which then acts for every user who authorized the client. Requires a confidential client with a client secret andsubject_type=public,subject_scope=global(sosubis theU...user id). Checked when enabled and on every request.
Backend REST API
Base <root>/api/v1, so a Clerk SDK works with apiUrl = <root>/api. Auth: Authorization: Bearer <client secret>.
Pagination limit/offset → {"data": [...], "total_count": n}. Timestamps are unix milliseconds. Errors:
{"errors": [{"message", "long_message", "code"}]} with authentication_invalid (401), authorization_invalid
(403), resource_not_found (404), bad_request (400), form_param_format_invalid / form_param_missing /
form_identifier_exists (422), too_many_keys (409).
Visibility
Invisible users, organizations and keys are 404.
| Regular client | allOrganizations client |
|
|---|---|---|
Users |
consented to the client (any identity or audience scope) |
consented, or a member of any organization |
Organizations ( |
enabled the client ( |
all |
Memberships of a user |
eligible and granted to the client by that user (normal organization access) |
all memberships |
|
|
|
Organization API keys |
organization visible; |
same, every membership counts as granted |
| Endpoint | Notes |
|---|---|
|
Clerk |
|
Memberships granted to this client |
|
|
|
id or slug |
|
|
|
|
|
|
|
|
|
|
|
|
Organization API keys need created_by with the org:api-keys organization permission (granted to
role:org-admin). User API keys may only be created by their subject (or without created_by).
Differences from Clerk
-
Ids are pykrete ids: users
U..., organizationsO..., API keysK...(letter + 32 alphanumerics), notuser_/org_/ak_. Clerk's OpenAPI patterns reject them; the SDKs do not check. -
API key secrets are
DELTA-API-KEY-<48 alphanumerics>and only their SHA-256 is stored, soGET /api_keys/{id}/secretis not offered. -
A member can hold several pykrete roles:
roleis the primary one (role:org-admin, elserole:org-member, else the first),permissionsis the union oforg:*permissions of all of them. -
Userlacks phone numbers, wallets, external accounts and sign-in timestamps (empty or null). Email ids (E...) and membership ids (M...) are derived hashes.Organization.updated_atequalscreated_at. -
Keys are bound to the client that created them; other clients see them as nonexistent.
Introspection and revocation
POST /oauth/introspect (RFC 7662) and POST /oauth/revoke (RFC 7009), advertised in discovery. Client
authentication: HTTP Basic (form-urlencoded id and secret, RFC 6749 2.3.1) or client_id/client_secret in the
body; the client must be confidential. Body: token, token_type_hint?, form or JSON.
Only tokens issued to the calling client are reported; everything else is exactly {"active": false}.
API key:
{"active": true, "kind": "api_key", "token_type": "Bearer", "iss": "<issuer>",
"client_id": "C...", "api_key_id": "K...", "name": "...", "scope": "a b",
"sub": "U..." | "org_id": "O...", "created_by": "U...", "claims": {...},
"iat": 1700000000, "exp": 1700003600}
Access token: kind: "access_token", iss, client_id, sub, scope, aud (string for one audience, else
array), iat, exp, org_id and org_roles when an organization was active. Times are unix seconds.
Revocation always answers 200: API keys are soft-revoked, access tokens deleted (with their refresh token), refresh tokens revoke their chain.