View as Markdown

Rate limits

The real limits, what each call costs, the headers you get, and how to back off without making things worse.

Tickwire uses a few plain token buckets, not a credit system. Each request costs a small, fixed number of units (its weight), and each bucket refills continuously. Limits apply per API key and per trading account, so one noisy integration can’t starve your others, and trades have their own budget, so polling can never block an order.

The limits

BucketBurst (units)Refill (units per second)Applies to
Per key10050Every authenticated request, by API key or token
Per account4020Requests that name a trading account (all keys together)
Per account, trades2010Trades on one account (all keys together)
Per IP, anonymous205Requests without a key (sign-up, public lists)
Per IP, failed auth200.5Requests with an invalid key
Per IP, MCP server20050The hosted MCP server (it also limits per key)

A request passes only if every bucket it uses has room, and then all of them are charged. A refused request charges nothing.

Streaming:

LimitValue
Concurrent WebSockets per key50
Request body16 MiB
WebSocket message16 MiB

What each call costs

ClassWeightBucketsCalls
Standard1key + accountReads and account changes: positions, orders, symbols, prices, account info
History5key + accountHistory and bulk reads: history-orders, history-deals, historical-market-data, historical-trades, terminal OrderHistory, PositionHistory, PriceHistory
Trade1key + account tradesPOST /users/current/…/trade, terminal OrderSend, OrderModify, OrderClose, CloseAll, POST /v1/execution/accounts/{id}/trade
Batch orders10keyPOST /v1/orders, POST /v1/orders/close (each leg is also checked by the account)
Stream connect5key + accountOpening a WebSocket. Frames on an open socket are free

So with one key you can, at a steady rate, make 50 reads a second, or 10 history calls a second, or trade 10 times a second on each account, and bursts of twice that.

Trades are never dropped silently

A trade refused by a rate limit is answered 429 with "sent": false and "outcome": "not_sent". It never reached the terminal and was not queued. You can resend it after Retry-After; use the same Idempotency-Key anyway, as for every trade.

Headers

Every response carries the tightest bucket’s state, in the IETF RateLimit header fields form, plus the same numbers under the older X- names:

HeaderMeaning
RateLimit-LimitThe bucket’s burst, in units
RateLimit-RemainingUnits left right now
RateLimit-ResetSeconds until the bucket is full again
RateLimit-Policy<burst>;w=<seconds to refill from empty>;name="<bucket>", e.g. 100;w=2;name="key"
X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-ResetThe same values

A 429 also carries Retry-After (seconds until this request would pass) and the standard error envelope with code rate_limited. metadata says which bucket refused it (bucket: key, account, account-trades, ip…), the request’s weight, and recommendedRetryTime, as on the /users/current/… API.

{ "error": "rate_limited", "message": "too many requests; retry after the time in Retry-After",
  "sent": false, "outcome": "not_sent",
  "metadata": { "recommendedRetryTime": "2026-09-25T11:02:20.000Z", "exceededConfig": "perAccountTrades",
                "resourceId": "account:acc_7Qx", "limit": 20, "bucket": "account-trades", "weight": 1 },
  "requestId": "4f1c…", "docUrl": "https://tickwire.io/docs/errors/rate_limited" }

On the /users/current/… routes error is TooManyRequestsError and our code is in code, so existing clients that read error handle it as they do today. Too many open WebSockets is 429 too_many_connections.

Backing off well

  • Wait at least Retry-After. Then back off exponentially with jitter, capped at 30 seconds or so. Without jitter, every client retries at the same instant and trips the limit again.
  • Never auto-retry a trade on 429 with a new idempotency key.
  • Stream instead of polling. One WebSocket replaces hundreds of GET /positions calls, and its frames don’t count against request limits.

What doesn’t count

Webhook deliveries, WebSocket frames we send you, and the health checks /_gateway/healthz and /_gateway/readyz.

Need more? Higher limits are available on request, per key; the headers always show the limits that apply to you.