Skip to content

Rate limits

Rate limits cap how often you can call the API. They are enforced as fixed-window counters in Redis and are completely separate from credits, which meter the cost of each call. Exceeding a limit returns HTTP 429 — and a 429 never deducts credits.

Each API key is tracked independently against three rolling windows — per minute, per hour, and per day — plus a short burst allowance for momentary spikes. The limits are set by your plan:

PlanPer minutePer hourPer dayBurst
Free1010050015
Starter601,00010,000100
Professional30010,000100,000500
Enterprise1,00050,000500,0002,000
Custom1,00050,000500,0005,000

All three windows must pass; the tightest one that trips is the one that returns 429. Limits are per key, so splitting traffic across multiple keys on the same account multiplies your effective ceiling up to your plan’s key cap.

Every endpoint requires a key — there is no anonymous access. The free public demo key (mtk_demo) is shared across all demo callers, so it draws from a single common bucket rather than a per-account one:

Demo key (mtk_demo)
Requests / minute~240 (shared across everyone using the demo)
Credit budget~100 credits / hour, pooled across all demo callers, auto-refilling
Result cap3 per list (400 if you request more)
PaginationNot available (cursor/offset/page return 400)

Because the demo bucket is shared, it can be throttled (429) or run dry (402) when many people are using it at once. When the hourly credit budget is exhausted, demo requests return 402 INSUFFICIENT_CREDITS until the bucket refills. For predictable headroom and your own balance, create your own API key.

On every successful request the API reports your current standing against the primary (per-minute) window:

HeaderMeaning
X-RateLimit-LimitThe limit for the current window.
X-RateLimit-RemainingRequests left in the current window.
X-RateLimit-PlanThe plan label the limit was derived from.

When you are throttled, the response is 429 and carries recovery hints instead:

HeaderMeaning
Retry-AfterSeconds to wait before retrying (the tripped window’s length).
X-RateLimit-LimitThe limit that was exceeded.
X-RateLimit-RemainingAlways 0 on a 429.
X-RateLimit-ResetWhich window tripped: minute, hour, or day.

A 429 body uses the standard error envelope:

{
"success": false,
"error": {
"message": "Rate limit exceeded. Please try again later.",
"code": "RATE_LIMIT_EXCEEDED"
},
"statusCode": 429,
"timestamp": "2026-06-05T12:00:00.000Z"
}

429 is a transient, retryable condition. Honour Retry-After when present, and otherwise fall back to exponential backoff with jitter. Never retry in a tight loop — that only deepens the throttle.

async function requestWithBackoff(url, options = {}, maxRetries = 5) {
for (let attempt = 0; attempt <= maxRetries; attempt++) {
const res = await fetch(url, options);
if (res.status !== 429) {
return res;
}
// Prefer the server's hint; otherwise exponential backoff with jitter.
const retryAfter = Number(res.headers.get('Retry-After'));
const wait = Number.isFinite(retryAfter) && retryAfter > 0
? retryAfter * 1000
: Math.min(2 ** attempt * 1000, 60_000) + Math.random() * 1000;
await new Promise((resolve) => setTimeout(resolve, wait));
}
throw new Error('Rate limited: retries exhausted');
}
const res = await requestWithBackoff('https://api.quantconomy.com/api/v1/entries', {
headers: { Authorization: 'Bearer mtk_your_key_here' },
});

These are two independent systems, and it is worth being explicit about how they interact:

  • A rate limit caps request frequency (per key; the demo key shares one bucket). Hitting it returns 429 and costs no credits.
  • Credits cap request volume by cost. Running out returns 402 (for the demo key, when its shared hourly budget is empty).
  • Both checks run on every request. A call can be rejected by either, and the rate-limit check happens first — so a throttled request is never billed.
  • Buying more credits does not raise your rate limit, and a higher rate limit does not grant credits. To raise both, upgrade your plan.