Skip to content

FAQ

What is the maximum allowed drift between timestamp / X-CH-TS and server time?

The server rejects requests whose timestamp is older than 5000 ms. You can widen this window with optional recvWindow.

X-CH-TS header cannot be empty — how to fix?

Log X-CH-TS on failure and confirm it is non-empty before each request.

Why does signature auth always return invalid signature?

Walk this checklist in order — items 1 and 2 cause >90% of cases:

  1. requestPath includes the gateway prefix by mistake. The full URL is https://openapi.bitbaby.com/futures/open/fapi/v1/openOrders, but the signature must use only /fapi/v1/openOrders — do not put /futures/open (or /spot/open) into PreHash. Same rule for /sapi/... on spot.
  2. The POST body is being serialized twice. A common mistake: you call json.dumps(obj) to compute the signature, then call requests.post(json=obj, ...) which serializes again, changing field order or whitespace and breaking the signature. Serialize once → sign that string → send that exact string as the HTTP body.
  3. GET and POST PreHash differ:
    • GET: timestamp + GET + requestPath + (?queryString)?no body.
    • POST: timestamp + POST + requestPath + (?queryString)? + bodybody is the raw request body.
    • The ? separator is added by the formula; queryString itself must not start with ?.
  4. X-CH-TS and the timestamp inside PreHash must be byte-for-byte identical (both 13-digit millisecond strings).
  5. API key and secret are case-sensitive; trim whitespace before use.
  6. Content-Type must be application/json, otherwise you'll see -1017 ILLEGAL_CONTENT_TYPE.
  7. Clock skew above ±5s is rejected. Call /sapi/v1/time or /fapi/v1/time to read serverTime, then fix the local clock or pass recvWindow (in the body for POST, in the query for GET).

When debugging, print the following three values on the client and diff them against your packet capture:

  • The HTTP method, URL, headers, and body you actually send
  • The exact PreHash string you used to compute the signature
  • The resulting X-CH-SIGN

PreHash examples (identical to General information):

text
GET example:   1588591856950GET/sapi/v1/openOrders?symbol=BTCUSDT&limit=10
POST example:  1588591856950POST/sapi/v1/order/test{"symbol":"BTCUSDT","price":"9300","volume":"1","side":"BUY","type":"LIMIT"}

Headers example:

bash
Content-Type: application/json
X-CH-APIKEY:  44c541a1-****-****-****-10fe390df2
X-CH-TS:      1574327555669
X-CH-SIGN:    c50d0a74bb9427a9a03933d0eded03af9bf50115dc5b706882a4fcf07a26b761

ILLEGAL_CONTENT_TYPE (-1017) — why?

Send header Content-Type: application/json on requests.

Are there per-second API rate limits?

Yes—see each endpoint’s documented rate limits.

How are API rate limits applied?

Private data is limited per API key. Public data is limited per IP. If you call public endpoints with a valid user context, limits may follow the API key instead.

What causes HTTP 429?

Too many requests; slow down.

Will I get IP-banned for exceeding rate limits? For how long?

Usually not—reducing frequency is enough.

Why does WebSocket disconnect?

  • Missing heartbeat—keep ping/pong to stabilize the connection.
  • Network loss so the server never sees pong, or other network issues.
  • Implement reconnect logic with heartbeat so the client recovers after drops.

Requests time out

Check network connectivity to the server.

How do I list all trading pairs?

Use spot GET /sapi/v1/symbols.

Are there limits for batch place/cancel?

Yes—batch endpoints allow at most 10 orders per call.

What is newClientOrderId for?

  • A custom id you assign to an order; after placement you can query by newClientOrderId.
  • You must keep ids unique—we do not dedupe; duplicates may cause cancel/query to affect only the latest matching row.

How do I get the latest trade price?

Use the ticker endpoint; last is the latest price.

Can 24h volume on the ticker decrease?

Yes. Rolling 24h stats can move with the window, so volume/amount in a later window may be lower than in the previous one.