MeowQuant is an independent third-party information site, not owned or operated by any exchange. This page contains no promotional links or invite codes. Full disclosure →

OKX · API Hands-On

How are OKX API rate limits counted: per IP, account or instrument?

The sub-account rule in the OKX API docs, "a maximum of 1000 order requests per 2 seconds", does not work out to 500 orders a second fired at one contract. On a single instrument ID, the single-order endpoint POST /api/v5/trade/order accepts only 60 requests per 2 seconds. The 1,000 covers new orders and amendments across every instrument in the sub-account; the 60 covers one instrument on one endpoint. Both apply at once, and whichever fills first is the one that rejects the request.

OKX API rate limits have no single requests-per-second figure. Public market data endpoints are counted by IP address, private endpoints by User ID (each sub-account has its own User ID), order placement, cancellation and amendment go down to the instrument ID, and WebSocket login and subscription are counted per connection. An ordinary breach returns error code 50011; going over the sub-account's 1,000 returns 50061.

Which OKX endpoints are limited per IP and which per User ID

It depends on whether the endpoint needs authentication. Public market data endpoints, called without an API key signature, draw on an allowance tied to the outgoing IP address. Signed private endpoints are tied to the User ID, with the master account and each sub-account counted separately. Here are eight endpoints a trading script might call:

EndpointRate limitCounted by
GET /api/v5/market/ticker20 requests per 2sIP
GET /api/v5/market/tickers20 requests per 2sIP
GET /api/v5/market/books40 requests per 2sIP
GET /api/v5/market/candles40 requests per 2sIP
GET /api/v5/account/balance10 requests per 2sUser ID
GET /api/v5/trade/orders-pending60 requests per 2sUser ID
GET /api/v5/trade/order60 requests per 2sUser ID + Instrument ID (Instrument Family for options)
GET /api/v5/trade/account-rate-limit1 request per secondUser ID

For the rows counted by IP, several scripts on one machine share a single allowance when they pull public market data, even if they hold API keys from different accounts. Private endpoints are counted differently: each sub-account has its own User ID, and the allowance is counted per User ID.

WebSocket has rules of its own. Connecting is limited to 3 requests per second per IP. On each connection, subscribe, unsubscribe and login requests together are limited to 480 per hour, and the connection breaks automatically if no subscription is established, or no data has been pushed, for more than 30 seconds. For private channels such as orders, account and positions, a sub-account can hold at most 30 connections on the same channel.

How many order, cancel and amend requests OKX allows per 2 seconds

The three kinds of request have independent allowances: once the 60 for placing orders are used, the 60 for cancelling are still there. Allowances are defined per User ID + Instrument ID, so BTC-USDT-SWAP and ETH-USDT-SWAP each have their own. Options are the exception. Their limits are defined at the Instrument Family level, and the Get instruments endpoint shows which Instrument Family an option belongs to.

EndpointRate limitCounted inCounts toward the sub-account limit
POST /api/v5/trade/order60 requests per 2sRequestsYes
POST /api/v5/trade/batch-orders300 orders per 2sOrdersYes, each order individually
POST /api/v5/trade/amend-order60 requests per 2sRequestsYes
POST /api/v5/trade/amend-batch-orders300 orders per 2sOrdersYes, each order individually
POST /api/v5/trade/cancel-order60 requests per 2sRequestsNo
POST /api/v5/trade/cancel-batch-orders300 orders per 2sOrdersNo
  • Multiple-order endpoints and single-order endpoints have separate allowances too. A multiple-order request carrying 5 orders uses 5 of the 300. When a multiple-order request carries only 1 order, it is counted as a single order and comes out of the 60.
  • Placing, cancelling and amending share their limits across REST and WebSocket, so moving order placement from REST to WebSocket does not produce a second 60. Market data over WebSocket is bound by the connection limit and by the subscribe and login count on each connection, which are separate from the trading allowances here.
  • An order can have at most 3 amend requests in progress at the same time. A further amend request submitted while 3 are still in progress is rejected with 51513.
  • Copy trading lead traders have far lower limits on their lead instruments: 4 requests per 2 seconds for placing an order and for amending one, and 4 orders per 2 seconds on the multiple-order endpoints for placing and amending.

