Authentication
Network
The API answers only the egress IP addresses we have listed for you. A request from any other address never reaches the application, whatever key it carries. Tell us before your addresses change.
Keys
Authorization: Bearer <your key>
- One key belongs to one tenant and carries an explicit list of scopes.
- A key is shown once. We store a SHA-256 of it and cannot show it again; a lost key is replaced, not recovered.
- An unknown, revoked or expired key, a suspended tenant, and a missing or malformed header all answer
401 unauthorized. They are deliberately indistinguishable. - A scope the key does not hold answers
403 forbidden_scope, anddetail.requirednames the scope.
GET /v1/whoami needs any valid key and no scope. It answers the tenant, the key's prefix, label and scopes, and your payout wallets. If you hold keys for more than one tenant, check each key here before you use it.
Scopes
| Scope | Opens |
|---|---|
deposits:read | GET /v1/deposits, GET /v1/deposit-addresses, GET /v1/deposit-xpubs |
deposits:write | Registering, deriving and retiring addresses and xpubs, watch-now, sweep holds, POST /v1/deposit-keys (also signed) |
deposits:issue | POST /v1/deposit-addresses/issue: addresses whose keys we hold. Granted only by name |
chain_payouts:write | POST /v1/chain-payouts, always together with a signature |
chain_payouts:read | GET /v1/chain-payouts/{payout_id}, payout estimates |
withdrawals:write | POST /v1/withdrawals |
withdrawals:read | Withdrawals, destinations, the withdrawal limit, withdrawal estimates, POST /v1/payments/proof |
quotes:read | GET /v1/currencies, GET /v1/pairs, GET /v1/fees, GET /v1/limits, POST /v1/quotes |
swaps:write / swaps:read | Conversions |
register:read | GET /v1/float, the statement, the register and its summary |
events:read | GET /v1/events |
customers:write / customers:read | Registering your end users and their identity checks |
transfers:*, accounts:* | Fiat transfers and accounts |
Scopes are granted in bundles, and a job that moves money gets its own key:
| Bundle | Scopes |
|---|---|
deposits | deposits:read, deposits:write, events:read |
chain_payouts | chain_payouts:write, chain_payouts:read, events:read |
withdrawals | withdrawals:read, withdrawals:write, register:read, events:read |
swaps | quotes:read, swaps:read, swaps:write, register:read, events:read |
swaps_for_customers | swaps plus customers:read, customers:write |
Separate keys are revoked separately: pulling a payout key stops money leaving without stopping the rest of your product.
Rate limits
Per key, on a 60-second sliding window:
| Per minute | |
|---|---|
| Reads | 600 |
Writes (POST, PUT, PATCH, DELETE) | 120 |
Your tenant may carry a lower ceiling agreed at onboarding; it can only tighten these. Over either limit you get 429 rate_limited with a Retry-After header and detail.retry_after_seconds and detail.limit_per_minute. GET /v1/limits returns the numbers applied to your key.
Limits are counted per key, not per address.
Request ids
Every response carries X-Request-Id. Send your own and it is kept, so your logs and ours join on the same value.