Rate limits
Understand Starkscan route-class budgets, headers, and the correct retry behavior for external API keys.
Rate limits
Starkscan rate-limits external API keys by route class.
Treat rate limits as part of the HTTP contract, not as a hidden operational detail.
Route classes
Current hosted external keys use two budget classes. The OpenAPI schema reserves
additional fine-grained class names for self-hosted/internal deployments, but
clients using Starkscan-issued API keys should back off on the class they
actually receive in X-Starkscan-Route-Class.
| Class | Typical use | Example routes |
|---|---|---|
light | cheap host/status, simple lookup reads, and balance-of for hosted keys | GET /v1/{chain}/status, GET /v1/{chain}/block/{block_ref}, GET /v1/{chain}/tx/{tx_hash}, GET /v1/{chain}/token/{token}/balance-of/{address} |
heavy | indexed lists, wallet/profile reads, exact token reads, traces, search, contract reads, and batch helpers | GET /v1/{chain}/token/{token}/total-supply, GET /v1/{chain}/address/{address}/transactions, GET /v1/{chain}/address/{address}/transfers, GET /v1/{chain}/tx/{tx_hash}/trace, GET /v1/{chain}/search, GET /v1/{chain}/contract/{address}/read, POST /v1/{chain}/tx/previews, POST /v1/{chain}/address/summaries, POST /v1/{chain}/address/intelligence |
The exact numeric budget is deployment-controlled. Read the headers instead of hard-coding assumptions into clients.
Access tier and rate budget are separate. Address batch helpers require a
utility or batch-scope key, preserve request order, and debit the hosted
heavy REST budget. Named wallet, paymaster, and migration policies can receive
higher per-minute heavy limits than ordinary expanded keys; clients should
still use the response headers as the source of truth.
For batch address classification specifically:
POST /v1/{chain}/address/summariesandPOST /v1/{chain}/address/intelligencerequire utility/batch access.- Keep batches at or below 128 addresses.
- Treat
403as access-tier evidence, not a malformed route. - Treat
429as rate pressure and honorRetry-After. - Treat
503as bounded-query timeout backpressure and honorRetry-Afterwhen present. Current address batch timeout responses useRetry-After: 2.
For authenticated JSON-RPC beta traffic, Starkscan can emit finer rpc_* method
classes such as rpc_read_light, rpc_read_state, rpc_read_history,
rpc_simulation, and rpc_write in X-Starkscan-Rpc-Class
(x-starkscan-rpc-class). RPC requests keep X-Starkscan-Route-Class as
batch, so back off by the RPC class header when present and by the route class
header for normal REST traffic.
For wallet/app Voyager migrations, treat the replacement set as:
| Migration route | Expected hosted key class |
|---|---|
GET /v1/{chain}/token/{token}/balance-of/{address} | light |
GET /v1/{chain}/tx/{tx_hash} | light |
GET /v1/{chain}/address/{address}/transactions | heavy |
GET /v1/{chain}/address/{address}/transfers | heavy |
Headers to read
Starkscan-issued API keys emit these budget headers on budgeted responses:
x-ratelimit-limitx-ratelimit-remainingx-ratelimit-policyX-Starkscan-Route-ClassX-Starkscan-Rpc-Classon authenticated JSON-RPC beta responses
On 429 Too Many Requests, Starkscan also emits:
Retry-After
Example response headers:
x-ratelimit-limit: 30
x-ratelimit-remaining: 0
x-ratelimit-policy: heavy;w=60
X-Starkscan-Route-Class: heavy
retry-after: 12Retry rules
- On
429 Too Many Requests, stop and honorRetry-After. - Do not retry immediately in a tight loop.
- Keep concurrency bounded even when
x-ratelimit-remainingstill looks healthy. - Prefer the smallest route set that answers the task.
- Do not let a
heavy429 stop unrelatedlightprobes; keep backoff state per route class. - For address batch helpers, stay at or below 128 addresses per request, assume the request debits the
heavyREST budget, and reduce batch size if you receive503withRetry-After.
Example 429
curl -i \
-H "X-Starkscan-Api-Key: $STARKSCAN_API_KEY" \
"${STARKSCAN_BASE_URL:-https://api.starkscan.co}/v1/$STARKSCAN_CHAIN/contract/<address>/read?selector=<selector>"Representative response:
HTTP/1.1 429 Too Many Requests
retry-after: 12
x-ratelimit-limit: 30
x-ratelimit-remaining: 0
x-ratelimit-policy: heavy;w=60
X-Starkscan-Route-Class: heavy
content-type: application/json; charset=utf-8
{"code":"rate_limited","message":"Rate limit exceeded; retry shortly","docSlug":"api/rate-limits","requestId":"mzk-..."}Operational note
Current public-read rate limiting is process-local fixed-window state:
- counters reset on process restart
- each replica enforces its own independent window budget
- boundary-adjacent bursts can briefly approach roughly double the minute budget
Do not build client correctness on an assumption that every host behaves like one perfectly global distributed limiter.
Best practices for agents
- Use Agent HTTP quickstart as the bounded starter contract.
- Back off by route class. A
heavy429 should not force an agent to stop cheaplightstatus checks. - Log
X-Request-Idon every failure. - Include rate-limit headers in issue reports when present.
- Prefer cursor-based incremental reads over repeated full rescans.