Rate limits

Rate limits

Every API key is subject to a rate limit enforced on a sliding 60-second window, plus a monthly or daily quota depending on your plan. Limits protect the shared infrastructure that backs Forge and keep latency predictable for everyone.

Response headers

Every /v1 response, successful or not, carries three headers describing your current standing:

HeaderDescription
X-RateLimit-LimitRequests allowed per 60-second sliding window for your plan.
X-RateLimit-RemainingRequests remaining in the current window.
X-RateLimit-ResetUnix timestamp (seconds) when the current window resets.

Plans

PlanPer-minute limitMonthly / daily quotaPrice
Free60 req/min1,000 req/day$0
Starter300 req/min100,000 req/month$29/mo
Pro1,000 req/min1,000,000 req/month$99/mo
EnterpriseCustomCustomCustom

Going over the limit

When you exceed your per-minute limit, Forge returns 429 Too Many Requests with a Retry-After header (seconds to wait) and a structured error body:

HTTP/1.1 429 Too Many Requests
Retry-After: 12
X-RateLimit-Limit: 60
X-RateLimit-Remaining: 0
X-RateLimit-Reset: 1752489672

{
  "status": "error",
  "error": {
    "code": "rate_limited",
    "message": "Rate limit exceeded. Retry after the window resets.",
    "doc_url": "https://forge-api.dev/docs/rate-limits"
  }
}

Handling 429s with backoff

Treat 429 as a signal to slow down, not an error to surface to your users. Respect Retry-After when present, and fall back to exponential backoff with jitter otherwise:

async function forgeFetch(url, options = {}, attempt = 0) {
  const res = await fetch(url, options);

  if (res.status === 429 && attempt < 5) {
    const retryAfter = Number(res.headers.get('Retry-After')) || 0;
    const backoff = retryAfter * 1000 || (2 ** attempt) * 500 + Math.random() * 250;
    await new Promise((resolve) => setTimeout(resolve, backoff));
    return forgeFetch(url, options, attempt + 1);
  }

  return res;
}

Best practices