Skip to main content
The Chataigne API limits how many requests a single key can make. The public /v1 limit is currently 1000 requests per 60 seconds. Limits are applied per key, per surface — your public /v1 traffic and your Admin /admin/v1 traffic are metered independently, and each key has its own budget. Every response carries headers that tell you exactly where you stand, so you can pace requests proactively instead of waiting to be throttled.
Limits are enforced per key. Rotating a key or issuing additional keys does not raise your total throughput on a surface — each key carries its own independent budget against the same backend.

How metering works

  • Per key. Each API key (ch_org_… or ch_admin_…) is metered separately. One noisy key never starves another.
  • Per surface. The public surface (https://server.chataigne.ai/v1) and the Admin surface (https://server.chataigne.ai/admin/v1) have independent counters. Exhausting one does not affect the other.
  • 60-second window. The counter resets every 60 seconds. X-RateLimit-Reset tells you when the current window resets.

Rate limit headers

Every response — successful or not — includes the following headers:
X-RateLimit-Limit
integer
The maximum number of requests permitted in the current window for this key and surface.
X-RateLimit-Remaining
integer
The number of requests remaining in the current window. When this reaches 0, further requests are rejected with 429 until the window resets.
X-RateLimit-Reset
integer
The Unix timestamp (seconds) at which the current window resets and X-RateLimit-Remaining is replenished.
Retry-After
integer
Only present on 429 responses. The number of seconds to wait before retrying. Always honor this value.
Read these headers on every response and slow down before you hit zero — the cheapest rate limit is the one you never trip.
Example response headers
HTTP/1.1 200 OK
X-RateLimit-Limit: 1000
X-RateLimit-Remaining: 987
X-RateLimit-Reset: 1748520000
X-Request-Id: req_8f2c4a1b9d

When you’re throttled (429)

When a key exceeds its budget for a surface, the API responds with 429 Too Many Requests, a Retry-After header, and a standard error body of type rate_limit_error.
429 response
HTTP/1.1 429 Too Many Requests
Retry-After: 2
X-RateLimit-Limit: 1000
X-RateLimit-Remaining: 0
X-RateLimit-Reset: 1748520002
X-Request-Id: req_3a7e0c5f21
Content-Type: application/json
Error body
{
  "error": {
    "type": "rate_limit_error",
    "code": "rate_limit_exceeded",
    "message": "Too many requests. Retry after 2 seconds.",
    "request_id": "req_3a7e0c5f21"
  }
}
Retry-After is authoritative. Do not retry before the interval it specifies — retrying early consumes budget against the next window and prolongs throttling. Include the request_id from the error body when contacting support.

Backoff guidance

Build retry logic into every client. The recommended strategy:
  1. Honor Retry-After first. On a 429, wait at least the number of seconds it specifies before retrying.
  2. Use exponential backoff with jitter for other transient failures (e.g. 500 api_error). Double the delay each attempt and add a small random offset to avoid synchronized retry storms across clients.
  3. Cap your retries. Stop after a few attempts (e.g. 5) and surface the error rather than retrying indefinitely.
  4. Pace proactively. Watch X-RateLimit-Remaining and throttle yourself as it approaches zero — don’t wait for the 429.
  5. Make retries safe. For resource-creating POSTs, send an Idempotency-Key so a retry never creates a duplicate.
# Retry once, respecting the server's Retry-After interval.
URL="https://server.chataigne.ai/v1/locations/loc_3kf9x2qd7m"

response=$(curl -s -w "\n%{http_code}" "$URL" \
  -H "x-api-key: ch_org_live_2Yb8Qd4Rf1Tg" \
  -D /tmp/headers.txt)

status=$(echo "$response" | tail -n1)

if [ "$status" = "429" ]; then
  retry_after=$(grep -i '^retry-after:' /tmp/headers.txt | awk '{print $2}' | tr -d '\r')
  echo "Rate limited. Waiting ${retry_after}s before retry..."
  sleep "$retry_after"
  curl -s "$URL" -H "x-api-key: ch_org_live_2Yb8Qd4Rf1Tg"
fi

Reducing your request volume

Before scaling up retries, scale down the number of calls you make:

Expand related objects

Use expand[] to inline related resources in a single request — e.g. ?expand[]=locations — instead of fetching them one by one.

Paginate efficiently

Request larger pages (limit up to 100) and use cursor pagination (starting_after) to walk lists with fewer round trips.

Send idempotency keys

Idempotency-protected retries return the original response without doing duplicate work — safe to retry after a 429.

Use request IDs

Capture X-Request-Id from throttled responses so support can trace any anomalous limiting quickly.
Need a higher limit for a specific integration? Reach out with your org_… id and a representative request_id so we can review your traffic pattern.