Skip to main content
Rate limits protect the platform and its participants. Unless a section says otherwise, a limit is configured per account rather than fixed platform-wide; contact our support team if you need one raised. Where no limit is configured for a budget, that budget is unlimited.

WS Connection Limits

WebSocket connections for Options and Perpetuals are served by the same gateway and share the same per-account allowances. A limit is keyed on your account only: the product, the contract filter and the client IP play no part.

WebSocket Connection Rate Limit

New connections are metered per account. Exceeding the allowance rejects the handshake with 429 Too Many Requests, a retry-after-ms header giving the wait in milliseconds, a Retry-After header giving it in whole seconds, rounded up, and a body carrying TOO_MANY_REQUESTS (0003):

Concurrent WebSocket Connection Limits

The number of connections you may hold open at the same time is capped per account. Every connection counts once, whether it is scoped to a single contract, to an expiration, or opened with market=ALL. When the cap is reached, further handshakes are rejected like a rate-limited one, but with retry-after-ms: 0: the cap clears when you close a connection, not with time.

Message and Subscription Limits

Each connection is also limited in how many messages it may send. Every inbound frame is charged, whatever the request type. A frame over the limit is not processed and is answered with a frame that carries no resultType, where retryAfterSec is the wait in seconds; the connection stays open:
A connection may hold at most 100 subscriptions (stream and contract filter pairs) unless a higher allowance is configured. A subscriptions query parameter over the limit rejects the handshake with 429 Too Many Requests and a body shaped like a rate-limited handshake’s, carrying the SUBSCRIPTION_LIMIT error (0012) and the message Too Many Requests: subscription limit is <max>. A subscribe request over the limit is answered with statusCode: 429, body: "Subscription limit reached (max N)" and the same error, and nothing is subscribed.

Order Creation and Operation Rate Limits

Account-Level Rate Limit

Requests are metered per account across all contracts and both transports, regardless of API keys. Each class of operation has its own budget, so exhausting one does not throttle the others. The key column names the budget as it is reported back to you when a request is refused. Every request costs one unit from its class’s budget. Order creation, modification and single cancellation are charged by the matching engine when the request reaches it, so a request refused earlier, for a malformed body or an expired token for instance, costs nothing. Two classes exist so that a caller who has spent the ordinary budgets can still close out:
  • Cancel all costs one unit of its own budget per call, however many orders it cancels, and the cancels it expands into cost nothing. On a cancelAllOrders request the engine charges the sweep before expanding it, so a refused sweep cancels nothing.
  • Reduce-only orders draw on their own allowance instead of the creation or modification budget. A modification cannot set the flag: it inherits the resting order’s, so modifying an ordinary order draws on the standard modification budget.
Liquidation and system orders are never metered. A budget is a set of sliding windows, per second, per minute, per hour and per day, and a request must fit under every window configured for its class. The per-second window is the burst limit: send requests at a steady rate rather than spending a whole minute’s allowance at once. Each cell reads default, or market-maker allowance: These are the defaults; a different allowance may be configured for your account. Market data is not metered: Get Expirations, Get Contracts and the public WebSocket streams are cached, shared data.

Maximum Open Orders Per Contract

The number of orders you may have open at once on one contract is capped: These are the defaults; a different cap may be configured for your account. Important details:
  • Checked on order creation and modification, never on cancellation
  • Every order resting on the contract counts, as does every order you have submitted for it that the engine has not yet applied; an order queued for cancellation counts until it leaves the book
  • Applies to limit and market orders combined
  • Exceeding this limit rejects the order with CREATE_ORDER_MAX_OPEN_ORDERS (10103), or MODIFY_ORDER_MAX_OPEN_ORDERS (10303) for a modification; see Error Codes
  • Use Get Open Orders to monitor your current count. Follow nextPageToken to count every page; each page consumes one options-read-orders request.
Hitting this limit usually means you are submitting faster than the engine settles: slow down until pending and cancelling orders drain.

In-Flight and Timing Limits

Independently of the per-account budgets, the matching engine bounds how much work it holds at once. These limits are fixed rather than configured per account: A request refused for one of these is reported on the Order Management Stream as TOO_MANY_INFLIGHT_ORDERS (10007), ENGINE_OVERLOADED (10008) or RECEIVE_WINDOW_EXCEEDED (10005) (see Error Codes) and has no effect: a refused cancel leaves the order resting, and a refused sweep cancels nothing. The receive window is measured inside the exchange, from the moment your request was queued, so it does not depend on your clock. Room in the in-flight limits returns as the engine settles earlier requests, so wait for their outcomes before resubmitting.

Handling Rate Limit Violations

Where a refusal is reported depends on where the budget is charged. Over HTTP, Cancel All Orders and the order and account read endpoints answer 429 Too Many Requests when their budget is spent, with a Retry-After header in whole seconds and a body carrying TOO_MANY_REQUESTS (0003) and naming the budget:
Create Order, Modify Order and Cancel Order are never refused with a 429: they answer 202 as soon as the request is queued, and the matching engine decides afterwards. A request the engine refuses for rate limiting is reported on the Order Management Stream like any other engine rejection, so hold a connection to that stream when you submit orders over HTTP. Over WebSocket, a refused request is answered on the Order Management Stream with statusCode: 400 and the RATE_LIMITED error (10006); see Error Codes for the shape. The WebSocket rejection carries no retry hint. Back off from that class of operation and resume at a steady rate; room returns gradually as the sliding windows move on, not all at once. Other classes are unaffected, so a refused create does not stop you cancelling. A rejection is delivered on a best-effort basis: under heavy load the engine may drop the message rather than delay order processing. Treat a request with no outcome as unknown and check Get Open Orders before resubmitting; see FAQs for safe-retry guidance.
Repeated violations or failure to respect rate limits may result in a ban.

Bans

There is no automatic soft ban on Options: a refused request is not followed by a disconnection or a timed lockout, and a rate-limited connection stays open. Repeated or abusive violations may lead to a ban applied to your account, under which every request in the banned class is refused as above until it is lifted. The cancel-all and reduce-only budgets are separate, so a ban on order creation does not prevent you from closing out.

Monitoring Rate Limit Usage

The Options APIs do not report your current usage: there is no quota field on WebSocket acknowledgments and no quota header on HTTP responses. The only signals are the 429 body’s remaining and retry_after_seconds on HTTP, once a request has already been refused, and the RATE_LIMITED rejection on the Order Management Stream. Meter each operation class on your side and stay below your allowance. If you receive a refusal, back off immediately and wait for Retry-After before sending further requests in that class.

Network Rate Limits

API Rate Limit

All HTTP endpoints, whether they are metered per account or not, sit behind a network-level limit shared by every user of one IP address: A client over this limit is blocked at the edge with 403 Forbidden until its request count falls back under the window. This limit is separate from the per-account budgets above and is applied before authentication, so refused requests do not reach the API.
We enforce fair usage of the HTTP endpoints. If we detect abnormal spamming of the API, we might ban the user.