Guide

Rate limits

Each API key may make a set number of requests a minute. Every response says how many are left; going over gets a 429 that says how long to wait.

The limit

Limits are per key, per minute. A key allows 120 requests a minute unless another limit was set when it was created — anything up to 10 000. Every request the key makes counts, whatever the endpoint — including ones that fail validation.

Keys have separate limits, so a bulk import on one key does not slow down the integration on another. Give each integration its own key. A key's limit is rate_limit_per_minute in GET /me.

The count starts with the first request and resets one minute later.

Headers

Every authenticated response carries the key's limit and what is left of it in the current minute:

HeaderValue
X-RateLimit-LimitRequests the key may make per minute.
X-RateLimit-RemainingRequests left in the current minute.
Retry-AfterOn a 429 only: seconds until the key may call again.
Response headers
HTTP/1.1 200 OK
Content-Type: application/json
X-RateLimit-Limit: 120
X-RateLimit-Remaining: 117

Over the limit

A request over the limit is not carried out. It gets 429 rate_limited, with the wait in seconds both in the Retry-After header and in retry_after in the body.

Response · 429
HTTP/1.1 429 Too Many Requests
Content-Type: application/json
Retry-After: 42
X-RateLimit-Limit: 120
X-RateLimit-Remaining: 0

{
  "message": "Rate limit exceeded.",
  "error": "rate_limited",
  "retry_after": 42
}

Wait that long, then retry. Retrying sooner only uses up the next minute's allowance.

async function request(url, init = {}) {
  for (let attempt = 0; ; attempt++) {
    const response = await fetch(url, {
      ...init,
      headers: { Authorization: `Bearer ${process.env.CLOSEPACT_API_KEY}`, ...init.headers },
    });

    if (response.status !== 429 || attempt === 3) return response;

    // Wait exactly as long as the API says, then try again.
    const seconds = Number(response.headers.get('Retry-After') ?? 1);
    await new Promise((resolve) => setTimeout(resolve, seconds * 1000));
  }
}

Staying under

  • Watch X-RateLimit-Remaining in long-running jobs and slow down before it reaches zero.
  • Read with limit=100 — a hundred records per request instead of twenty-five. See Pagination.
  • Subscribe to webhooks instead of polling for changes. See Webhooks.
  • Spread bulk work out rather than sending it in one burst, and run imports outside working hours.
  • Need more? Create a key with a higher limit, up to 10 000 a minute.