Authentication
Every /v1/* route authenticates with an API key:
Authorization: Bearer sk_live_...
X-API-Key: sk_live_... is accepted identically, for HTTP clients that reserve Authorization for
something else.
Test keys and live keys
| Prefix | Mode | Real money |
|---|---|---|
sk_test_… |
Test | No — all the code runs (routing, fees, validation), no money moves |
sk_live_… |
Production | Yes |
Objects created in test mode carry is_test: true and never appear in your production reports.
Test mode does not cover instant payment. The PI and tontine families refuse test keys: they talk to an external system that has no sandbox on our side.
The secret exists once
When a key is created (or rotated), the secret is shown once. On our side only its HMAC is stored: nobody — not even support — can give it back to you. Lost? Rotate: the old key is revoked and the new one is shown once.
Why does my key answer client_inactive?
A key is issued as soon as you sign up, but it admits no call until the account is approved
(KYB file accepted, account active). That is the compliance door: it opens on approval and closes
immediately on suspension — the same key, with nothing else changed.
Scopes
Each key carries scopes, and an operation outside them answers 403 insufficient_scope: collect,
pay out, refund, read, manage webhooks. Issue the narrowest key that does the job — a read key for
your reports has no business being able to pay out.
Idempotency
On creations (POST /v1/payments, POST /v1/payouts, POST /v1/refunds…), pass an
Idempotency-Key header of your choosing — your order reference, for instance. A replay with the
same key returns the original operation, never a duplicate; the same key with a different payload
is refused with 409.
One key per operation, never per parent object. A collection can be refunded in several parts: an idempotency key carrying the payment's identifier would make the second partial refund look like a replay of the first. Success on the merchant's side, customer not refunded.
Rate limit
300 requests per minute per key. Beyond that, 429 with a Retry-After header — honour it rather
than retrying immediately.
Good practice
- One key per environment (production, staging), never shared between services.
- The secret lives in a secret manager, never in code and never in the front end.
- Rotate at the first doubt — with no outage if you deploy the new key before revoking the old one.