Docs

Type a word or a question. Esc closes the search.

DE
Sign in Start free
Developers/Basics

Steady traffic, short bursts allowed.

The API limits requests with token buckets. A bucket holds a burst, refills at a steady rate and answers 429 rate_limit_exceeded when it is empty.

The buckets

A bucket starts full. Each request takes one token and tokens come back at the rate in the table. At 1,200 per minute that is 20 requests per second, and a burst of up to 300 at once is fine.

BucketApplies toRefillBurst
Per IP addressAll requests from one address except the check-ins below, authenticated or not. Not counted: OPTIONS, /v1/health, /v1/readyz and /v1/password/forgot.3,000 per minute300
Per API keyEvery authenticated request, counted per key.1,200 per minute300
Per heartbeat slug and IPCheck-ins to /v1/heartbeat/{slug}. These calls need no key.120 per minute20

An API call takes a token from the IP bucket first and then from the key bucket, and fails if either is empty. Idempotent replays count like any other request. Login, registration, contact and the public status page forms have their own, tighter buckets per IP address.

Headers

HeaderValue
X-RateLimit-LimitThe refill rate of the IP bucket in requests per minute.
X-RateLimit-RemainingWhole requests left in the IP bucket after this one.
X-RateLimit-ResetA Unix timestamp in seconds, the moment the IP bucket has refilled one request. The bucket refills continuously, so this is about now, not the end of a window.
Retry-AfterOnly on 429: whole seconds to wait, at least 1.

The X-RateLimit-* headers describe the IP bucket, not the key bucket. A key that has used up its own 300-request burst gets 429 and Retry-After: 1 while the headers still show a healthy IP bucket. Treat 429 and Retry-After as the signal, not Remaining.

curl -si https://app.upfour.io/v1/monitors \
  -H "Authorization: Bearer $UP4_API_KEY" | grep -i -E '^(HTTP|x-ratelimit|retry-after)'
HTTP/2 429
retry-after: 1
x-ratelimit-limit: 3000
x-ratelimit-remaining: 299
x-ratelimit-reset: 1793102400

{ "error": { "code": "rate_limit_exceeded", "message": "Rate limit exceeded", "request_id": "req_…" } }

After a 429

  1. Stop sending for the number of seconds in Retry-After.
  2. Retry the same request. A POST that carries an Idempotency-Key is safe to repeat.
  3. If the next answer is again 429, wait longer each time and add a random delay, so parallel workers do not retry together.

Spread bulk work instead of racing it: POST /monitors/batch and POST /monitors/bulk create or change many monitors in one request.

How the counts are kept

When up4 runs its shared counter store, all API servers count together. If that store is not available, each server counts for itself, so the ceiling you can reach during such a period can be higher, never unlimited.

Common mistakes

  • Waiting until X-RateLimit-Reset. It is almost now; use Retry-After.
  • Reading Remaining as your key’s budget. It is the IP bucket’s.
  • Running many workers behind one address and one key. They share both buckets.
  • Retrying at once in a tight loop. Every retry takes a token too.
  • Polling for state changes. A webhook sends them to you.