Limits and credits
The API is free and keyless. Limits apply to each IP address, or to each /64 network for IPv6.
Limits
| Limit | Value |
|---|---|
| Request rate | 1 request per second on average, bursts of up to 5 |
| Daily credits | 500, reset at 00:00 UTC |
Going over the rate gives 429 rate_limited. A request that would take you over 500 credits gives 429 credits_exhausted. Both say in Retry-After how many seconds to wait. For credits_exhausted that is the time until 00:00 UTC.
What a request costs
| Credits | Request |
|---|---|
| 0 | GET /v1/chains, /v1/openapi.json, /v1/status |
| 0 | GET /v1/tokens/search |
| 1 | A block, a transaction on a named chain |
| 1 | An address on one chain, a search |
| 1 | Every x402 route except the leaderboards |
| 1 | Every Perpl route except stress of all markets and concentration |
| 1 | Token, price, DeFi, market and Polymarket routes |
| 2 | An address on every chain (evm:) |
| 2 | An x402 leaderboard |
| 2 | Perpl stress of all markets, Perpl concentration |
| 5 | GET /v1/txs/{hash}, find a transaction on any chain |
| 5 | A search for a 64-character hash |
Each endpoint page in the API reference states its own cost.
When credits are charged
Credits are charged before the data is read, so a 404, 503 or 504 still costs. These cost nothing:
- A malformed ID (400).
- A chain that is not served (404).
- A hexadecimal block number (301).
- Search text that matches nothing.
- A 304 Not Modified.
Free requests still count toward the rate limit and still work after your credits run out. GET /healthz and GET /readyz use no credits and do not count toward the per-IP rate limit.
Headers
Answers that depend on you carry these headers. Answers that every caller gets identically leave them out, so read your balance from a latest block or from a 429.
| Header | Example | Meaning |
|---|---|---|
RateLimit-Policy | "public";q=5;w=5 | Quota of 5 requests per window of 5 seconds |
RateLimit | "public";r=4;t=1 | 4 requests left, the allowance is full again in 1 second |
X-Sona-Credits-Used | 217 | Credits spent today, counting this request |
X-Sona-Credits-Remaining | 283 | 500 minus the credits used |
Retry-After | 1 | Seconds to wait, on 429 and 503 |
When Sona's shared counter cannot be reached, it sets X-Sona-Degraded: 1, applies a local rate limit and omits the credit headers.
A 429 answer
{
"type": "urn:sona:problem:rate_limited",
"title": "Too many requests",
"status": 429,
"instance": "/v1/chains",
"code": "rate_limited",
"retry_after_s": 1
}Send the ETag of an answer you hold back in If-None-Match. An unchanged answer returns 304 and costs 0 credits. See Pagination and caching.