Operating system set to macOS
Documentation jurisdiction set to United States
Sign inConnect Claude

Rate limits

Per-key, sliding window, conservative defaults. Every key gets a request budget; you can raise (or lower) it per key from the portal — no email required.

The number

Default: 60 requests per minute, per key. Every bearer-authenticated endpoint shares the same bucket.

Three knobs feed the effective limit, evaluated in order — the first one set wins:

Where it livesWho sets itOverrides…
Per-key — rate_limit_per_minuteYou, from Dashboard → Keys (expand a row) or via client.keys.update(key_id, rate_limit_per_minute=…)Org override + default
Per-org — set by ArchieEmail [email protected] if you need an org-wide bump that applies to every new keyDefault
Default — 60/min(applies when neither override is set)—

Setting rate_limit_per_minute = 0 on a key blocks every request through it (useful for parking a key without revoking it). Setting it to null clears the override and falls back to the org / default.

Other surfaces

Beyond the per-key cap, a few endpoints have their own limits:

SurfaceDefault limitWindow
IP-level fairness gate120 req1 min
WorkStream cycle starts (workstream.run)20 starts1 min
SSE event tail (/api/v1/workstreams/cycles/{id}/events)4 concurrent(per key)
Portal key creation1 req per minute, 5 per dayper signed-in user

Setting a per-key override

Two paths — same backend, same instant effect:

Portal

  1. Open Dashboard → Keys.
  2. Click the chevron on the key row to expand its detail panel.
  3. Set Rate limit (per minute). The save happens 600ms after you stop typing; a small saved pill confirms.

SDK (heyarchie 1.2.0+)

from heyarchie import Archie

client = Archie()
client.keys.update("api_key_01KRVGB…", rate_limit_per_minute=30)
# Next request through that key sees the new cap immediately.

Cache invalidation is automatic — the backend flushes the per-key cache on PATCH so the new cap is honoured on the very next request. No 5-minute staleness window.

Headers on every response

Every API response includes the current quota state for the caller's key:

HeaderMeaning
X-RateLimit-LimitRequest budget for the window. Reflects the per-key override if set, else the org / default.
X-RateLimit-RemainingHow many you have left in the current window.
X-RateLimit-ResetUnix epoch seconds when the window rolls over.

When you're throttled

Limit-exceeded responses return HTTP 403 with the canonical error envelope and a Retry-After header (seconds):

HTTP/1.1 403 Forbidden
Content-Type: application/json
Retry-After: 23
X-RateLimit-Limit: 30
X-RateLimit-Remaining: 0
X-RateLimit-Reset: 1747356900

{
  "error": {
    "type": "api_error",
    "code": "RATE_LIMIT.USER",
    "message": "Rate limit exceeded for user 'c79225d0-…': 30 requests per 60s",
    "retry_after_seconds": 23
  }
}

Note: the code is RATE_LIMIT.USER when a per-key or default cap fires, and RATE_LIMIT.ORG when an org-wide override hits first.

Retry pattern

The official SDKs and CLI handle this automatically. Rolling your own client? Exponential backoff with Retry-After as the floor:

import time, random, httpx

def call_with_retry(url, headers, payload, max_attempts=5):
    delay = 1.0
    for attempt in range(max_attempts):
        r = httpx.post(url, headers=headers, json=payload)
        if r.status_code != 403 or "RATE_LIMIT" not in r.text:
            return r
        sleep_for = max(int(r.headers.get("Retry-After", "0")), delay) + random.random()
        time.sleep(sleep_for)
        delay = min(delay * 2, 30.0)
    raise RuntimeError(f"Still rate-limited after {max_attempts} attempts")

Pair the retry with the same idempotency_key from your original request on any write skill (workstream.run, workstream.cancel, etc.) so the server returns the original cycle id rather than starting a duplicate.

What never throttles

  • Skill catalogue listing (GET /api/v1/skills) — cached, free.
  • The OpenAPI spec (/openapi.json) — static.
  • Health check (/health).
  • OAuth discovery + dynamic client registration — bursty by nature; throttled at the network edge instead.

Next

  • Authentication — sk_* bearer, scopes, where keys live.
  • WorkStreams — when retries land on a cycle, use idempotency_key.
  • Python SDK — handles 403 RATE_LIMIT + Retry-After for you.