Add up what one instrument allows: 60 single-order requests plus 300 orders through the multiple-order endpoint come to at most 360 new orders in 2 seconds, and amendments are the same 60 + 300 = 360. New orders and amendments together make 720, short of 1,000. On that arithmetic, a script trading a single instrument runs into the instrument-level 50011 first, and the sub-account's 1,000 only comes within reach when several instruments are traded at once.

Error 50061 means the sub-account hit its 1,000 requests per 2 seconds

50061 comes back with the message "You've reached the maximum order rate limit for this account." The code for an endpoint's own limit, 50011, reads "Rate limit reached. Please refer to API documentation and throttle requests accordingly." 50061 belongs to the sub-account rate limit: each sub-account is allowed a maximum of 1,000 order requests per 2 seconds. Only new order requests and amendment requests count toward it, so cancellations do not, and in a batch request with multiple orders each order is counted individually. The endpoints it covers are the REST Place order, Place multiple orders, Amend order and Amend multiple orders, together with the WebSocket Place order, Place multiple orders, Amend order and Amend multiple orders. It operates in parallel with the limit per instrument ID, and a request has to satisfy both.

An example: a script runs three perpetual swaps at once and, within 2 seconds, uses all 60 single-order requests and all 300 multiple-order slots on each, for 360 × 3 = 1,080 new orders. No single instrument is over its own limit, but the sub-account total has passed 1,000, and the error that comes back is 50061, not 50011.

