Foreshock

API

Rate limits

Per-account limits reported on every response, and why a 429 on the decision endpoint is a hold rather than a delay.

Updated
2026-08-24

The headers

Every response carries the current state of your window.

HeaderMeaning
RateLimit-LimitRequests permitted in the current window for this account.
RateLimit-RemainingRequests remaining in the current window.
RateLimit-ResetSeconds until the current window resets.

Read them on success, not only on failure. A client that first learns about the limit from a 429 is a client that will hit it during an incident, which is exactly when it can least afford to.

When you exceed it

429 with type: .../rate-limited and a Retry-After header in seconds. Back off for at least that long, with jitter, and prefer a token bucket on your side over retry storms.

On the decision endpoint, a 429 is a hold

POST /v1/decide/deposit returns a distinct 429 shape carrying fail_closed_action: HOLD.

{
  "type": "https://foreshock.org/problems/rate-limited",
  "title": "Too many requests",
  "status": 429,
  "detail": "Rate limit exceeded. No verdict was produced; treat as HOLD.",
  "request_id": "req_EXAMPLE0000000008",
  "fail_closed_action": "HOLD"
}

No verdict was produced. Waiting is not a substitute for a verdict: the deposit stays on HOLD until a 200 is received, however long the back-off runs.

Keeping under the limit

Screening is cheaper than deciding, and layer A is never billed — but neither is free of rate limit. Two habits keep the pressure down:

  • Decide once per deposit, with a stable Idempotency-Key. Replays are cheap and are not billed again, but a fresh key per attempt turns one deposit into many decisions.
  • Run the exposure cursor loop on a steady cadence rather than polling in a tight loop. next_cursor: null means you are caught up; sleep before asking again.