Rate limits

Each API key gets 120 requests per 60-second window. The limit is per key, so splitting traffic across keys splits the budget.

The limit

Budget 120 requests per 60 seconds.
Counted against The API key, not the organization or the IP address.
Window Fixed 60-second buckets, not a rolling average. The counter resets at the boundary in X-RateLimit-Reset.
Scope All eight public endpoints share one counter. Reads and writes are not budgeted separately.

Response headers

Every response carries your current position in the window, so you do not have to guess.

Response headers
X-RateLimit-Limit: 120
X-RateLimit-Remaining: 117
X-RateLimit-Reset: 1771406400
X-RateLimit-Limit Requests allowed in a window.
X-RateLimit-Remaining Requests left in the current window.
X-RateLimit-Reset Unix timestamp when the window resets and the counter returns to zero.
Retry-After Seconds to wait. Sent only on HTTP 429.

When you exceed the limit

You get HTTP 429 with RATE_LIMIT_EXCEEDED and a Retry-After header. Honour the header rather than retrying on a fixed timer.

429 Too Many Requests
HTTP/1.1 429 Too Many Requests
Retry-After: 18
X-RateLimit-Limit: 120
X-RateLimit-Remaining: 0
X-RateLimit-Reset: 1771406400

{
  "detail": {
    "code": "RATE_LIMIT_EXCEEDED",
    "message": "Rate limit exceeded. Try again later.",
    "suggestion": "Maximum 120 requests per 60s window. Retry after 18s."
  }
}
Python
import time


def with_retry(send, attempts=5):
    """Retry on 429 using Retry-After, with an exponential fallback."""
    for attempt in range(attempts):
        response = send()
        if response.status_code != 429:
            return response

        wait = response.headers.get("Retry-After")
        time.sleep(int(wait) if wait else 2 ** attempt)

    raise RuntimeError("rate limited after %d attempts" % attempts)

Staying under the limit

  • Cache what does not move. Workspace ids and gateway credentials are stable between plan changes; fetch them once and reuse them.
  • Prefer one wide call to many narrow ones. GET /proxies returns every assignment in the organization, so you rarely need per-workspace calls in a loop.
  • Poll on a timer, not in a tight loop. When you are waiting for a workspace to finish provisioning, a few seconds between polls is plenty.
  • Give each service its own key so a noisy batch job cannot starve your user-facing traffic.

Need a higher limit?

Tell us what you are building and the shape of the traffic. Limits are configurable and we would rather raise yours than have you work around it.

hello@proxycharm.com