LEAPERone Docs

Rate Limits

Understanding and handling rate limits.

LEAPERone applies per-user rate limits on a sliding window to ensure fair usage and service stability.

Current Limits

Limits are applied per user, per endpoint over a 1-minute window. Different endpoints may have different thresholds depending on the compute cost of each request.

Specific rate limit numbers may change over time. Always check the X-RateLimit-* response headers for the current values that apply to your request.

Rate Limit Headers

Every API response includes these headers:

HeaderDescription
X-RateLimit-LimitMaximum number of requests allowed in the current window.
X-RateLimit-RemainingNumber of requests remaining in the current window.
X-RateLimit-ResetUnix timestamp (seconds) when the current window resets.
Retry-AfterSeconds until you can retry (only present on 429 responses).
Example response headers
X-RateLimit-Limit: 60
X-RateLimit-Remaining: 42
X-RateLimit-Reset: 1700000060

Handling 429 Responses

When you exceed the rate limit, the API returns a 429 status:

429 Response
{
  "error": {
    "message": "Rate limit exceeded. Please slow down.",
    "type": "rate_limit_error",
    "code": "rate_limit_exceeded"
  }
}

Use the Retry-After header to determine how long to wait before sending the next request.

Exponential Backoff

The recommended strategy for handling rate limits is exponential backoff with jitter:

Rate-limit-aware fetch
async function fetchWithBackoff(url, options, maxRetries = 5) {
  for (let attempt = 0; attempt <= maxRetries; attempt++) {
    const response = await fetch(url, options);

    if (response.ok) return response;

    if (response.status === 429) {
      const retryAfter = response.headers.get("Retry-After");
      const waitMs = retryAfter
        ? parseInt(retryAfter, 10) * 1000
        : Math.min(1000 * 2 ** attempt, 30000);
      const jitter = Math.random() * 1000;

      console.warn(
        `Rate limited. Retrying in ${Math.round((waitMs + jitter) / 1000)}s...`
      );
      await new Promise((r) => setTimeout(r, waitMs + jitter));
      continue;
    }

    // Non-retryable error
    throw new Error(`Request failed with status ${response.status}`);
  }

  throw new Error("Max retries exceeded");
}

Best Practices

  • Monitor the headers. Check X-RateLimit-Remaining proactively and slow down before hitting zero.
  • Queue requests. If you are making many calls in a batch, use a queue to space them out evenly across the window.
  • Use jitter. Always add random jitter to backoff delays to prevent synchronized retries from multiple clients.
  • Cache responses. If you call the same endpoint with the same parameters, cache the result to avoid unnecessary requests.