Documentation

Rate Limits

AdminUpdated Sep 20, 2026

Rate Limits

The Restore Hub API uses a sliding-window limiter measured in 10-second buckets. Limits are per API key (effectively per account), and they scale with your plan. Every authenticated response carries headers describing your current state.

Per-plan limits

Plan

Requests / 10s

Effective requests / minute

Free

50

~300

Premium

100

~600

Business

200

~1,200

Enterprise

200

~1,200 (contact sales for higher)

Free-plan keys are also restricted to read-only methods (GET). Write operations return 403 with an upgradeUrl.

Response headers

Every authenticated response includes these headers:

Header

Meaning

X-RateLimit-Limit

Your bucket size for the current plan (e.g. 100).

X-RateLimit-Remaining

Requests left in the current 10-second window.

X-RateLimit-Reset

Unix timestamp (seconds) at which the window resets.

X-RateLimit-Window

Always 10s. Reserved for future flexibility.

Retry-After

Seconds to wait. Sent only on 429 responses.

When you exceed the limit

The server responds with HTTP 429 and a JSON body:

{
  "error": "Rate limit exceeded",
  "limit": 100,
  "window": "10s",
  "retryAfter": 10,
  "plan": "PREMIUM",
  "upgradeUrl": "https://restorehub.net/pricing"
}

Backoff strategy

Recommended algorithm for clients:

  1. On 429, read the Retry-After header.

  2. Sleep for Retry-After + jitter seconds (10–25% jitter).

  3. Retry the same request. Cap at 3 attempts before giving up.

  4. If you keep hitting 429, slow your concurrency or upgrade.

async function call(url, init = {}, attempt = 0) {
  const res = await fetch(url, {
    ...init,
    headers: { Authorization: `Bearer ${process.env.RH_API_KEY}`, ...init.headers },
  });
  if (res.status !== 429) return res;
  if (attempt >= 3) throw new Error("Rate-limit backoff exhausted");

  const retryAfter = Number(res.headers.get("Retry-After") ?? 10);
  const jitter = Math.random() * 0.25 + 1;
  await new Promise(r => setTimeout(r, retryAfter * 1000 * jitter));
  return call(url, init, attempt + 1);
}
import os, random, time, requests

def call(url, attempt=0, **kw):
    r = requests.get(
        url,
        headers={"Authorization": f"Bearer {os.environ['RH_API_KEY']}"},
        **kw,
    )
    if r.status_code != 429:
        return r
    if attempt >= 3:
        raise RuntimeError("Rate-limit backoff exhausted")
    delay = int(r.headers.get("Retry-After", "10")) * (1 + random.uniform(0, 0.25))
    time.sleep(delay)
    return call(url, attempt + 1, **kw)

Member pulls have their own budget

members:pull is throttled separately — Discord caps how fast bots can join users to a guild. Restore Hub paces pulls at 50 members per minute per target server, regardless of your plan's API rate limit. See API Reference for the full pull endpoint contract.

Guidance for AI agents

  • List endpoints are paginated. Don't fetch every page in parallel — interleave.

  • Cache the OpenAPI spec and data-model JSON locally; they rarely change.

  • If you're orchestrating with the MCP server, the same limits apply (it proxies REST).

  • Respect Retry-After. Don't tight-loop after a 429.

Need more?

Contact [email protected] for higher limits on the Enterprise plan, or upgrade in Billing.

Was this page helpful?
Rate Limits