Starkscan

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.

ClassTypical useExample routes
lightcheap host/status, simple lookup reads, and balance-of for hosted keysGET /v1/{chain}/status, GET /v1/{chain}/block/{block_ref}, GET /v1/{chain}/tx/{tx_hash}, GET /v1/{chain}/token/{token}/balance-of/{address}
heavyindexed lists, wallet/profile reads, exact token reads, traces, search, contract reads, and batch helpersGET /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/summaries and POST /v1/{chain}/address/intelligence require utility/batch access.
  • Keep batches at or below 128 addresses.
  • Treat 403 as access-tier evidence, not a malformed route.
  • Treat 429 as rate pressure and honor Retry-After.
  • Treat 503 as bounded-query timeout backpressure and honor Retry-After when present. Current address batch timeout responses use Retry-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 routeExpected hosted key class
GET /v1/{chain}/token/{token}/balance-of/{address}light
GET /v1/{chain}/tx/{tx_hash}light
GET /v1/{chain}/address/{address}/transactionsheavy
GET /v1/{chain}/address/{address}/transfersheavy

Headers to read

Starkscan-issued API keys emit these budget headers on budgeted responses:

  • x-ratelimit-limit
  • x-ratelimit-remaining
  • x-ratelimit-policy
  • X-Starkscan-Route-Class
  • X-Starkscan-Rpc-Class on 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: 12

Retry rules

  • On 429 Too Many Requests, stop and honor Retry-After.
  • Do not retry immediately in a tight loop.
  • Keep concurrency bounded even when x-ratelimit-remaining still looks healthy.
  • Prefer the smallest route set that answers the task.
  • Do not let a heavy 429 stop unrelated light probes; keep backoff state per route class.
  • For address batch helpers, stay at or below 128 addresses per request, assume the request debits the heavy REST budget, and reduce batch size if you receive 503 with Retry-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 heavy 429 should not force an agent to stop cheap light status checks.
  • Log X-Request-Id on every failure.
  • Include rate-limit headers in issue reports when present.
  • Prefer cursor-based incremental reads over repeated full rescans.

On this page