⚠️
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 by default. Beyond that, 429 with a Retry-After header — honour it
rather than retrying immediately. The limit is per key, so live and test integrations do not share it.
Your dashboard's API keys page shows the limit that applies to your account; if an integration needs
more, ask support and it is adjusted for your account, not for a single key.
Payout-creating calls (POST /v1/payouts, /v1/payout-requests, /v1/transfers) may carry a
second, tighter per-key limit set for your account; the same 429 and Retry-After apply.
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.