Rate limits are bucketed by merchant and endpoint; 429 includes Retry-After.
Rate Limits
Measured per merchant × bucket using a sliding window. Buckets are determined by method + path prefix.
| Bucket | Coverage | Quota |
|---|---|---|
deposits | POST /v1/deposits | 60 / minute |
members_write | POST /v1/members and writes under /v1/members/* | 300 / minute |
orders | All other writes (remittance / QR payment / exchange / transfer / wealth / cards) | 120 / minute |
reads | All GET requests | 1200 / minute |
POST /v1/deposits has the tightest limit because it is the only endpoint in the system that creates member balance without moving existing funds.
What Happens When You Exceed It
HTTP 429
Retry-After: 60
{ "error": { "code": "rate_limited", "message": "…", "retry_after": 60 } }
Back off according to Retry-After, rather than retrying immediately. It gives the current window's duration in seconds.
Two Things to Know
Matching uses path prefixes, not an endpoint list. Unrecognized writes fall into orders, and unrecognized reads into reads, so new endpoints automatically have a gate. A list-based approach requires remembering to add a row for every endpoint; an omission produces no error, just an unprotected endpoint.
429 is recoverable; handle it as a normal path. It does not mean you are banned. Unrecoverable balance creation is the real risk; quotas reflect that tradeoff, even if legitimate merchants occasionally need to back off.
Do Not Poll Us Like a Database
A reads quota of 1200/minute is not an invitation to scan the order table every second. Use Webhooks for state changes: they carry status_version, allowing forward-only merging. Polling consumes quota and can also turn completed orders back into processing when slow responses arrive late.