Skip to content

Rate Limiting

This guide explains how rate limits work on the Synthetix off-chain trading APIs and how to build clients that stay within limits.


Overview

Rate limits protect the system and ensure fair access for all users. Limits apply per subaccount and, on WebSocket, per IP address.

APIPer-subaccount limitPer-IP limit
REST (POST /v1/trade)YesNo
WebSocketYes (trade actions only)Yes (all actions)

How Limits Work

Limits use a token bucket model:

  • Each subaccount (and on WebSocket, each IP) has a bucket of tokens
  • Each request consumes tokens based on the action
  • Tokens refill over time
  • If a request would exceed available tokens, it is rejected with 429 Too Many Requests

Rate limit buckets (Mainnet)

Token costs are the same across environments. Bucket sizes may differ on Testnet. See Environments for environment-specific configuration.

Limit typeTokens per windowWindowScope
Per-subaccount (REST)1,00010 secondsPOST /v1/trade
Per-subaccount (WebSocket)1,00010 secondsTrade actions only
Per-IP (WebSocket)10,00010 secondsAll actions (trade + info)

Token costs — Trade actions (REST and WebSocket subaccount)

These costs apply to both REST POST /v1/trade and WebSocket trade actions. For placeOrders, cost = base cost × number of orders in the batch.

ActionBase costNotes
addDelegatedSigner100
cancelAllOrders2
cancelOrders2
createSubaccount100
getBalanceUpdates100
getDelegatedSigners20
getDelegationsForDelegate20
getFeeRate10
getFees10
getFundingPayments100
getOpenOrders10
getOrderHistory50
getPerformanceHistory100
getPortfolio10
getPositions10
getRateLimits20
getReferral20
getSubAccount20
getSubAccounts20
getTrades20
getTransfers10
modifyOrder5
modifyOrderBatch5
placeIsolatedOrder5
placeOrders5Cost = 5 × number of orders in batch
removeAllDelegatedSigners100
removeDelegatedSigner100
scheduleCancel5
transferCollateral5
updateIsolatedMargin5
updateLeverage5
updateSubAccountName100
voluntaryAutoExchange100
withdrawCollateral5

Token costs — WebSocket info actions (per-IP limit only)

These costs apply only to the per-IP bucket on WebSocket. Info actions do not consume from the per-subaccount bucket.

ActionCost
getCandles200
getCollaterals50
getFundingRate250
getFundingRateHistory1,000
getIsWhitelisted250
getLastTrades200
getMarketPrices200
getMarkets50
getMids50
getOpenInterest50
getOrderbook200
getSubAccountIds250

Trade actions on WebSocket also consume from the per-IP bucket using the same costs as the trade table above.


REST API

  • Endpoint: POST /v1/trade
  • Limit: Per authenticated subaccount
  • Scope: All trade actions

WebSocket API

Two limits apply:

  1. Per-IP limit — Applies to all actions (trade and info). Checked first.
  2. Per-subaccount limit — Applies to trade actions only.

Both must pass for a trade action. Multiple WebSocket connections from the same IP share the same per-IP budget.


Rate Limit Response

When you exceed a limit, the API returns:

  • HTTP status: 429 Too Many Requests
  • Error code: RATE_LIMIT_EXCEEDED
  • Category: RATE_LIMIT
  • Retryable: true

REST example

{
  "success": false,
  "clientRequestId": "abc-123",
  "error": {
    "code": "RATE_LIMIT_EXCEEDED",
    "category": "RATE_LIMIT",
    "message": "Rate limit exceeded for action 'placeOrders'",
    "retryable": true
  }
}

WebSocket example (subaccount limit)

{
  "success": false,
  "clientRequestId": "abc-123",
  "error": {
    "code": "RATE_LIMIT_EXCEEDED",
    "category": "RATE_LIMIT",
    "message": "Rate limit exceeded for action 'placeOrders'"
  }
}

WebSocket example (IP limit)

{
  "success": false,
  "clientRequestId": "abc-123",
  "error": {
    "code": "RATE_LIMIT_EXCEEDED",
    "category": "RATE_LIMIT",
    "message": "IP rate limit exceeded"
  }
}

Implementation Notes for Bots

1. Use exponential backoff on 429

When you receive 429 with RATE_LIMIT_EXCEEDED, wait before retrying. Start with about 1 second and increase on repeated failures (e.g. 1s, 2s, 4s).

2. Pace placeOrders requests

Each order in a batch consumes 5 tokens (cost = 5 × batch size). A batch of 20 orders consumes 100 tokens. With a 1,000-token subaccount limit per 10 seconds, large batches can hit limits quickly. Consider:

  • Smaller batches
  • Spacing requests over time
  • Avoiding bursts of many orders at once

3. Share IP budget on WebSocket

Per-IP limits apply across all WebSocket connections from the same IP. If you run multiple bots or connections from one server, they share the same IP budget.

4. Treat rate limits as retryable

Rate limit errors are marked retryable: true. Retry after a short delay instead of treating them as permanent failures.

5. Avoid hammering after a 429

Back off and reduce request rate after hitting a limit. Continuing at the same rate will keep triggering 429s.


Related Documentation