Skip to main content

Rate Limits

Per-wallet rate limiting for order operations and API requests.

Overview​

Rate limiting uses fixed 60-second windows. Wallet limits come from the wallet's tier and are applied to:

  • Order placements (POST /order, PUT /order, WebSocket PlaceOrder, and TEE perp order submissions)
  • Order cancellations (DELETE /order, DELETE /order_cloid, and TEE perp cancels)
  • API requests (wallet-scoped reads and other signed writes)

Separate limits keyed by network source, with a process-wide ceiling, apply to cancels, agent authorization, MMP writes, and public risk simulations.

Counters are held in memory by each API process. They are not shared across replicas, so treat the published numbers as the most a single process will admit, not a cluster-wide budget.

Default Limits​

TierOrders/minCancels/minAPI Requests/minMax Open OrdersMax Positions
Default6012060010050
Tier 130603005020
Tier 21203001,200500200
Market Maker1,2002,4006,0005,000Unlimited

New wallets receive default limits. Contact support for tier upgrades. Your current API request limit is in the X-RateLimit-Limit header of any wallet-scoped read, for example GET /orders?wallet=....

Rate Limit Response​

When a rate limit is exceeded, the API returns 429 Too Many Requests:

{
"error": "rate_limit_exceeded",
"message": "Rate limit exceeded for OrderPlacement: 60 per minute, retry after 45 seconds",
"retry_after_secs": 45,
"limit": 60
}

Response Headers​

Wallet-limited endpoints return these headers. A 429 carries X-RateLimit-Limit, X-RateLimit-Remaining: 0, and Retry-After, but no X-RateLimit-Reset:

HeaderDescriptionExample
X-RateLimit-LimitMaximum requests allowed per window60
X-RateLimit-RemainingRequests remaining in current window42
X-RateLimit-ResetUnix timestamp in seconds when the window resets (success responses only)1737312060
Retry-AfterSeconds until retry (only on 429)45

Example Response Headers​

Successful request:

HTTP/1.1 200 OK
X-RateLimit-Limit: 60
X-RateLimit-Remaining: 42
X-RateLimit-Reset: 1737312060

Rate limited request:

HTTP/1.1 429 Too Many Requests
Retry-After: 45
X-RateLimit-Limit: 60
X-RateLimit-Remaining: 0

Rate Limit Categories​

Rate limits are tracked separately for each action type:

Order Placement​

Applies to:

  • POST /order and PUT /order (options orders)
  • WebSocket PlaceOrder
  • POST /bulk_order (bulk orders, each order in batch counts)
  • PUT /bulk_order (bulk replacements, each replacement counts)
  • POST /v1/tee-perp/orders/submit, POST /v1/tee-perp/orders/submit-trigger, and POST /v1/tee-perp/orders/submit-batch (TEE perp orders, a batch counts once)
  • POST /v1/tee-perp/leverage/submit

POST /bulk_order and PUT /bulk_order are capped at 50 entries per request.

Order Cancellation​

Applies to:

  • DELETE /order and DELETE /order_cloid
  • DELETE /bulk_order (bulk cancels, each cancel counts)
  • DELETE /bulk_order_cloid (bulk cancels by client order ID, each cancel counts)
  • POST /v1/tee-perp/cancels/submit, POST /v1/tee-perp/cancels/submit-by-oid, and POST /v1/tee-perp/schedule-cancel/submit (TEE perp cancels)
  • POST /v1/tee-perp/cancels/submit-prepared (manager-signed TEE perp cancel, counted against the manager wallet rather than the Account)

Every cancel route, including DELETE /bulk_order and DELETE /bulk_order_cloid, is also limited before signature verification to 6,000 cancel legs per network source and 60,000 legs process-wide per minute. A bulk cancel counts one leg per entry.

TEE Perp Routes​

The TEE perp routes listed above, except submit-prepared (manager-signed and counted against the manager wallet), are signed by an API wallet and counted against the Account:

  • Tier: The limit comes from the Account's tier, not from the API wallet that signed the request.
  • Shared window: TEE perp orders and options orders sent for the same Account address use one order window. Their cancels use one cancel window.
  • API wallets: An Account with several API wallets has one window. A new or rotated API wallet does not start a new one.
  • Headers: Every counted request returns the X-RateLimit-* headers, even when it is rejected later. A request rejected before it is counted, such as one with an unauthorized signature, returns none.

API Requests​

Counted per wallet against the tier's API Requests/min:

  • Wallet-scoped reads, keyed on the wallet query parameter
  • Signed writes not listed above, such as MMP configuration and margin mode

RFQ Submission​

POST /rfq/request and the WebSocket RFQ submit commands are limited to 10 per wallet per minute, independent of tier.

Risk Simulation​

Public portfolio and order simulations (POST /risk/simulate/portfolio, POST /risk/simulate/orders, and the perp preview POST /v1/tee-perp/preview) have separate limits of 60 requests per network source and 600 requests process-wide per minute. At most four simulations run concurrently in one API process. A request that exceeds a quota or finds the simulation workers saturated returns 429 Too Many Requests.

Agent Authorization​

POST /approve-agent, DELETE /revoke-agent, and DELETE /revoke-all-agents are limited before signature verification to 120 requests per network source and 1,200 requests process-wide per minute.

MMP Writes​

MMP configuration writes are limited before signature verification to 120 requests per network source and 1,200 requests process-wide per minute, in addition to the wallet's API request limit.

Position and Order Limits​

In addition to rate limits, wallets have maximum open order and position limits:

Limit TypeDescriptionRejection
Max Open OrdersMaximum concurrent open ordersNew order rejected while the wallet is at the limit
Max PositionsMaximum unique positions (-1 = unlimited)Order rejected if it would open a new position

These are order rejections, not HTTP errors. The order response is HTTP 200 with status: "REJECTED" and a reason such as:

max_open_orders_exceeded: current=100, limit=100
max_positions_exceeded: wallet 0x... has 50 positions, limit is 50

Best Practices​

Handling Rate Limits​

  1. Monitor headers: Track X-RateLimit-Remaining proactively
  2. Respect Retry-After: Wait the specified duration before retrying
  3. Implement backoff: Use exponential backoff on repeated 429s
import time

def place_order_with_retry(order, max_retries=3):
for attempt in range(max_retries):
response = api.place_order(order)

if response.status_code == 429:
retry_after = int(response.headers.get('Retry-After', 60))
time.sleep(retry_after)
continue

return response

raise RateLimitError("Max retries exceeded")

Optimizing Request Usage​

  1. Use bulk endpoints: POST /bulk_order for multiple orders in one request
  2. Batch cancels: DELETE /bulk_order or DELETE /bulk_order_cloid instead of multiple DELETE /order requests
  3. WebSocket for updates: Subscribe to order updates instead of polling GET /orders

Monitoring​

Track these client-side metrics:

  • Request rate per action type
  • X-RateLimit-Remaining trends
  • 429 response frequency
  • Average Retry-After durations

Error Reference​

HTTP StatusError CodeDescription
429rate_limit_exceededRate limit exceeded, retry after specified time

See Errors for the full error reference.