GuidesResources

Rate limits

How many REST API requests you can send, how to read your remaining budget from each response, and what to do when you go over.

Rate limits apply to the REST API. Each limit counts requests in a fixed window, such as one calendar minute. When the window ends, the count starts again.

Limits

Keys from the developer console belong to an app. The app's limits are shared by all of its keys, and you can see them in the console. A new app starts with these:

RoutesLimit
Trading: /v1/orders and everything under it, /v1/markets/{id}/orderbook, /v1/markets/{id}/quote, /v1/markets/quotes500 per minute
Search: /v1/search120 per minute
Everything else250 per minute

Placing and removing orders (POST requests under /v1/orders) also has a limit of 40 per second. Both limits apply, so a burst of orders has to stay under both.

Keys issued before the developer console have two limits: 500 per minute for the trading routes and 240 per minute for everything else, search included.

On testnet you can call the API without a key. Requests without a key are limited per IP address: 500 per minute for the trading routes and 240 per minute for everything else. On mainnet, every request needs a key.

Read your budget from responses

Every response carries headers that tell you where you stand:

HeaderMeaning
RateLimit-LimitThe number of requests the window allows.
RateLimit-RemainingHow many requests are left in the window.
RateLimit-ResetSeconds until the window resets.
RateLimit-PolicyEvery limit that applied to the request, as "name";q=<limit>;w=<window in seconds>.
RateLimitEvery limit's live state, as "name";r=<remaining>;t=<seconds until reset>.

For example, a request to /v1/markets on testnet returns:

RateLimit-Limit: 240
RateLimit-Remaining: 239
RateLimit-Reset: 39
RateLimit-Policy: "rpm";q=240;w=60
RateLimit: "rpm";r=239;t=39

When two limits apply, as for order placement, RateLimit-Policy and RateLimit list both, such as "rps";q=40;w=1, "rpm";q=500;w=60. RateLimit-Limit, RateLimit-Remaining and RateLimit-Reset then describe whichever limit is closer to running out.

When you go over

A request over the limit gets a 429 response, and the request is not processed:

{
  "success": false,
  "code": 429,
  "error": "too_many_requests",
  "message": "Rate limit exceeded",
  "timestamp": "2026-11-04T20:37:19.030930831Z"
}

The response has the same RateLimit-* headers. There is no Retry-After header, so use RateLimit-Reset to know how long to wait:

// Sends a request and, on a 429, waits for the rate limit window to reset before
// trying again.
async function fetchWithRetry(url: string, init: RequestInit, attempts = 3) {
  for (let attempt = 1; ; attempt++) {
    const response = await fetch(url, init);
    if (response.status !== 429 || attempt === attempts) return response;

    // seconds until the window that refused the request resets, plus a random
    // fraction so parallel clients do not retry at the same moment.
    const resetSeconds = Number(response.headers.get("RateLimit-Reset") ?? 1);
    await new Promise((resolve) =>
      setTimeout(resolve, (resetSeconds + Math.random()) * 1000),
    );
  }
}

const response = await fetchWithRetry("https://api.predict.fun/v1/markets", {
  headers: { "x-api-key": "YOUR_API_KEY" },
});
console.log(response.status, response.headers.get("RateLimit-Remaining"));

Stay under the limits

  • Use the WebSocket API for anything that changes often, such as order books and your own orders, instead of polling the REST API.
  • Watch RateLimit-Remaining and slow down before it reaches 0.
  • Remove orders in batches. One request can remove up to 100 orders (see Cancel orders).

On this page