Authentication - Kontier Billing API
All API requests require authentication via an API key passed as a Bearer token in the standard Authorization HTTP header.
Bearer token
Include your API key in every request:
Code
Keys come in two formats, distinguished by prefix:
| Prefix | Workspace mode | Use for |
|---|---|---|
sk_live_<64-hex> | live | Production traffic. Real money, real invoices. |
sk_test_<64-hex> | sandbox | Sandbox testing. No real charges; isolated from live data. |
Each key is bound to one organization and one workspace. The organization ID and workspace ID are derived from the key.
Treat keys as secrets. Never commit them to source control or expose them in browser-side code.
Authentication errors
When authentication fails, the API returns an application/problem+json error document (per RFC 9457). See Errors for the full envelope shape.
| HTTP status | code | When |
|---|---|---|
| 401 | UNAUTHORIZED | Authorization header missing, scheme is not Bearer, token is empty, key not found, key revoked, or organization suspended. |
| 403 | FORBIDDEN | Key has an IP allowlist and the request IP is not in it. |
| 500 | INTERNAL_ERROR | The key lookup itself failed (database/infrastructure error). |
These checks run before any endpoint logic, so these statuses can come back from any endpoint.
Managing API keys
Keys are created, listed, rotated, and revoked through the API key endpoints. The plaintext key value is only returned once, at creation or rotation time - store it immediately.
List keys
Code
Returns metadata only (id, prefix, type, name, scopes, allowed_ips, expires_at, created_at). The plaintext key is never retrievable after creation.
Create a key
Code
Request body (all optional except name):
| Field | Type | Default | Notes |
|---|---|---|---|
name | string | required | Human-readable label. |
key_type | "sk_live" | "sk_test" | matches workspace mode | Override only if you know what you're doing. |
scopes | string[] | required, at least one | Permission codes the key carries. There is no full-access key; an empty array is rejected. |
allowed_ips | string[] | [] (no restriction) | CIDRs or single IPs. Requests from outside return 403. |
expires_at | RFC 3339 timestamp | null | null (non-expiring) | Optional automatic expiry. |
Response (201 Created) returns the plaintext key in the key field. This is the only time it appears.
Code
Rotate keys
Code
Generates a new key for the workspace and stamps a 24-hour expiry on existing keys. Both work during the grace window. Response (201) carries new_key (plaintext, only chance to capture it), old_key_expiry (RFC 3339), and a human message.
Revoke a key
Code
Response (200) returns { "data": { "status": "revoked" } }. Returns 404 if the id is unknown or the key was already revoked.
Workspace context
Every key is bound to a single workspace. Workspaces have a mode field that drives behaviour:
live- real billing. Production keys (sk_live_...) belong here.sandbox- isolated testing. Sandbox keys (sk_test_...) belong here. Sandbox test artifacts (test clocks, payment simulations) only work in sandbox.
The workspace and its mode are resolved from the key automatically. To work across workspaces, use separate keys.