Learn / Exchange APIs

Bybit API key setup and request signing

Figures on this page are as of 2026-09. Fees, limits and margin tiers change — check the venue's own docs before acting on a number.

Bybit’s V5 API is straightforward once the signature is right, and the signature is where almost everyone loses an hour. The reason is specific: Bybit’s pre-hash string is a different shape from Binance’s and OKX’s, so code adapted from another exchange produces a signature that is confidently wrong.

The headers

Four, on every private request:

HeaderContent
X-BAPI-API-KEYThe API key
X-BAPI-TIMESTAMPUTC timestamp in milliseconds
X-BAPI-SIGNThe derived signature
X-BAPI-RECV-WINDOWOptional; default 5000 ms

Broker users additionally send X-Referer or Referer.

The signature

Algorithm: HMAC_SHA256 or RSA_SHA256.

The pre-hash string:

  • GETtimestamp + api_key + recv_window + queryString
  • POSTtimestamp + api_key + recv_window + jsonBodyString

Bybit’s own worked example:

1658384314791XXXXXXXXXX5000category=option&symbol=BTC-29JUL22-25000-C

which produces

410e0f387bafb7afd0f1722c068515e09945610124fa11774da1da857b72f30b

Note what is concatenated and what is not. There are no separators, the method is not included, and the request path is not included.

Why code from another exchange fails here

The three major venues each do this differently, and none of the differences are cosmetic:

VenuePre-hash string
Bybittimestamp + api_key + recv_window + queryString | body
BinanceQuery string concatenated with the HTTP body
OKXtimestamp + method + requestPath + body

So a signer ported from OKX will include the HTTP method and the path — both absent from Bybit’s construction. A signer ported from Binance will omit the timestamp, key and recv window from the signed material. Both produce a well-formed signature that Bybit will reject.

If you are adapting working code, rewrite the pre-hash construction from Bybit’s documentation rather than adjusting the one you have. It is faster and you will not be left wondering which of three differences you missed.

Getting the environment right

Testnet is a separate hostname:

PurposeURL
Mainnethttps://api.bybit.com (alternate https://api.bytick.com)
Testnethttps://api-testnet.bybit.com

There are also regional mainnet domains — .nl, .tr, .kz, .ge, .ae, .eu, .id, plus manepa.jp for Japan and spark-fintech.com for Hong Kong.

A separate testnet host is the safe arrangement: testnet credentials do not exist on mainnet, so pointing at the wrong host produces an authentication error rather than a live trade. Compare OKX, where demo and production share a hostname and the environment is carried by a header.

Telling failures apart

The useful skill is distinguishing signing problems from key problems from account-type problems, because they look similar and have nothing to do with each other.

Signing or transport

SymptomLikely cause
HTTP 401Wrong key, or auth params not placed in the request header
Auth failure with correct-looking keyPre-hash construction — see above
Intermittent failure, some endpoints onlyQuery-string ordering or encoding differing between signed and sent

Key state

CodeMeaning
10010“Unmatched IP, please check your API key’s bound IP addresses.”
10005“Permission denied, please check your API key permissions.”
10003Classic: too many sessions under the same UID. UTA spot: your key has expired
33004UTA derivatives: your key has expired

Account type — these two are near-mirror images and genuinely confusing:

CodeMeaning
110028“The API can only be accessed by unified account users.”
100028“The API cannot be accessed by unified account users.”

If you are hitting either, the endpoint and your account type disagree. Check which you have before changing any code.

Region — HTTP 403 is documented for IP rate limit breaches, for GET requests sent with an empty JSON body, and for requests from US IPs. Three unrelated causes, one status code.

Practical setup notes

  • Sync your clock. The timestamp is in the signature and recvWindow defaults to 5000 ms. Drift produces authentication failures that look like signing bugs.
  • Log the pre-hash string during development. Not the secret — the string being signed. Comparing it against the documented example is the fastest way to find a construction error.
  • Start read-only. Permission failures then surface as 10005 immediately, rather than as a surprise when you first place an order.
  • Bind an IP if you can. 10010 exists because IP binding is enforced; it is the cheapest reduction in what a leaked key is worth.

FAQ

Why is my Bybit signature rejected when the same code works on another exchange?

Because the pre-hash string is different. Bybit signs timestamp + api_key + recv_window + queryString (or the JSON body for POST), with no separators, no HTTP method and no request path. OKX includes the method and path; Binance signs the query string concatenated with the body. Rewrite the construction from Bybit’s documentation rather than adapting.

What does Bybit error 10003 mean?

It depends on your account type, which is why it is confusing. On classic accounts it means too many sessions under the same UID. Under a Unified Trading Account on spot, it means your API key has expired — and the derivatives equivalent is 33004. Check which account type you have before debugging.

What is X-BAPI-RECV-WINDOW for?

It is how long Bybit will accept the request after the signed timestamp, defaulting to 5000 ms. It exists to bound replay. If you see intermittent authentication failures on an otherwise correct setup, clock drift against this window is a strong suspect.

Is Bybit testnet a separate account?

Yes — separate hostname at https://api-testnet.bybit.com and separate credentials. Testnet keys do not work against mainnet, which means an environment mix-up fails with an auth error rather than placing a real order.