Bearer-token API keys. Sandbox vs production. Key rotation.
Every mutating route on api.iso-compliant.com requires a Bearer token. Two tiers: iso_test_… keys are sandbox-only (no Stripe meter, no production-bank UAT side-effects) and iso_live_… keys are production.
The token format is opaque. Server-side it resolves to a tenant id + a signing-key (used to verify HMAC-signed webhooks back to the customer's webhook URL) — see apps/api/src/lib/signing-key.ts and apps/api/src/lib/tenant.ts. The lookup is Hyperdrive-pooled with a p50 of 5–20ms.
Rotation: generate a new key from the dashboard; the old key remains valid for a 24-hour grace window. Webhook signing keys rotate independently of the API key on a 90-day cadence.
Never put an iso_live_… key in a client-side bundle or git repo. The free /qrbill and /iban-check and /address-lint pages on the marketing site are pure-local and require no key.
Mandatory header `Idempotency-Key` (UUID or other opaque ≤64 char string). A second request with the same key and the same body returns the cached response and the header `X-Iso-Compliant-Idempotent-Replay: true`. A second request with the same key but a different body returns 409.
Rate limit
Sandbox: 60 requests / minute, 1000 / day. Production: 600 requests / minute soft cap, lifted per tenant on request.