Skip to main content

Rate limits

The limit​

600 requests per minute per credential, in a fixed 60-second window that starts with your first request.

  • An API key has its own window. Dashboard sessions share one window per account.
  • It is the same for every key type and every plan.
  • It is counted per API server, so under load balancing you may get somewhat more before a refusal. Do not design to that.
  • A refused request does not count against the window.

Where it applies​

SurfaceLimited
Developer routes — /v1/fx/rates, /v1/webhooks*, /v1/api-keys*, /v1/request-logs*, /v1/usage/*, /v1/transactions*, /v1/contacts*, …Yes
Dashboard routesYes
Money routes — /v1/banking/*Yes
GET /v1/public/pay/{handle}300 per hour per IP address; its 429 carries no X-RateLimit-* or Retry-After headers
Other public routesNo
Sandbox tools — the faucet, simulate-deposit, simulate-arrival, simulate-completion, the digital-asset approvalEach also has a window of its own: at most 30 requests an hour from one account, a refused request included (429 rate_limited, the message says how many minutes are left). The faucet and the digital-asset tools count against the 600 per minute too — see Sandbox behaviour

Besides our limit, our banking partner limits us. When it does, you get 429 rate_limited with the message "upstream partner rate-limited the request" and no Retry-After. Back off and retry. A payout or conversion refused this way has already been recorded as created, and a retry with the same Idempotency-Key only returns that record — it is never sent. Send it again with a new key, as for any other 4xx (Payouts).

Headers​

Every response from a limited surface carries:

HeaderMeaning
X-RateLimit-Limit600
X-RateLimit-RemainingRequests left in the current window
X-RateLimit-ResetUnix time, in seconds, when the window resets

A refusal adds Retry-After in seconds:

HTTP
HTTP/1.1 429 Too Many Requests
Retry-After: 12
X-RateLimit-Limit: 600
X-RateLimit-Remaining: 0
X-RateLimit-Reset: 1792094427
JSON
{
"success": false,
"error": "rate_limited",
"message": "too many requests; retry in 12s. The limit is 600 requests per minute."
}

The X-RateLimit-* headers are not exposed to cross-origin browser code; read them server-side.

Handling 429​

  1. Wait Retry-After seconds if it is present; otherwise back off exponentially with jitter, starting at a second.
  2. Retry with the same Idempotency-Key where the route takes one — our own limit refuses a request before it does anything. (A 429 without Retry-After on a money route is our partner's; see above.)
  3. If you hit the limit routinely, spread the work over time and cache GET /v1/fx/rates (it is reused for a minute on our side anyway). Polling payouts counts too: pace it.

A 429 is not written to request logs — the limit is checked before the request is logged.