Loading documentation

Access required

Your account doesn't have access to the documentation. Contact your administrator.

Sign out
Skip to main content

Rate limits

Status: stable Category: reference Added: 2026-04-20 Last reviewed: 2026-06-04

Summary

Rate limits are yours to set. From the developer portal you cap how fast your integration may call the API — across your whole account, a single key, or an individual route — so a runaway loop or a noisy deploy can never burn through more than you intended. Set a number, leave a field blank for no cap, and the API enforces it for you.

When a request would exceed one of your caps it returns 429 RateLimited, and the response tells you exactly which cap you hit and when it clears.

How limits work

You configure limits in the portal at three levels, and each level takes a value for any of six time windows — per minute, hour, day, week, month, or year:

LevelApplies to
Account-wideEvery key on your account, combined.
Per keyOne key on its own.
Per routeOne endpoint, for a chosen key. A route cap sits on top of that key's caps.

A request is checked against every cap that applies to it, and the tightest one wins. If your key allows 10 requests/minute but you've set a single route to 1/minute, the second call to that route in a minute is limited even though the key still has room. Any window you leave blank simply isn't enforced.

Because you set these values, you always know your limits — there's no hidden number to discover. Adjust them anytime in the portal; changes take effect within about a minute.

When you hit a limit

The request returns 429 Too Many Requests with headers describing the cap you hit:

HeaderMeaning
Retry-AfterSeconds to wait before retrying.
X-RateLimit-ScopeWhich limit you hit: version (a single key) or consumer (your whole account).
X-RateLimit-WindowThe window that was exceeded: minute, hour, day, week, month, or year.
X-RateLimit-LimitThe cap for that scope and window.
X-RateLimit-RemainingRequests left in the window — 0 on a 429.
X-RateLimit-ResetUnix epoch (seconds) when the window resets.

A real example — a key capped at 10 requests/minute, on the 11th call within the minute:

HTTP/1.1 429 Too Many Requests
Content-Type: application/json; charset=utf-8
Retry-After: 41
X-RateLimit-Scope: version
X-RateLimit-Window: minute
X-RateLimit-Limit: 10
X-RateLimit-Remaining: 0
X-RateLimit-Reset: 1780545600

The same shape appears for any cap. A per-route hourly cap reads X-RateLimit-Window: hour with that route's limit; an account-wide cap reads X-RateLimit-Scope: consumer. The headers only appear on a 429.

The 429 body

The body follows the standard error envelope (see errors.md):

{
"timestamp": "2026-06-04T03:16:44.034Z",
"error": "RateLimited",
"message": "Too many requests",
"request_id": "ce9ea793-1759-4cad-ab1b-fbc11475df3a",
"retry_after": 16
}

retry_after in the body and the Retry-After header always carry the same value. Read either.

When a limit resets

Windows are aligned to the calendar and reset on their own schedule — the minute window at the top of each minute, the day at 00:00 UTC, the month on the first, and so on. They reset independently: exhausting your hourly cap doesn't touch the daily one, and a minute clearing doesn't help if the hour you're in is still over.

That independence is easy to see in practice. Hammer a key past its per-minute cap and you get 429s until the next minute — then the very next request succeeds:

requests 1–10 -> 200
request 11 -> 429 X-RateLimit-Window: minute Retry-After: 13
... wait for the minute to roll over ...
next request -> 200

You never have to clear anything or contact us — once the window the cap belongs to rolls over, you're through again.

  1. Honor Retry-After. Don't retry before the indicated delay. Retrying early just reconfirms the limit and pushes your recovery out by another window.
  2. Back off on repeated 429s. If a retry after Retry-After is still limited, double your wait and add jitter: wait = Retry-After × 2^attempts + random(0, jitter).
  3. Cap the backoff. Don't grow the wait past a minute — at that point, surface the limit to your caller instead of looping.
  4. Pace bursts. If you have a batch to send, spread it out to stay under the caps you set rather than firing everything at once. If you regularly bump a cap, raise it in the portal.
  5. Don't retry 400, 401, 404, 413, 415, 422. These aren't rate-limit errors; retrying without changing the request wastes calls against your window.

Example retry loop (Python)

import os
import time
import random
import requests

def call_engine(path: str, body: dict, max_attempts: int = 5) -> dict:
attempt = 0
while True:
attempt += 1
resp = requests.post(
f"https://engine.tripod-health.com{path}",
headers={
"apikey": os.environ["ENGINE_API_KEY"],
"Content-Type": "application/json",
},
json=body,
timeout=30,
)
if resp.status_code != 429:
resp.raise_for_status()
return resp.json()
if attempt >= max_attempts:
resp.raise_for_status() # surface the 429
wait = int(resp.headers.get("Retry-After", "1"))
wait = wait * (2 ** (attempt - 1)) + random.uniform(0, 0.5)
time.sleep(min(wait, 60))

What counts against a limit

Every authenticated request counts — including 400, 404, and 5xx responses. A 400 ValidationError still consumes the window, so fix validation errors client-side before retrying.

What does not count:

  • Requests rejected with 401 before a key is accepted.
  • The unauthenticated GET /health liveness probe.
  • authentication.md — keys and how to send them.
  • errors.md — full error taxonomy, including RateLimited.
  • credits.md — credit metering and budgets; the contrasting "only successful calls are billed" rule.
  • conventions.md — response-shape rules.

Change history

DateChange
2026-04-20Initial publication.
2026-06-04Documented configurable account / key / route limits, the six time windows, and the X-RateLimit-* headers.