Rate limits & credits
Two separate budgets: how fast you may ask, and how much you may take.
A rate limit is requests per minute — it controls burst. A credit is a unit of monthly volume. Plans buy throughput; credits buy volume. Running out of one does not affect the other, and the errors are different: too fast is 429, out of credits is 402.
By plan
| Plan | Requests / min | Credits / month | Streams |
|---|---|---|---|
| Free | 60 | 10,000 | — |
| Builder | 120 | 500,000 | — |
| Pro | 300 | 3,000,000 | 1 |
| Business | 600 | 10,000,000 | 3 |
| Enterprise | Negotiated | Unmetered | Negotiated |
| Pay-as-you-go | 60 | What you buy | — |
Pay-as-you-go stays at 60/min on purpose. Credits are volume, not speed — without that ceiling they would simply replace the subscriptions. Full pricing is on the API dashboard.
What a request costs
- One credit per REST request for the ordinary endpoints.
- Streaming bills per 100 messages delivered, not per second connected — an idle socket costs nothing.
/v1/usageis free. Poll it as often as you need to; it never counts against you.
Knowing where you stand
/v1/usageFree. The authority on what this key has left.
Kept in this browser only, and reused on every page. Never sent anywhere but the API.
{
"tier": "pro",
"rate_limit_per_min": 300,
"parallel_streams": 1,
"quota": 3000000,
"used": 279,
"remaining": 2999721,
"period_resets_at": "2026-09-01T00:00:00+00:00",
"credit_balance": 0,
"daily_limit": null,
"daily_used": 65,
"addons": [],
"scope": null
}| Field | Meaning |
|---|---|
quota | Monthly credit allowance. null means unmetered. |
used / remaining | Consumed and left in the current period. remaining is null when unmetered. |
credit_balance | Purchased credits, on top of the plan allowance. These do not expire. |
period_resets_at | When used returns to zero. |
daily_limit | An additional per-day cap where one applies; null if not. |
parallel_streams | How many WebSocket connections may be open at once. |
scope | Set when a key is restricted to part of the API; null for a full key. |
Handling a 429
Back off and retry — do not hammer. Exponential backoff with jitter is enough; a fixed retry loop from several workers simply re-synchronises them into the next burst.
async function get(path, tries = 4) {
for (let i = 0; i < tries; i++) {
const res = await fetch(BASE + path, { headers: { 'X-API-Key': KEY } });
if (res.status !== 429) return res;
// Wait longer each time, with jitter so parallel workers do not resynchronise.
const wait = 2 ** i * 500 + Math.random() * 400;
await new Promise((r) => setTimeout(r, wait));
}
throw new Error('rate limited');
}period_resets_at. Credits bought on a paid plan are discounted; the higher the plan, the better the rate.Staying inside the budget
- Ask for what you need.
limit=100once beatslimit=10ten times — same data, a tenth of the credits. - Cache what does not move. The ranked list changes on a schedule, not per second.
- Stream instead of polling. Watching for new trades over WebSocket costs far less than a REST poll every few seconds.