Pagination and caching
Pagination
Only lists that can be long use cursors. A page holds limit items. When more are left, the answer has a next_cursor. Send it back as cursor, with the same other parameters, to get the next page. The last page has no next_cursor (token holders return it as null).
| Route | limit | Default | Cursor |
|---|---|---|---|
| x402 payments | 1 to 200 | 50 | <block>.<log_index> |
| Perpl liquidations | 1 to 200 | 50 | <block>.<log_index> |
| Token holders | 1 to 100 | 25 | An opaque string |
A cursor stays valid. Newer items only add to the first page and never move older ones. A token holders cursor belongs to the chain and token it came from. A cursor Sona did not make answers 400 invalid_query.
curl -s "https://api.sonaintel.com/v1/chains/eip155:143/x402/payments?limit=2&cursor=88738438.120"Polymarket leaderboards page by limit (1 to 100, default 50) and offset (0 to 10000, default 0) instead.
ETag and If-None-Match
Every answer has an ETag, a fingerprint of its content. Send it back in If-None-Match on the next request for the same URL.
curl -si -H 'If-None-Match: "205cf86e7fb33774"' "https://api.sonaintel.com/v1/chains"An unchanged answer returns 304 Not Modified with no body and no credit cost. A 304 is free as long as Sona still holds the answer your ETag names, which it does while that answer is fresh. If Sona has to read the data again first, the usual cost is charged. A 304 still counts toward the rate limit.
You may send several ETags separated by commas. A W/ prefix is accepted and * matches any stored answer.
Cache headers
| Header | Meaning |
|---|---|
Cache-Control | How long a browser may reuse the answer. At most 5 seconds for chain data and 300 for the chain list and the OpenAPI document. no-store for errors, partial answers and pending transactions. |
Cloudflare-CDN-Cache-Control | How long the CDN may keep a shared copy. Only on answers every caller gets identically. Informational. |
X-Sona-Cache | Where the answer came from. Informational. |
X-Sona-Cache values.
| Value | Source |
|---|---|
l1 | Sona's in-memory cache |
l2 | Sona's shared cache |
miss | Read from the data source for this request |
stale | A slightly old copy, refreshed in the background while it is served |
static | A fixed answer prepared at start-up: the chain list and the OpenAPI document |
Freshness by route class
| Data | How fresh |
|---|---|
| Blocks, transactions, addresses | Read from the chain, with a short Cache-Control |
| x402 | Trails the chain by 10 blocks and refreshes every 30 seconds. A new payment usually appears within one to two minutes. |
| Perpl | A snapshot every 30 seconds. The market, liquidation map, stress and account routes can be up to 5 seconds old on top of that, and the concentration, liquidations and funding routes up to 30 seconds. |
| Token holders | Kept for 5 minutes, 15 seconds while the index is still building |
| Token transfers | Kept for 1 minute |
| Price charts | A 7d chart is kept for 10 minutes, a 1y or all chart for 6 hours, the current price for 1 minute |
| Top coins | Refreshed every 5 minutes, kept for 2 minutes |
| Polymarket history | A closed snapshot ending at Polygon block 85,948,288 (2026-04-24 07:43:40 UTC), answers kept for 10 minutes |
| Polymarket live markets and large trades | Refreshed once a minute, answers kept for 30 seconds |
Answers whose meta.as_of names a block tell you exactly how far the data reaches.