Rate limits & quotas

Two per-token bounds, plus one per-IP safety net:

Burst limit

60 requests/minute per token. Exceeding it returns 429 (code rate_limited) with Retry-After: 60.

Daily quota

5,000 requests per UTC day per token. Every counted response carries X-Quota-Limit and X-Quota-Remaining; exceeding it returns 429 (code quota_exceeded) with Retry-After set to the UTC-midnight reset. GET /v1/health is never counted.

Pace long jobs off X-Quota-Remaining rather than retrying into the wall.

Per-IP fallback

An additional 300 requests/minute per client IP guards against floods. If you run several tokens from one server, they share this IP budget — space them out or spread across IPs to stay clear of it.

Caching

Heavy GETs (project, task list) return a strong ETag. Send it back as If-None-Match and an unchanged resource answers 304 Not Modified with an empty body — poll cheaply that way. Cross-origin JavaScript can read ETag, X-Total-Count, X-Trace-Id, and Retry-After (CORS-exposed).

Idempotent creates

POST endpoints that create things accept an Idempotency-Key header. Retrying with the same key and same body replays the original response — no duplicate is created. The same key with a different body is 409 idempotency_conflict. Keys are scoped to your token and project.

One caveat: a replay returns the cached original response, not a live re-read — if the resource changed or was deleted since, the replay still echoes its creation snapshot. Use a fresh key per logical create; reuse a key only to retry the identical request.

Best practices

  • Back off on 429 rather than retrying immediately — honor the Retry-After header, whether the limiting bound was the burst limit or the daily quota.
  • Check the code field on a 429 (rate_limited vs quota_exceeded) to tell a short burst apart from a day you need to pace differently.
  • Watch X-Quota-Remaining on every response and slow down before you hit zero, instead of discovering the wall by getting 429s.