Rate limits

Every key gets the same Card Data limit: 300 requests per minute, measured over a rolling 60-second window, independent of your credit balance. The limit controls how fast you may spend, credits control how much — throughput is never a plan differentiator.

The Gacha and Instant Pack APIs on the same key have their own, lower ceiling — 240 requests/minute plus shared concurrency caps that queue briefly and shed sustained overload with a 503 — documented on the Gacha overview.

The headers

Every response carries the state of your window:

X-RateLimit-Limit: 300
X-RateLimit-Remaining: 0
X-RateLimit-Reset: 1785470340
Retry-After: 60
HeaderMeaning
X-RateLimit-LimitRequests allowed in the window
X-RateLimit-RemainingRequests left before you're throttled
X-RateLimit-ResetWhen the window rolls over (Unix epoch seconds)
Retry-AfterPresent only on a 429. Seconds to wait, and always better than your own guess.

When you're throttled

You get 429. Throttled requests are never billed — rate limiting runs before metering — so a retry storm costs you latency but not credits. Back off exponentially, and cap the number of attempts:

async function call(path, attempt = 0) {
  const res = await fetch(BASE + path, { headers: { 'X-API-Key': KEY } });

  if (res.status === 429 && attempt < 5) {
    // Honour the server's own number first; only guess if it's absent.
    const wait = Number(res.headers.get('Retry-After')) ||
                 Math.min(2 ** attempt, 30);
    await new Promise((r) => setTimeout(r, wait * 1000));
    return call(path, attempt + 1);
  }

  return res;
}

Overload shedding. Separately from your per-key window, the API bounds concurrent catalog reads globally. Under heavy load a request can get an immediate 503 with Retry-After: 1 — also never billed. Treat it exactly like a 429: wait and retry.

Staying under the limit

  • Batch with pagination. One request for 100 cards is one request; 100 requests for one card each will throttle you and cost 100× the credits.
  • Serialize backfills. A bulk import should run one request at a time with a small delay, not a hundred in parallel. You'll finish sooner than a fleet that spends its life in backoff.
  • Never call us from the browser. Every user's page load then shares one key's window, and it exposes the key. Proxy through your own server and cache there.
  • Separate keys for separate workloads. Give your batch jobs a different key from your user-facing traffic so an overnight import can't throttle your product. Both draw from the same credit balance.