Skip to main content
Every request to the Quantum Chain Custody API requires authentication via a Bearer API key. This guide covers credential format, lifecycle, and security best practices.

API key format

Credentials consist of a key ID and a secret, separated by a colon:
Authorization: Bearer <key_id>:<secret>
The 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.
from quantumchain_custody import Client

client = Client(api_key="ck_live_abc123:sk_live_xyz789")
vaults = client.vaults.list()

How it works

1

Client sends Bearer token

The middleware extracts the key_id and secret from the Authorization header.
2

Lookup credential

The key_id is looked up in the database. Only ACTIVE credentials are accepted.
3

Verify secret

The provided secret is compared against the stored hash using constant-time comparison.
4

Tenant resolution

The credential resolves to a tenant ID, which is injected into the request context. All subsequent operations are scoped to this tenant.
5

IP allowlist check

If the tenant has an IP allowlist configured, the request’s source IP must match one of the allowed CIDRs.

Credential lifecycle

StageDescription
ProvisionedKey pair generated by the platform team or admin CLI
ActiveKey is valid and accepts requests
RotatedNew key issued; old key remains valid during grace period
RevokedKey permanently disabled; all requests return 401
Store your API secret securely. It is shown only once at creation time and cannot be retrieved later.

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 Forbidden response
  • The allowlist is configured per tenant
  • CIDR notation is supported for IP ranges
curl -X POST https://api.quantumchain.io/v1/tenants \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer $API_KEY" \
  -d '{
    "name": "Secure Corp",
    "ipAllowList": [
      "203.0.113.0/24",
      "198.51.100.42/32"
    ]
  }'
When an IP allowlist is configured, requests from unlisted IPs receive a 403 Forbidden response. If the list is empty or null, all IPs are allowed.

Idempotency

All POST and PUT requests should include an Idempotency-Key header:
Idempotency-Key: unique-request-identifier
  • 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_CONFLICT error
Use UUIDs or your own internal request IDs as idempotency keys. This makes retries safe across network failures.

Error codes

Authentication failures return specific error codes:
StatusCodeMeaning
401UNAUTHORIZEDMissing or invalid Bearer token
403FORBIDDENValid token, but IP not in allowlist or insufficient permissions
422IDEMPOTENCY_CONFLICTIdempotency key reused with different method/path
401 Response
{
  "code": "UNAUTHORIZED",
  "message": "authentication required",
  "requestId": "req_abc123"
}

Security best practices

Create a new credential, update your integrations, then revoke the old one. The API supports multiple active credentials per tenant. Rotate every 90 days.
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.
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.
Maintain distinct credentials for development, staging, and production to limit blast radius.