Skip to main content

Rate limits & idempotency

Per-PAT rate limits​

Every response carries RateLimit-* headers (RFC draft):

HeaderMeaning
RateLimit-LimitBucket size (e.g. 60)
RateLimit-RemainingRequests left in the current window
RateLimit-ResetSeconds until the window resets
RateLimit-Policy60;w=60 — 60 requests per 60-second window

Defaults (per PAT, per minute):

  • Writes (POST, PUT, PATCH, DELETE): 60/min
  • Reads (GET, HEAD): 300/min

Over the limit returns 429 rate_limited with a Retry-After header. Back off with jitter and retry.

Idempotency-Key​

Make any POST safe to retry:

curl -X POST https://api.vps-server.host/v1/servers/srv_42:reboot \
-H "Authorization: Bearer $PAT" \
-H "Idempotency-Key: $(uuidgen)"
  • Same key + same body within 24h → replays the cached response (Idempotent-Replay: true header)
  • Same key + different body → 409 idempotency_conflict
  • The key is your responsibility; use a fresh UUID per logical operation.

Retries​

Retryable status codes: 429, 502, 503, 504, plus 408 on the rare HTTP timeout. Use exponential backoff:

for attempt in range(5):
r = requests.post(...)
if r.status_code < 500 and r.status_code != 429:
break
time.sleep((2 ** attempt) + random.random())

Never retry on 400, 401, 403, 404, 409 (except idempotency_conflict on retry of a failed request — there the key was reused with a changed body, generate a new one), 422.