Usage limits

Two layers protect the API: a per-source-IP guard in front of every request, and a per-organization, per-endpoint quota. Both expose their state in standard headers: read them and your client paces itself.

5 min read

The two-layer model

LayerScopeLimitCode when exceeded
Per-IP guardPer source IP35,000 requests per minuteRATE_DDOS_EXCEEDED
Per-endpoint quotaPer organization and per endpointSpecific to each endpoint (ping allows 20 per minute)RATE_TPS_EXCEEDED

The per-IP guard runs first: it is a safety floor, not a commercial commitment. Hitting it usually means a misconfigured shared IP or a clear abuse pattern; the threshold is generous and legitimate traffic does not get close. The per-endpoint quota is the one you will see in normal operation, and each endpoint states its own in the reference.

The two layers count differently: the IP layer adds up every request coming from the same IP, no matter the endpoint; the quota layer adds up requests to a single endpoint. Rotating endpoints does not multiply the IP budget, and rotating IPs does not multiply the endpoint quota.

Sliding window, not fixed buckets

Both layers use a two-bucket weighted sliding window, the same technique Cloudflare and Stripe use. The intuition:

  • The current 60-second bucket counts at full weight.
  • The previous bucket counts with a weight that decays from 1.0 (start of the current bucket) to 0.0 (end of it).
  • The effective total is current + previous × weight.

With fixed buckets, a client could send the full limit at second 59 and the same again at second 0 of the next bucket: double the limit in two seconds. The sliding window catches that.

Response headers

The API follows RFC 9598 (RateLimit Header Fields for HTTP). Every quota-protected response carries:

HTTP
RateLimit-Limit:     20
RateLimit-Remaining: 18
RateLimit-Reset:     31
RateLimit-Policy:    20;w=60;name="endpoint"
RateLimit-Limit
Quota for the active window.
RateLimit-Remaining
Requests remaining in the active window.
RateLimit-Reset
Seconds until the active window resets.
RateLimit-Policy
Declarative quota in a parseable format. 20;w=60 means 20 requests in a 60-second sliding window.

On a 429 you also get Retry-After in seconds: wait at least that long before retrying.

Recommended strategy

  1. 01
    Throttle preemptively

    Read RateLimit-Remaining on every response. When it drops below 20 % of RateLimit-Limit, slow down so you reach the next reset with room to spare.

  2. 02
    Respect Retry-After

    When you get a 429, wait at least the seconds it reports before the next attempt. Retrying immediately just re-triggers the counter.

  3. 03
    Exponential backoff with jitter

    If retries keep failing, add an exponential delay (for example 2^n × 100 ms) with ±50 % random jitter. The jitter keeps thousands of clients from syncing on the same second.

Reference implementation
import time, random

def call_with_backoff(client, request, max_retries=5):
    for attempt in range(max_retries):
        r = client.send(request)
        if r.status_code != 429:
            return r
        wait = int(r.headers.get("Retry-After", "1"))
        # retroceso exponencial con techo en Retry-After * 4, mas variacion
        delay = min(wait * (2 ** attempt), wait * 4)
        delay += random.uniform(0, delay * 0.5)
        time.sleep(delay)
    return r  # quien llama decide que hacer al agotar los intentos

If you write your own client, parsing the policy is straightforward:

JavaScript
// RateLimit-Policy: 20;w=60;name="endpoint"
// -> limite 20, ventana 60 s, nombre "endpoint"
const [limit, ...params] = policy.split(';')
const window = Number(params.find((p) => p.startsWith('w='))?.slice(2))

What you see when it fires

Both layers return HTTP 429 with the standard envelope. The error.code tells you which one fired:

429 Too Many Requests
RateLimit-Limit:     20
RateLimit-Remaining: 0
RateLimit-Reset:     42
Retry-After:         42

{
  "success": false,
  "error": {
    "code": "RATE_TPS_EXCEEDED",
    "message": "You have exceeded the allowed request rate for this endpoint."
  }
}

Asking for a higher limit

If your traffic pattern legitimately exceeds an endpoint quota (bulk imports, campaigns, batch onboarding), talk to your account manager. We can raise the limit for your organization on a specific endpoint without touching the per-IP safety floor. Have this ready:

  • Expected peak and total daily volume.
  • Whether the peak is one-off (a launch) or sustained.
  • How you back off when limited, so we know the increase does not just move the problem.