Rate Limits

What each surface allows per key, the IP allowlist, the 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 wherever a key is involved: your own bucket, independent of where you dial from. Public market data, which has no key, is metered per address.

Limits today

SurfaceLimit
Bot API, per key600 reads and 120 trading calls a minute. X-RateLimit-Remaining on every answer, 429 with Retry-After beyond. Ten keys per user.
MCP, per keymarket data 120 a minute, chat 10 a minute, points 30 a minute, key validation 60 a minute. 429 with Retry-After.
TRUE market data REST (public)600 requests a minute per address
SSE stream32 concurrent streams and 240 connects a minute per address
Market data WebSocket6 sockets and 60 handshakes a minute per account (32 and 240 per address), 40 topics per socket, 30 client frames burst and 5 a second sustained
TRUE Quotes (quotes.truefinance.ai), per key60 requests a minute on the free tier, 600 on pro, 6,000 on quant; socket caps on Realtime
Venue REST (dex-prod.truefinance.ai)no published per address limit; design for 600 reads and 120 order calls a minute

TRUE’s own services are exempt from every edge rule, so a limit you hit is yours alone.

Higher tiers

A key can be moved to a pro or market maker tier with a higher sustained rate and burst, more sockets and more topics per socket. Tiers are granted by TRUE against a described use case, not self-selected, and a market maker tier is never granted without an IP allowlist. Write to the team through the app (Kira) with what you are building, the markets you intend to quote and the addresses you will call from.

The headers

HeaderMeaning
X-RateLimit-RemainingBot API: calls left in the current minute for this key and class (read or trade)
Retry-AfterOn a 429: 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

A bot key can be pinned to a list of IP addresses or CIDR ranges, IPv4 or IPv6, when you create it or later from the Bots tab. A request arriving from outside the list is refused with 403 ip_not_allowed even when the signature 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, so nothing changes until you set one.
  • Bare addresses are treated as a /32 or /128.
  • The refusal names the address we saw, so a bot behind a changing egress address can tell you what to add.

For MCP keys, an allowlist is set by TRUE on request together with a tier.

Market maker keys must be pinned

A market maker key without an allowlist is a high rate 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. X-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 limiter matched to your key’s allowance. It is a dozen lines and it turns a rate limit from an error path into arithmetic. The Hummingbot and ccxt connectors already do this.
  • 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, not as requests. Closing a connection frees the slot immediately. The topic cap per socket is sent to you in the ready frame (maxTopics), so your client can read it rather than hardcode it.

See also

Last updated: