Rate Limits

Per-key tiers, the IP allowlist, the standard RateLimit headers TRUE returns, and what to do when you get a 429 instead of guessing.

Limits belong to the key, not the address

An API key is an identity. Limiting by IP address punishes everyone behind the same network and does nothing to an attacker who can change address, so TRUE meters per key: your own bucket, your own tier, independent of where you dial from.

Each key sits in a tier. The tier sets a sustained rate and a burst, plus caps on concurrent streams.

TierRequests / secondBurstWebSocket connectionsTopics per socketSSE connectionsIP allowlist
Retail5202404Optional
Pro2010041008Optional
Market maker1005001040016Required

Every key starts on Retail. Pro and Market maker are granted by TRUE, not self-selected: write to us with what you are building and the addresses you will call from.

How the bucket actually behaves

It is a token bucket, not a fixed window. The burst column is the size of the bucket, the rate column is how fast it refills.

A Market maker key that has been idle can fire 500 requests immediately, and then sustains 100 per second. A Retail key can fire 20 at once, then 5 per second. This matters when you start up: a bot that opens by loading thirty markets will get the first twenty through and be limited on the rest, even though its steady-state rate is nowhere near the cap.

The headers

Every response that passed a limit carries these. A 429 adds Retry-After.

HeaderMeaning
RateLimit-LimitYour bucket size
RateLimit-RemainingTokens left right now
RateLimit-ResetSeconds until a fully drained bucket is full again
Retry-AfterOn a 429 only: seconds until this request could succeed

Retry-After answers “when could I do this again”, not “when am I back to full”. Honour it exactly. Adding your own jitter on top of a server that already told you the answer just makes your client slower than it needs to be.

IP allowlists

Any key can be pinned to a list of IP addresses or CIDR ranges, IPv4 or IPv6. A request arriving from outside the list is refused with 403 ip_not_allowed even when the secret is correct.

This is the only control that survives the key leaking. A rate limit slows an attacker down and a scope narrows what they can reach, but an allowlist means the stolen string does not work from the thief’s machine at all.

  • An empty list means any IP. That is the default for every key, so nothing changes until you set one.
  • Up to 32 entries per key. Bare addresses are treated as a /32 or /128.
  • Changes are confirmed by an emailed code, and you get a second email naming what changed. Widening an allowlist is the most valuable thing an attacker with your session could do, so it costs a code from your inbox.
  • The app shows the address we see for you next to the field. Behind a mobile network, a VPN or CGNAT you cannot know your own egress address, and guessing it is how people lock themselves out.
Market maker keys must be pinned

A market maker key without an allowlist is a 100 request per second credential that works from anywhere on the internet. The tier cannot be granted without one.

What to do with a 429

  • Read the headers instead of retrying blind. RateLimit-Remaining tells you how close you are before you get refused; a client that watches it never sees a 429 in the first place.
  • Run your own token bucket matched to your tier. It is a dozen lines and it turns a rate limit from an error path into arithmetic.
  • Back off exponentially only when Retry-After is absent.
  • Do not open more connections to get more throughput. The bucket is per key, so a second socket shares the same tokens, and concurrent connections have their own cap.

Streams

Socket and SSE limits are counted as concurrent connections per key, not as requests. Closing a connection frees the slot immediately. Topic subscriptions per socket are capped by tier and the cap is sent to you in the ready frame, so your client can read it rather than hardcode it.

See also

Last updated: