Bybit API errors 10006 vs 10018: account vs IP rate limits
Figures on this page are as of 2026-09. Fees, limits and margin tiers change — check the venue's own docs.
Bybit’s 10006 — “Too many visits. Exceeded the API Rate Limit.” — means
one account (UID) sent too many requests to one endpoint within Bybit’s rolling
per-second window. 10018 — “Exceeded the IP Rate Limit.” — means the traffic
leaving one IP address was too much. The fixes differ: pace the specific
endpoint for 10006, using the X-Bapi-Limit* headers; reduce total traffic
from the address for 10018.
This page is for anyone running more than one bot, polling several endpoints, or seeing rate-limit errors that do not match their own request counts. It explains Bybit’s two layers, what each code implies about your architecture, and how to handle both in code. It deliberately contains no quota numbers — those change, and they live on Bybit’s rate-limit page.
What these errors actually mean
Bybit documents two independent layers.
The API limit — per UID, per endpoint. Bybit describes it as “based on the
rolling time window per second and UID”. Each endpoint has its own budget for
your account. Breach it and the response is retCode: 10006. Every response
carries three headers that describe this layer:
| Header | Content |
|---|---|
X-Bapi-Limit-Status | Requests remaining for this endpoint |
X-Bapi-Limit | Current limit for this endpoint |
X-Bapi-Limit-Reset-Timestamp | Reset time if exceeded; otherwise the current timestamp |
The IP limit — per address. A per-IP request budget over a short fixed
window, applied across api.bybit.com and the regional hosts. The rate-limit
page says a breach returns HTTP 403 “access too frequent”, that you should
stop all HTTP sessions and wait, and that “the ban will be lifted
automatically”. Bybit’s error table also lists retCode 10018, “Exceeded the
IP Rate Limit.”
We did not find official text explaining when 10018 is returned versus the
HTTP 403. Handle both as the IP layer and do not build logic that depends on
getting one rather than the other.
The distinction, side by side
10006 | 10018 / HTTP 403 | |
|---|---|---|
| Counted per | Account (UID) and endpoint | IP address |
| Window | Rolling, per second | Short fixed window |
| Visible in advance | Yes — X-Bapi-Limit-Status | No per-response header documented |
| What it says about you | One endpoint is called too often | The machine, as a whole, sends too much |
| Fix | Pace that endpoint; wait for the reset timestamp | Stop HTTP sessions from that IP, wait, then reduce total traffic |
| Raised by VIP / Pro tiers | On endpoints the table marks “upgradable” | We did not find anything saying so |
The practical reading: 10006 is local to one endpoint; the others still
work. A strategy that hammers the order-status endpoint can hit 10006 there
while its order placement is fine. The IP layer is global to the address, so
everything on that machine is affected at once.
The usual cause of each
10006: polling. A loop that checks order status, positions or balances
far more often than anything changes. The per-endpoint budget is spent on
questions whose answer has not moved. Our suggestion is to move repeated reads
of changing state to a WebSocket subscription, which has its own, separate
connection limits — see
WebSocket vs REST for trading.
10018: several consumers behind one address. This is our reading, not
Bybit’s wording, but the arithmetic makes it the usual way in: each account on
a machine has its own per-UID budgets, while all of them share one per-IP
budget. Three bots on three sub-accounts, each well within its own limits, can
together exceed what the address is allowed. Sharing an IP across accounts is
the pattern to look for.
Other causes, in order of likelihood
1. A retry storm. An error handler that retries immediately turns a single
10006 into a burst, and a burst across many endpoints into an IP-layer
problem.
2. Batch endpoints sized wrong. Batch create, amend and cancel have their
own limit, not shared with the single-order endpoint, and consume one unit
per order in the batch. If a batch is larger than the remaining budget, the
overflow orders fail and the rest succeed. That is a partial success, and code
that checks only the top-level retCode will miss it: inspect the result for
every order in the batch.
3. Startup bursts. Every process fetching instruments, positions, balances and open orders at once on boot — worse when a crash loop restarts it repeatedly.
4. Not a quota at all. Two codes read like rate limits and are not yours to pace:
| Code | Meaning | Implication |
|---|---|---|
HTTP 429 | “System level frequency protection. Please retry when encounter this” | Platform-side; back off and retry |
429 (UTA retCode) | “The trading service is experiencing a high server load…” | Server load, not your quota |
10429 (WebSocket order entry) | “System level frequency protection” | WebSocket channel |
20003 (WebSocket order entry) | “Too frequent requests under the same session” | Per-session message rate |
10003 (WebSocket order entry) | “Too many sessions under the same UID” | Session count, not request rate — see Bybit API error 10003 |
How to confirm which one you have
- Read the code, then the headers. On
10006, log the endpoint and all threeX-Bapi-Limit*headers. AX-Bapi-Limit-Statusthat fell steadily to zero points at polling; one that jumped from high to zero points at a burst. - Count per IP, not per process. For
10018or403, sum the request rate of every process on that address. The single process that got the error is rarely the whole story. - Check the timing. Errors clustered after restarts are startup bursts; errors after other errors are retry storms.
Handling both in code
remaining = int(resp.headers.get("X-Bapi-Limit-Status", "1"))
body = resp.json()
if body["retCode"] == 10006:
reset_ms = int(resp.headers["X-Bapi-Limit-Reset-Timestamp"])
pause_endpoint(path, until_ms=reset_ms) # this endpoint only
elif body["retCode"] == 10018 or resp.status_code == 403:
pause_all_http(backoff_with_jitter()) # whole IP; also check the other 403 causes
elif remaining <= LOW_WATERMARK:
slow_endpoint(path) # pace before you hit zero
A 403 also covers GET requests sent with an empty JSON body and requests from
restricted regions, so log the body before assuming it is the IP layer.
For orders, a 10006 is a refusal: Bybit answered and did not accept the order.
That is different from a timeout, where you do not know what happened and must
reconcile before resending — see
error handling patterns for trading APIs.
FAQ
What is the difference between Bybit error 10006 and 10018?
10006 means your account exceeded the limit for one specific endpoint, in
Bybit’s rolling per-second window per UID. 10018 means the IP address as a
whole exceeded its limit. The first is fixed by pacing that endpoint, guided by
the X-Bapi-Limit* headers; the second by reducing total traffic from the
address.
How do I know how close I am to Bybit’s rate limit?
Every Bybit V5 response carries X-Bapi-Limit-Status (requests remaining for
that endpoint), X-Bapi-Limit (the endpoint’s current limit) and
X-Bapi-Limit-Reset-Timestamp. These describe the per-UID, per-endpoint layer.
We did not find equivalent per-response headers documented for the IP layer.
Why do I get 10018 when each bot is within its limits?
Because the IP layer counts every request from the address, regardless of account. Several bots on different accounts can each stay within their own per-UID budgets and still exceed the shared per-IP budget together. Give heavy consumers their own egress address, or reduce polling across all of them.
Do Bybit batch orders count as one request?
No. Bybit’s batch create, amend and cancel endpoints have their own limit and consume one unit per order in the batch. If the batch is larger than the remaining budget, the overflow orders fail while the rest succeed, so check the result of each order rather than only the top-level response.