Rate limits
Frame enforces per-merchant rate limits on every V1 endpoint. The limiter is a 60-second rolling window scoped by (merchant, endpoint, mode); over-limit requests get HTTP 429 Too Many Requests.
Default limits
| Mode | Requests/minute |
|---|---|
| Live | 160 |
| Sandbox | 50 |
Sandbox is intentionally tighter — it discourages load-testing against shared sandbox infrastructure (see Testing).
High-throughput endpoints
A handful of endpoints carry higher caps because real merchant traffic legitimately bursts through them:
| Endpoint family | Live requests/minute |
|---|---|
/v1/charge_intents (all routes) | 3000 |
/v1/payment_methods (all routes) | 3000 |
/v1/customers (all routes) | 800 |
If you're consistently bumping against these on legitimate traffic, contact support before the next traffic spike rather than after — per-merchant overrides are available.
What causes rate limiting
Two common patterns:
- Bulk operations. Analytics jobs, migrations, or backfills that fire requests in tight loops. Throttle these client-side — there's no upside to going as fast as the network allows.
- Traffic spikes. Flash sales, viral moments, scheduled drops. Limits are set well above typical merchant load, but if you know a spike is coming, reach out ahead of time.
Handle 429s gracefully
Watch for 429 and retry with exponential backoff plus jitter. Backoff alone causes thundering-herd retries; jitter spreads the retries out.
A reasonable starting policy: first retry at 1s + random(0–500ms), double on each subsequent retry, cap at 6 retries or ~30s total.
Don't load-test against sandbox
Sandbox limits are roughly a third of live, so a sandbox load test hits limits live traffic wouldn't. Sandbox also mocks the payment-gateway leg, which changes latency in ways that make results unrepresentative.
Build a mocking layer into your integration instead. Sample real live-mode latencies, sleep for that distribution in your mock, and load-test against the mock — not against Frame's sandbox.