Skip to content
Talk to our solutions team

HTTP API

Every route requires the four CPET headers (X-Customer, X-Product, X-Env, X-Tenant). The error envelope is uniform: {"error": "...", "code": "..."}. Auth-flow endpoints are rate-limited per (tenant, caller IP) → 429 + Retry-After. Request bodies are capped at 1 MiB.

Auth flows (unauthenticated — they are the auth surface)

Section titled “Auth flows (unauthenticated — they are the auth surface)”
Method + PathRequest → Response
POST /auth/login{identity, password, identity_type?, realm?}{token, refresh_token, expires_in, user}. MFA-enabled → {mfa_required: true, mfa_token, methods}. Managed tenants → {session_id, expires_at} + kis_session cookie. Errors: 401 invalid_credentials, 400 unknown_realm, 403 provider_not_allowed
POST /auth/refresh{refresh_token} → new pair. Replay → 401 token_reuse + family revocation. Roles re-read, realm preserved
POST /auth/logout{refresh_token} — revokes the rotation family
POST /auth/password/reset/request / confirmCodes via the notify service; always 200 (enumeration resistance)
POST /auth/apikey{service?, capabilities?, expires_in_days?}{id, key, expires_at, capabilities}key shown once; capabilities may not exceed the issuer’s own (403 scope_exceeds_authority)
DELETE /auth/apikey/:idRevoke
POST /auth/tokenAuthorization: ApiKey <key>, ?audience= — exchanges a service API key for a short service PASETO (type: "service" + CPET scope claims). 403 not_a_service_key, 401 apikey_invalid
POST /auth/bootstrap{token, email, password, firstname, lastname} — one-shot first-superadmin creation gated by bootstrap.token; closes itself once a superadmin exists
POST /auth/mfa/totp/setupenableverify, disableTOTP lifecycle; codes are single-use (401 code_reused); disable requires a current code
POST /auth/magic/request / verifyMagic-link login via the configured channel
POST /auth/webauthn/register/begin|finish, /auth/webauthn/assert/begin|finishPasskeys; 503 webauthn_disabled when not configured
GET /auth/oauth/:provider/start / callbackOAuth with PKCE S256; 10-minute state
GET /.well-known/jwks.jsonPer-tenant Ed25519 public keys
Method + PathBehavior
POST /superadmin/impersonate{tenant, user_id, reason, read_write?}{token, session_id, expires_in, mode, acting_as, tenant}. Enforced in order: plane operator → exact role (impersonate-readonly / impersonate) → grant on the target tenant → target user’s allow_impersonation → mint with act claim → force-managed session → audit in both planes. reason is mandatory

Enforced by each entity’s access: rules; Bearer token + CPET headers:

Method + PathPurpose
GET/POST /rest/:entity · POST /rest/:entity/search · GET/PUT/PATCH/DELETE /rest/:entity/id/:id · POST /rest/:entity/id/:id/restoreGeneric CRUD over every IAM entity (including product-defined ones) — full detail in the IAM API reference
/admin/user, /admin/role, /admin/realm, /admin/tenantDomain aliases, admin-gated
GET /schema, GET /schema/:entitySchema introspection

Separation of duties: admin can look, superadmin can change.

RoleRoutes
adminGET /admin/data/seeds, /admin/data/applied, /admin/data/plans/:id, /admin/data/locks; POST /admin/data/plans (generate)
superadminPOST /admin/data/plans/:id/apply, seed runs, lock release, retention, maintenance
superadmin/superadmin/tenant/:t/* — cross-tenant onboarding, incl. DELETE /superadmin/tenant/:t/cache
Method + PathPurpose
POST /superadmin/registry/tenants{slug, displayname} — register
GET /superadmin/registry/tenantsList
POST /superadmin/registry/tenants/provision{slug, admin_email, admin_password} — register → bootstrap → seed → activate, idempotent; reports steps applied

Managed sessions (mesh-internal, gateway ↔ iam over mTLS)

Section titled “Managed sessions (mesh-internal, gateway ↔ iam over mTLS)”

id here is the control-plane row id — never the bearer credential.

Method + PathPurpose
POST /internal/session/exchange{session_id, audience?}{token, format, expires_at, cpet}; 401 invalid_session with no reason oracle
POST /internal/session/revoke{id, reason} → 204 — instant revocation
POST /internal/session/rotate{id, aal} → new session id (fixation defense, AAL step-up)
GET /internal/session/list?principal=<id>Enumerate a principal’s sessions