Skip to main content
Every /api/v1/* response tells you exactly where you stand in your window, so you never have to guess your quota. Read the headers on the response you already have — do not hard-code a number.
Runnable. Every header and status on this page was captured live from the partner sandbox at https://phosra-api-sandbox-production.up.railway.app on 2026-07-06. The /api/v1/platforms read used below needs no API key, so you can reproduce the exact bytes.

The limit

TierDefault limitWindowKeyed by
Sandbox / free100 requestsper 60 s (rolling)your developer org (authenticated) or source IP (unauthenticated)
PaidRaised per planper 60 syour developer org
The default of 100 requests/minute is the free-tier org limit (DefaultFreeRateLimitRPM). Authenticated calls are counted per developer org — every key in the org shares one bucket — so adding keys does not add quota. Unauthenticated calls (the sandbox read routes) are counted per source IP.
Discovery reads are unmetered. The unauthenticated OCSS discovery surface — /.well-known/ocss/trust-list, profiles, and Annex B editions — carries no rate-limit headers and is not counted against your window. Only the /api/v1/* surface is metered. Poll discovery cheaply with ETags.

Read your window off every response

Every metered response carries three headers. Read them and you always know your exact standing — no fixed quota to hard-code.
HeaderMeaningExample
X-RateLimit-LimitCeiling for the current window100
X-RateLimit-RemainingRequests left before a 42999
X-RateLimit-ResetUnix epoch seconds when the window resets1783321140
curl
curl -s -D - -o /dev/null \
  https://phosra-api-sandbox-production.up.railway.app/api/v1/platforms \
  | grep -i x-ratelimit
Response headers
x-ratelimit-limit: 100
x-ratelimit-remaining: 99
x-ratelimit-reset: 1783321140
X-RateLimit-Reset is Unix epoch seconds, not a duration and not milliseconds. To sleep until reset: wait = max(0, reset - now_seconds).

What a 429 looks like

When you exhaust the window you get 429 Too Many Requests with Retry-After (seconds) and the same three counters, so a single response tells you both how long to wait and that you are fully drained (remaining: 0). Captured live after exhausting the 100-request window:
Response · 429 (per-IP limiter)
HTTP/2 429
content-type: text/plain; charset=utf-8
retry-after: 60
x-ratelimit-limit: 100
x-ratelimit-remaining: 0
x-ratelimit-reset: 1783321440

Too Many Requests
Two 429 bodies, one contract. The per-IP throttle on unauthenticated routes returns the plaintext body above. The per-org limiter on authenticated routes returns the machine-readable house envelope instead — same status, same intent:
Response · 429 (per-org limiter)
{ "error": "Too Many Requests", "message": "rate limit exceeded", "code": 429 }
Branch on the status code (429) and honour Retry-After — never on the body shape. See the errors reference.

Handle it: wait for the reset, then retry

Do not retry a 429 immediately — sleep until the window resets, then send the request exactly once. Retry-After (seconds) is the simplest signal; X-RateLimit-Reset (absolute) is equivalent.
BASE=https://phosra-api-sandbox-production.up.railway.app
# Dump headers + status for one request
HDRS=$(curl -s -D - -o /dev/null -w "HTTP_CODE:%{http_code}" \
  -H "Authorization: Bearer $PHOSRA_API_KEY" \
  "$BASE/api/v1/families")

if echo "$HDRS" | grep -q "HTTP_CODE:429"; then
  RESET=$(echo "$HDRS" | tr -d '\r' | awk 'tolower($1)=="x-ratelimit-reset:"{print $2}')
  WAIT=$(( RESET - $(date +%s) )); [ "$WAIT" -lt 1 ] && WAIT=1
  sleep "$WAIT"
  # ...then retry the request once
fi

Staying under the limit

Read, don't assume

Watch X-RateLimit-Remaining and slow down as it approaches 0 instead of sprinting into a 429.

Poll discovery with ETags

Trust-list and edition reads are unmetered and support If-None-Match — a 304 costs you nothing. See Versioning.

Batch where the API allows

Prefer bulk-upsert rule writes over one call per rule; prefer a single fan-out enforce over per-child calls.

One bucket per org

Adding keys does not add quota — they share the org window. Need more? Contact us to raise rate_limit_rpm on your plan.

Next steps

Limits & quotas

The resource ceilings — page sizes, body caps, ID lengths — distinct from this 429 throttle.

Errors

The full status/class table, including where the 429 sits.

Pagination

Bound big reads so you make fewer, cheaper requests.