Data API

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

PlanRequests / minCredits / monthStreams
Free6010,000
Builder120500,000
Pro3003,000,0001
Business60010,000,0003
EnterpriseNegotiatedUnmeteredNegotiated
Pay-as-you-go60What 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/usage is free. Poll it as often as you need to; it never counts against you.

Knowing where you stand

GET/v1/usage

Free. The authority on what this key has left.

Try it/v1/usage

Kept in this browser only, and reused on every page. Never sent anywhere but the API.

Response
{
  "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
}
FieldMeaning
quotaMonthly credit allowance. null means unmetered.
used / remainingConsumed and left in the current period. remaining is null when unmetered.
credit_balancePurchased credits, on top of the plan allowance. These do not expire.
period_resets_atWhen used returns to zero.
daily_limitAn additional per-day cap where one applies; null if not.
parallel_streamsHow many WebSocket connections may be open at once.
scopeSet 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.

JavaScript
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');
}
Running out of credits mid-month is a 402, not a 429. Retrying will not fix it — buy a top-up or wait for 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=100 once beats limit=10 ten 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.