Rate Limiting

How API request limits work across HTTP and WebSocket

Overview

All API requests — whether over HTTP or WebSocket — share a single rate-limit budget of 3 requests per second (180 per minute) per user, with a burst allowance of up to 20 requests allowed. This budget is shared across both protocols: using the HTTP API and WebSocket API simultaneously does not double your allowance.


How the Limit Works

Rate limiting uses a smooth, token-based algorithm rather than a hard window. Think of it as a bucket that holds up to 20 tokens and refills at a steady rate of 3 tokens per second.

Every request consumes one token. If the bucket is empty, the request is rejected. Since the bucket refills continuously, a brief pause is all you need to recover — you never have to wait for a full window to reset.

In practice, this means:

  • Burst — if you haven't made a request recently, you can fire up to 20 requests as fast as you want.

  • Sustained — after the burst is spent, you can make 1 request roughly every 330ms (3 per second).

  • Recovery — pausing for about 7 seconds fully recharges the burst allowance. You do not need to wait a full minute.


HTTP API

HTTP requests (/v1/api/*) are rate-limited at two layers.

Edge protection enforces a global cap of per minute per IP address. Requests exceeding this are rejected before they reach CrossTrade's servers. This protects infrastructure and is not configurable. If you exceed this protection level for any reason (this should never happen; it's multiple times higher than the application-level allowance), then our firewall will block all requests from your IP address for an amount of time commensurate with the infraction.

The application enforces the per-user budget described above. When you exceed it, you'll receive a 429 HTTP response with the body {"error": "Rate limit exceeded"}. Simply wait briefly and retry.


WebSocket API

The WebSocket API (/ws/stream) applies the same per-user budget as HTTP, with additional protections specific to persistent connections.

RPC Messages

Every action: "rpc" message counts against the shared rate-limit budget. When a message is rejected, you receive an error response on that specific message rather than having your connection closed:

Subscription Management

Subscription actions (subscribe, unsubscribe, streamPnl) have their own separate, tighter limit of approximately 20 per minute with a burst of 5. These actions trigger backend work on your trading platform and shouldn't need to be called frequently. Normal usage patterns — subscribing to a handful of instruments on Connect, toggling P&L streaming on or off — will never come close to this limit.

Connection Limits

Each CrossTrade account is limited to 1 active WebSocket connection to /ws/stream. If a new connection appears, we will automatically close any open sockets.

The WebSocket handshake itself is rate-limited to 5 new connections per IP per minute. This prevents connection-storm abuse from rapid connect/disconnect cycles. Since the API enforces single-session per user (opening a new connection closes the previous one), legitimate usage should never hit this limit.


Abuse Detection and Disconnection

The WebSocket API includes a circuit breaker to protect against clients that ignore rate-limit errors and continue flooding messages.

Each time an RPC message is rejected for exceeding the rate limit, a violation counter increments. Each successful request decays the counter back toward zero, so occasional rate-limit hits during normal usage will not accumulate.

If a client accumulates more than 10 consecutive violations, the server closes the WebSocket connection with close code 1008 (Policy Violation) and the message "Rate limit abuse." This is intentionally aggressive — a well-behaved client that respects error responses will never trigger it.

To avoid disconnection:

  • Check every response for rate-limit errors before sending the next message.

  • Implement backoff when you receive a rate-limit error. A simple strategy: pause for 500ms after a rejection, then resume.

  • Do not retry rate-limited requests immediately in a tight loop.

Message Size

Individual WebSocket messages are limited to 1 MB. Messages exceeding this size will cause the connection to close. All standard API payloads are well under this limit.

Last updated