The fill ratio section of the docs includes this line: "Block trading, spread trading, MMP and spot/margin orders are exempted from the sub-account rate limit." (MMP is Market Maker Protection, OKX's mechanism for market makers to pull their quotes.) So orders from a spot-only script do not count toward the 1,000, and the limit it mainly has to watch is the 60 requests per 2 seconds on each instrument. Even so, keep the local counter for the sub-account total in place, and if a 50061 does arrive, handle it as follows.

On a 50061, slowing only the pair that returned the error may not be enough. The allowance is shared by every instrument in the sub-account, so the figure to bring down is the total of new orders and amendments across all of them. Cancellations do not count toward this limit; cancel what needs cancelling as usual.

From VIP5 up, the sub-account limit has 8 tiers set by fill ratio

These tiers apply only to users at VIP5 and above. For them, a sub-account's cap on new orders plus amendments per 2 seconds is set by its fill ratio, in 8 tiers from 1,000 to 10,000.

At 00:00 UTC each day, the system calculates two ratios from the past 7 days of data:

  • Sub-account fill ratio = the sub-account's trade volume in USDT ÷ Σ(new and amendment request count per symbol × symbol multiplier). The master trading account is itself treated as a sub-account here.
  • Master account aggregated fill ratio = the trade volume in USDT at master account level ÷ Σ(new and amendment count per symbol × symbol multiplier, over all sub-accounts).

Only successful order requests (sCode=0) are counted. Block trading, spread trading, MMP and fiat orders are left out of the order count, and block trading and spread trading are left out of the trade volume.

The symbol multiplier adjusts the weight of each symbol in the ratio. A smaller multiplier (below 1) is used for smaller pairs that need more updates per unit of trading volume, so each of their requests weighs less in the denominator. Every instrument has a default multiplier, and some have an overridden one:

InstTypeOverride ruleDefault symbol multiplierOverridden symbol multiplier
Perpetual FuturesPer instrument ID0.21: BTC-USDT-SWAP, BTC-USD-SWAP, ETH-USDT-SWAP, ETH-USD-SWAP
Expiry FuturesPer instrument family0.10.3: BTC-USDT, BTC-USD, ETH-USDT, ETH-USD
SpotPer instrument ID0.10.5: BTC-USDT, ETH-USDT
OptionsPer instrument family0.1—

Spot orders are exempt from the sub-account rate limit, yet Spot still has a row in the multiplier table, and XRP-USDT's trade volume and order count go into the ratio in the calculation further down.

Symbol multiplier table from the Fill ratio based sub-account rate limit section of the OKX API docs, with rows for Perpetual Futures, Expiry Futures, Spot and Options, overridden multipliers of 1, 0.3 and 0.5 and default multipliers of 0.2, 0.1, 0.1 and 0.1, followed by two paragraphs on what the fill ratio computation excludes and on the 08:00 UTC determination
As of October 2026 the OKX API docs weight the listed BTC and ETH instruments at 1 for perpetuals, 0.3 for expiry futures and 0.5 for spot, leave every other symbol on a default multiplier of 0.2 (perpetuals) or 0.1, keep block trading, spread trading, MMP and fiat orders out of the order count, and set the limit at 08:00 UTC from whichever is higher in the 00:00 UTC snapshot: the sub-account's fill ratio or the master account's aggregated one.

At 08:00 UTC each day, the system takes the 00:00 UTC snapshot, uses the larger of the sub-account fill ratio and the master account aggregated fill ratio, and sets the sub-account's rate limit from this table:

TierFill ratio [x ≤ ratio < y)Sub-account rate limit per 2 seconds (new and amendment)
Tier 1[0, 1)1,000
Tier 2[1, 2)1,250
Tier 3[2, 3)1,500
Tier 4[3, 5)1,750
Tier 5[5, 10)2,000
Tier 6[10, 20)2,500
Tier 7[20, 50)3,000
Tier 8≥ 5010,000

How a tier moves:

  • When the fill ratio improves and the rate limit is to be raised, the uplift takes effect immediately at 08:00 UTC.
  • When the fill ratio falls and the rate limit has to be lowered, there is a one-day grace period, and the lowered limit is only applied on T+1 at 08:00 UTC. If the ratio has improved by T+1, the higher limit is applied instead.
  • A client demoted to VIP4 has the rate limit downgraded to Tier 1, also with a one-day grace period.
  • A sub-account whose 7-day trading volume is below 1,000,000 USDT is given the fill ratio of the master account.
  • A newly created sub-account starts on the Tier 1 limit, and the normal rules apply from T+1 at 08:00 UTC.

The worked example in the docs has three accounts, with a symbol multiplier of 1 for BTC-USDT-SWAP and 0.1 for XRP-USDT. Running its numbers through the two formulas:

AccountTrade volume (USDT) and order countRatioAfter taking the larger value
A (master account)BTC-USDT-SWAP 100 / 10 orders; XRP-USDT 20 / 15 orders120 ÷ (10 × 1 + 15 × 0.1) = 120 ÷ 11.5 ≈ 10.43 (the docs show 10.4)10.43 → Tier 6, 2,500 per 2s
B (sub-account)BTC-USDT-SWAP 200 / 100 orders; XRP-USDT 20 / 30 orders220 ÷ (100 × 1 + 30 × 0.1) = 220 ÷ 103 ≈ 2.14 (the docs show 2.13)3.01 → Tier 4, 1,750 per 2s
C (sub-account)BTC-USDT-SWAP 300 / 100 orders; XRP-USDT 20 / 45 orders320 ÷ (100 × 1 + 45 × 0.1) = 320 ÷ 104.5 ≈ 3.063.06 → Tier 4, 1,750 per 2s
Master account aggregatedVolume 660; denominator 10 + 1.5 + 100 + 3 + 100 + 4.5660 ÷ 219 ≈ 3.01—

In that example, Account C's BTC-USDT-SWAP order count is listed as 1000, while the formulas for Account C and for the master account aggregate both use 100; the table here follows the formulas. The volumes in the example are small demonstration numbers. On a real account, a sub-account with less than 1,000,000 USDT of 7-day trading volume has the master account's fill ratio applied to it.

Checking your current OKX rate limit, and retrying after a rejection

The current allowance comes from GET /api/v5/trade/account-rate-limit, the account rate limit endpoint, which is itself limited to 1 request per second per User ID. It returns the sub-account fill ratio, the master account aggregated fill ratio, the current sub-account rate limit and the sub-account rate limit on T+1 (the field to read when the limit is about to be lowered). The data is updated daily at 08:00 UTC, so a script can read it once after that hour and store the result for the day, with no need to query before every order.

Count locally on three levels. Each instrument gets one counter each for placing, cancelling and amending, over 2 seconds. New orders plus amendments across every instrument in the sub-account go into one total, compared against the sub-account limit you read. For WebSocket, track connections opened per second and the subscribe and login requests on each connection. On a reconnect, don't let several connections rebuild in the same second, and don't unsubscribe and resubscribe over and over on one connection.

For many orders concentrated on one instrument, the two placement endpoints carry different allowances: 60 requests per 2 seconds on the single-order endpoint, 300 orders per 2 seconds on the multiple-order endpoint. Going through the multiple-order endpoint does not widen the sub-account cap, since each order still counts individually toward the 1,000. With amendments, wait for earlier results to come back before sending more: an order can have 3 amend requests in progress at once, and a further one submitted while those 3 are still pending is rejected with 51513.

Error codeWhich limit was hitWhat the script does
50011An endpoint's own rate limit (by IP, User ID or instrument ID)Slow this endpoint down, back off, then retry
50061The sub-account's total of new orders plus amendments per 2 secondsSlow new orders and amendments across the whole sub-account; cancel as usual
515133 amendments already in progress on the same orderWait for the earlier amendments to return before submitting another

A retry loop needs a wait that lengthens from one attempt to the next and a point at which it gives up; the OKX API errors checklist has that back-off code. If you don't have an API key yet or haven't placed a demo order, start with getting a demo key and placing and cancelling a first order. For grid bots run over the API, see the parameters for creating one and the calls for querying its state.

Risk note: When a script that places orders automatically goes wrong, the loss grows with its order rate. The figures for accounts A, B and C come from the worked example in the OKX docs, and the three perpetual swaps trading at full allowance are a hypothetical that doesn't represent any account. The sources are OKX's English API v5 docs, checked October 2026: the Rate Limits and WebSocket sections, and the rate limit fields in the endpoint descriptions for placing, amending and cancelling single and multiple orders and for the account rate limit. This article is not investment advice. Only use money you can afford to lose entirely, and take responsibility for your own trading decisions.

OKX API rate limits: questions and answers

How many orders per second can the OKX API place?

OKX counts over 2 seconds. On one instrument, the single-order endpoint allows 60 requests per 2 seconds and the multiple-order endpoint 300 orders per 2 seconds; the two allowances are independent, and options are counted by Instrument Family. At sub-account level, new orders plus amendments are capped at 1,000 per 2 seconds, and from VIP5 up the cap is tiered by fill ratio, reaching 10,000 at the top. REST and WebSocket order placement share these allowances.

How do I fix OKX API error 50061?

OKX returns 50061 with the message: You've reached the maximum order rate limit for this account. It means this sub-account's new order and amendment requests in 2 seconds went over its rate limit, 1,000 by default, with each order in a batch request counted individually. Slowing only the pair that returned the error may not be enough: slow order placement and amendments on every instrument in the sub-account. Cancellations do not count toward this limit. The docs state that spot and margin orders are exempted from the sub-account rate limit, so orders from a spot-only script do not count toward the 1,000; if a 50061 does arrive, slow down the same way.

Does placing orders over WebSocket give me an extra rate limit allowance?

No. Rate limits for placing, cancelling and amending orders are shared across REST and WebSocket, so switching channel adds nothing, and WebSocket order management is counted by User ID as well. WebSocket has connection limits of its own: 3 connection requests per second per IP, and 480 subscribe, unsubscribe and login requests per hour on each connection.