OKX API error 50011 "Rate limit reached": what is being counted
Figures on this page are as of 2026-09. Fees, limits and margin tiers change — check the venue's own docs.
OKX error 50011 means you exceeded a rate limit. OKX’s error table lists
the code twice: once with HTTP 200 and the message “Rate limit reached. Please
refer to API documentation and throttle requests accordingly.”, and once with
HTTP 429 and “Too Many Requests”.
Slowing down is the obvious fix. Slowing down the right thing is the useful one, because OKX counts requests on several different bases — per IP, per user ID, per instrument, per connection — and the counter you tripped may not be the one you were watching. This page covers the counting model, how to find which limit you hit, and what to change. It deliberately does not quote quotas: they are per endpoint, they change, and OKX publishes each one next to the endpoint it governs.
What this error actually means
One code, two HTTP statuses
The two rows in OKX’s
error-code table share
the code 50011 but not the status. The docs do not say which conditions
produce which row, so handle them identically.
The practical consequence: do not detect rate limiting by HTTP status. A
handler that only treats 429 as “slow down” will miss the HTTP 200 variant —
and HTTP 200 carrying an error is normal on OKX, where many trade-class errors
arrive with a success status and the failure in the code field. For
order endpoints the docs add that when a response includes sCode, “It is sCode
and sMsg that represent the request result or error reason”. Read code, and
sCode where present, on every response.
Limits are per endpoint, counted on different bases
There is no single account-wide request budget. OKX’s rate-limit overview says each endpoint states its own limit and its own rule, and the rule decides what is being counted:
| Request kind | Counted per |
|---|---|
| Public, unauthenticated REST | IP address |
| Private REST | User ID — each sub-account has its own |
| WebSocket login and subscription | Connection |
| WebSocket order management | User ID |
| Place, amend, cancel (REST or WebSocket) | Instrument ID (options: instrument family) |
Two details in that last row matter more than they look. The trading limits are shared across REST and WebSocket, and place, amend and cancel each have their own limit, independent of the others. Batch and single-order endpoints also have independent limits, and a batch containing one order counts as a single-order request.
The usual cause: several consumers on one user ID
Private REST is counted per user ID, not per API key. Every key on the same account draws from the same budget. A trading process, a dashboard, a reconciliation job and an MCP server all pointed at one account are one consumer as far as the limiter is concerned — even if each has its own key and each, on its own, stays comfortably under the limit.
The typical shape: everything works in development, where one process runs,
and 50011 starts appearing once the second or third consumer is added. Issuing
another key does not help. Separating the consumers onto different sub-accounts
does, because each sub-account has its own user ID — which is also the route
OKX itself suggests when you need more throughput. The broader case for doing
this is in
using sub-accounts for automation.
Polling makes it worse. A loop that asks for positions or open orders every second, in each of several processes, spends the shared budget on questions a WebSocket subscription would answer without touching it.
Other causes, in order of likelihood
1. One instrument, too many order actions
A strategy that cancels and replaces quotes on a single instrument, or amends
the same order repeatedly, runs into the per-instrument trading limit while every
other instrument is fine. The symptom is 50011 concentrated on one instId.
Moving that traffic from REST to WebSocket does not buy headroom. The trading limits are shared across the two channels, so a strategy split between them is counted against one total per instrument.
2. Retries without backoff
A handler that retries immediately on any error turns one rate-limit response into a burst of them. This is how a brief spike becomes a sustained outage of your own making.
3. Startup bursts
Fetching history, positions and instrument details for many instruments at once on boot can exceed limits that steady-state traffic never approaches. Spread the start-up reads out.
4. Many processes behind one IP
Public market-data endpoints are counted per IP. Several services on one host, or many hosts behind one NAT gateway, share that budget without knowing it.
5. WebSocket churn
Login and subscription limits are counted per connection. A reconnect handler that re-logs-in and resubscribes to everything in a tight loop can hit them — see WebSocket reconnection patterns.
A different code: 50061
OKX also runs a sub-account-level order limit in parallel with the
per-instrument ones. Exceeding it returns 50061, not 50011, and the docs
describe a fill-ratio-based uplift to it for higher VIP tiers. If you see
50061, the constraint is the account’s overall order rate, not any one
instrument.
How to confirm which limit you hit
- Record the endpoint and
instIdof every request that returned50011. Rate limits are per endpoint, so the endpoint is the first thing you need. - Look up that endpoint’s “Rate Limit” line in the V5 docs. It gives the limit and the rule — per IP, per user ID, or per instrument.
- Count your own traffic on the same basis, across every process that shares it: all consumers on the user ID, all services behind the IP, or all order actions on the instrument over REST and WebSocket.
- Check the pattern. Failures on one instrument point to the trading limit; failures across private endpoints point to the user-ID budget; failures on public data point to the IP.
If the count you make is well under the published limit, you are almost certainly missing a consumer. Look for the one you forgot.
What to change
- Throttle client-side, keyed the way OKX keys it. A limiter per endpoint, per user ID and — for order actions — per instrument, shared by every process on that account. A limiter per process cannot see the others.
- Replace polling with subscriptions for positions, orders and market data.
- Back off with jitter on
50011, and let the backoff grow on repeats. - Use batch endpoints where you genuinely send several orders together; they have their own limit, separate from single-order requests.
- Split consumers across sub-accounts when one account is doing too many jobs.
For order placement, backoff is not the whole answer. A rate-limit response to
an order is, in principle, a refusal — but “in principle” is not what you want
deciding whether a retry doubles a position, and on a batch request each order
carries its own sCode. Reconcile before re-sending an order: check open
orders and positions, then decide. The reasoning is in
error handling patterns for trading APIs,
and the model-driven version of the problem — a language model calling tools in
a loop — is covered in
rate limits in an MCP trading setup.
FAQ
Why does OKX return error 50011 with HTTP 200?
OKX’s error table lists 50011 twice: once with HTTP 200 (“Rate limit
reached…”) and once with HTTP 429 (“Too Many Requests”). Many OKX errors arrive
with HTTP 200 and the failure in the response’s code or sCode field, so a
client must read those fields rather than relying on the HTTP status.
Does moving order placement to WebSocket avoid OKX rate limits?
No. OKX’s limits for placing, amending and cancelling orders are shared across REST and WebSocket and counted per instrument ID. Splitting order traffic between the two channels counts against the same total for that instrument.
Do separate OKX API keys have separate rate limits?
Not for private endpoints. Private REST limits are counted per user ID, so every key on the same account shares one budget. Sub-accounts have their own user IDs, which is why OKX suggests multiple sub-accounts when you need more throughput.
Where do I find the exact OKX rate limit for an endpoint?
On the endpoint’s own section of the V5 API docs, which states its limit and whether it is counted per IP, user ID or instrument. The quotas change, so read them there rather than from an article, and re-check when you add a new endpoint to your integration.