Getting started

Units and limits

There are two independent limits, and they fail in different ways. Confusing them is the usual reason an integration behaves oddly under load.

Burst rate limitMonthly quota
Counted perAPI keyAccount (all your keys together)
Unit of accountRequestsUnits — endpoints cost different amounts
Window60 seconds, rollingCalendar month, UTC
HeadersX-RateLimit-*X-Quota-*
When it trips429 — wait seconds and retry429 — wait until the 1st, or upgrade

Why units and not requests

A request is not a request. A metadata read is an in-process lookup; a charts call is a multi-query fan-out to a paid upstream that we pay for per call. Charging both the same would mean either overcharging for the cheap one or subsidising the expensive one out of everybody else’s allowance.

TierUnitsEndpoints
Metadata0/v1/chains, /v1/protocols
Detail1/v1/positions/:chainId/:protocol/:id, /v1/pools/:chainId/:protocol/:id
List2/v1/positions, /v1/pools
Charts10…/charts on either resource

The live table is served from GET /v1/pricing/units and rendered on the pricing page. Read it from the API rather than hard-coding these numbers.

When the quota resets

00:00 UTC on the 1st of each month. Not a rolling 30 days, and not the anniversary of when you subscribed. X-Quota-Reset is the number of seconds until that instant, so you can act on it without doing calendar arithmetic.

The consequence worth planning for: subscribing on the 20th gives you the whole month’s allowance, and it resets eleven days later. We would rather be clear about that than quietly prorate an allowance nobody can predict.

Requests we refuse are not billed

Units are consumed before your request is served, and credited back on any 4xx. A malformed filter, an unknown position id, a 403 from a server key used in a browser — none of them cost anything. Billing for a request the API declined is not defensible, so we do not.

A 429 is the exception, and only technically: it is rejected before anything is consumed, so there is nothing to credit.

Handling a 429

Both kinds carry Retry-After in seconds. Honour it rather than retrying on a fixed timer — a burst 429 clears in seconds, a quota 429 clears at the month boundary, and the header is how you tell them apart without parsing prose. The body also carries retryAfterSec.

http
HTTP/1.1 429 Too Many Requests
Retry-After: 12
X-RateLimit-Limit: 300
X-RateLimit-Remaining: 0

{"error":"Rate limit exceeded","retryAfterSec":12}

If a paid plan lapses

Your account moves to Free and your keys keep working at Free limits. Nothing is revoked and nothing is deleted. Your consumed units for the current month are also reset at that point, so a downgrade cannot leave you locked out for the rest of the month on an allowance you had already spent.