API key format
Credentials consist of a key ID and a secret, separated by a colon:key_id is the public identifier for your credential. The secret is the private value — it is securely hashed server-side and never stored in plaintext.
How it works
Client sends Bearer token
The middleware extracts the
key_id and secret from the Authorization
header.Verify secret
The provided secret is compared against the stored hash using
constant-time comparison.
Tenant resolution
The credential resolves to a tenant ID, which is injected into the request
context. All subsequent operations are scoped to this tenant.
Credential lifecycle
| Stage | Description |
|---|---|
| Provisioned | Key pair generated by the platform team or admin CLI |
| Active | Key is valid and accepts requests |
| Rotated | New key issued; old key remains valid during grace period |
| Revoked | Key permanently disabled; all requests return 401 |
IP allowlisting
For production deployments, restrict API access to known IP addresses. The custody API validates the source IP of each request against the tenant’s allowlist. When IP allowlisting is enabled:- Requests from unlisted IPs receive a
403 Forbiddenresponse - The allowlist is configured per tenant
- CIDR notation is supported for IP ranges
Idempotency
AllPOST and PUT requests should include an Idempotency-Key header:
- Keys are scoped per tenant, method, and path
- Keys are valid for 24 hours
- Replaying a request with the same key returns the original response
- Using the same key with a different method or path returns a
422 IDEMPOTENCY_CONFLICTerror
Error codes
Authentication failures return specific error codes:| Status | Code | Meaning |
|---|---|---|
401 | UNAUTHORIZED | Missing or invalid Bearer token |
403 | FORBIDDEN | Valid token, but IP not in allowlist or insufficient permissions |
422 | IDEMPOTENCY_CONFLICT | Idempotency key reused with different method/path |
401 Response
Security best practices
Rotate credentials regularly
Rotate credentials regularly
Create a new credential, update your integrations, then revoke the old one.
The API supports multiple active credentials per tenant. Rotate every 90 days.
Use IP allowlists in production
Use IP allowlists in production
Restrict access to your known egress IPs. This provides defense-in-depth
even if a credential is compromised. Never call the API from client-side code.
Never log secrets
Never log secrets
The
secret portion of your API key should be treated like a password.
Never log it, commit it to version control, or expose it in client-side
code.Use separate credentials per environment
Use separate credentials per environment
Maintain distinct credentials for development, staging, and production to
limit blast radius.