Tenant API Keys
Tenant API keys are long-lived, programmatic credentials scoped to a single organisation. They are the credential behind the X-Api-Key authentication scheme of the MultiAuth selector — the right choice for CI jobs, integrations, and service-to-service calls that have no interactive user to drive a browser login.
Every key is prefixed with csk_ (Consystence key). Keys are minted, listed, and revoked through the admin surface under /api/admin/api-keys. These endpoints sit outside the CLI-scoped API reference — the CLI has no key-management commands — so this page is the authoritative contract for their request and response shapes.
Who can manage keys
Section titled “Who can manage keys”On a cloud cell, all three endpoints sit behind the OrgAdmin authorisation policy. A caller may mint, list, or revoke keys only if they are:
- an org owner or admin (see roles), or
- a verified platform-admin.
Org members cannot create or revoke keys.
On a site server, key management — like site users and site configuration — is a site function, authorised on the caller’s site role: a principal with an owner or admin site role qualifies, including a site-PIN principal, while site members cannot manage keys.
Authorisation is evaluated against the role of the caller, which may itself be a CIAM Bearer session or another API key.
Tenant scoping
Section titled “Tenant scoping”The target tenant is never taken from the request body. It is derived from the authenticated principal’s organisation — the org_slug claim (the org’s routing slug) is itself the tenant scoping key on the cell, while the account-minted org_ id (an 8-character Crockford base32 id, e.g. org_ab12cd34) serves only as the cross-plane correlation identity — so a caller cannot mint or touch keys outside its own organisation. Cross-tenant access attempts — and genuinely non-existent keys — return an identical, cause-agnostic 404, so the API never leaks whether a key exists in another tenant.
Key lifecycle
Section titled “Key lifecycle”stateDiagram-v2
[*] --> Active: POST /api/admin/api-keys<br/>(plaintext returned ONCE)
Active --> Active: used on requests<br/>(X-Api-Key, last_used_at updated)
Active --> Revoked: DELETE /api/admin/api-keys/{keyId}
Active --> Expired: expires_at reached
Revoked --> [*]
Expired --> [*]
Minting a key — POST /api/admin/api-keys
Section titled “Minting a key — POST /api/admin/api-keys”The request body supplies the key’s role, a human-readable label, and an expiry:
{ "role": "admin", "name": "ci-historian-reader", "expiresAt": "2027-02-18T00:00:00Z"}role— the org role the key will carry (see roles). Roles reserved for the account control plane are rejected with400 ReservedRole; an org admin cannot self-mint a control-plane credential through this tenant-facing surface.name— a label that appears in the list view and in expiry-reminder emails.expiresAt— required; subject to the expiry policy below.
On success the endpoint returns 201 Created with the plaintext key in the response body — exactly once:
{ "keyId": "1f8e...-uuid", "keyPrefix": "csk_AbCd", "plaintext": "csk_AbCd…(32 base62 chars)", "role": "admin", "name": "ci-historian-reader", "expiresAt": "2027-02-18T00:00:00Z", "createdAt": "2026-02-18T09:14:00Z"}Key format and storage
Section titled “Key format and storage”The plaintext is csk_ followed by 32 base62 characters (digits + upper + lower), drawn from a cryptographically secure RNG with rejection sampling to avoid modulo bias — roughly 190 bits of entropy.
What the platform actually stores is not the plaintext:
- Verifier — what the platform stores is a one-way verifier of the key, never the plaintext. The plaintext cannot be recovered from storage or re-derived, and no later request re-emits it. A missing or misconfigured verifier secret is a hard start-up failure — the server refuses to run with broken hashing.
- Prefix —
csk_plus the first 4 base62 characters of the plaintext (8 characters total, e.g.csk_AbCd). This is the only fragment retained for display; it is safe to show in lists, logs, and notifications.
Listing keys — GET /api/admin/api-keys
Section titled “Listing keys — GET /api/admin/api-keys”Returns the tenant’s non-revoked keys, ordered by creation time (newest first). Each item is prefix-only metadata — never the plaintext, never the hash:
[ { "keyId": "1f8e...-uuid", "keyPrefix": "csk_AbCd", "role": "admin", "name": "ci-historian-reader", "createdByUserId": "…the minting principal's subject id…", "createdAt": "2026-02-18T09:14:00Z", "expiresAt": "2027-02-18T00:00:00Z", "lastUsedAt": "2026-02-18T09:20:11Z" }]createdByUserId is the minting principal’s subject identifier: for a CIAM session that is the pairwise OIDC sub — not the Entra oid, so it will not match directory object ids — and when a key is minted using another API key it is that key’s keyId. lastUsedAt is updated best-effort as the key authenticates requests, and is null until first use.
Revoking a key — DELETE /api/admin/api-keys/{keyId}
Section titled “Revoking a key — DELETE /api/admin/api-keys/{keyId}”{keyId} is the key’s UUID (keyId from mint/list), not its prefix. The body is optional — supply a reason for the audit trail, or omit it:
{ "reason": "rotating credentials" }A successful revocation returns 204 No Content. A key that does not exist, belongs to another tenant, or is already revoked returns the uniform 404 described under tenant scoping — revoked keys drop out of the tenant lookup, so a retried DELETE (say, after a timeout) sees 404, not a second 204; treat a 404 on retry as success, not as a wrong keyId. The audit revoked_at timestamp is set once and never advanced.
There is no separate rotation endpoint: rotate by minting a new key, switching the caller over, then revoking the old one. Keys also end with their organisation: deprovisioning an org removes its API keys along with the rest of the org runtime.
Expiry policy
Section titled “Expiry policy”expiresAt is validated at the service layer against a horizon measured from now:
| Bound | Value |
|---|---|
| Minimum | 1 hour from now |
| Maximum | 2 years (730 days) from now |
Requests outside this range are rejected with 400 ExpiryPolicyViolation. A value within range but in the past is likewise rejected by the minimum bound.
A background reminder service polls every 24 hours and emails the key’s creator when a key falls 24–30 days from expiry, with a 7-day cooldown so a key is reminded at most once per window. This is courtesy notification only — expiry itself is enforced at authentication time.
Using the key
Section titled “Using the key”Present the plaintext on each request via the X-Api-Key header. The MultiAuth selector routes the request to the ApiKey scheme based on the header’s presence:
curl https://acme.consystence.com/api/... \ -H "X-Api-Key: csk_AbCd…"The key authenticates only while it is active — not revoked and not past expiresAt. For how the platform chooses between this and the CIAM Bearer and site-PIN schemes, see the authentication model. The key-management endpoints themselves are not part of the CLI-scoped API reference — the schemas on this page are the contract.