General information
API basics
- REST base URLs:
- Spot / margin:
https://openapi.bitbaby.com/spot/open - Futures:
https://openapi.bitbaby.com/futures/open
- Spot / margin:
- WebSocket base URLs:
- Spot market data:
wss://openapi.bitbaby.com/spot/ws - Futures market data:
wss://openapi.bitbaby.com/futures/ws
- Spot market data:
- All endpoints return a JSON object or array.
- When the response contains arrays, elements are ordered by time descending (older data appears first).
- All times and timestamps are UNIX time in milliseconds.
HTTP status codes
- HTTP
4XXindicates invalid request content, behavior, or format. - HTTP
429warns that rate limits were exceeded and the IP may soon be blocked. - HTTP
418means access continued after429, so the IP was blocked. - HTTP
5XXindicates an internal server error; do not treat this alone as a failed operation—execution state is unknown and may have succeeded or failed. - HTTP
504means the API layer submitted the request to the core but did not get a response.504does not mean failure—outcome is unknown; the request may have executed or not and must be verified. - Any endpoint may return an ERROR payload like:
{
"code": -1121,
"msg": "Invalid symbol."
}Common request rules
- All requests use HTTPS. Set header
Content-Typetoapplication/json. - For
GET, send parameters in the query string. - For
POST, send parameters in the request body. - Parameter order does not matter.
Rate limits
- Each endpoint documents its own rate limits.
- Violating limits yields HTTP 429 as a warning.
- When you receive 429, reduce request frequency or pause calls.
Authentication types
- Each endpoint declares an auth type that determines how you authenticate.
- When an API key is required, pass it in header
X-CH-APIKEY. - API key and secret are case-sensitive.
- You can change API key permissions in the web user center (e.g. read account, trade, withdraw).
| Auth type | Description |
|---|---|
| NONE | No authentication |
| TRADE | Valid API key + signature |
| USER_DATA | Valid API key + signature |
| MARKET_DATA | Valid API key |
Signed endpoints (TRADE and USER_DATA)
For TRADE or USER_DATA endpoints you must send these three headers:
| Header | Description |
|---|---|
X-CH-APIKEY | Your API key |
X-CH-TS | Client timestamp in milliseconds, e.g. 1767867649647 |
X-CH-SIGN | HMAC-SHA256 of the PreHash string using the API secret, lowercase hex encoded |
PreHash formula
PreHash = timestamp + method + requestPath
+ ("?" + queryString)? // only when queryString is non-empty
+ body? // only when body is non-empty (POST yes, GET no)timestamp— exactly the same string sent inX-CH-TS.method— HTTP method uppercased:GET/POST.requestPath— the API path, e.g./sapi/v1/order,/fapi/v1/openOrders.queryString— the part after?in the URL, e.g.symbol=BTCUSDT&limit=10. The?separator is added by the formula; do not include?inqueryStringitself.body— the raw POST body string (the exact bytes that go on the wire). OmitbodyforGET; do not substitute{}or any placeholder.
Most common pitfall
requestPath does NOT include the gateway prefix /spot/open or /futures/open. The gateway strips the prefix before forwarding to the backend, so signature checks always use /sapi/v1/... or /fapi/v1/....
Example: for the URL https://openapi.bitbaby.com/futures/open/fapi/v1/openOrders?contractName=E-ETH-USDT, the signed requestPath is /fapi/v1/openOrders — not /futures/open/fapi/v1/openOrders.
About POST body
The body you sign must be byte-for-byte identical to the body you transmit. In practice:
- Don't let your HTTP client re-serialize JSON after you compute the signature (field order, whitespace, and number formatting all change the body).
- Recommended pattern: serialize once → use that string for HMAC → send the same string as the HTTP body.
- If a POST has no body, sign with the empty string
"". Do not sign{}.
Timestamp security
- Signed requests must send
X-CH-TSin milliseconds. - The server rejects requests whose timestamp is older than 5000 ms (configurable via the optional
recvWindow: in the body for POST, in the query for GET). - Requests whose timestamp is more than one second in the future vs server time are also rejected.
- Pseudologic:
if (timestamp < (serverTime + 1000) && (serverTime - timestamp) <= recvWindow) {
// process request
} else {
// reject request
}Trading timeliness: Network latency is not perfectly stable, so client-to-exchange clock skew varies. Tune recvWindow as needed; values above 5 seconds are not recommended.
Worked signing examples
The keys below are samples only.
| Key | Value |
|---|---|
| apiKey | vmPUZE6mv9SD5V5e14y7Ju91duEh8A |
| secretKey | 902ae3cb34ecee2779aa4d3e1d226686 |
Example 1: GET /sapi/v1/openOrders?symbol=BTCUSDT&limit=10
- PreHash:
1588591856950GET/sapi/v1/openOrders?symbol=BTCUSDT&limit=10- HMAC-SHA256 (bash + openssl):
echo -n "1588591856950GET/sapi/v1/openOrders?symbol=BTCUSDT&limit=10" \
| openssl dgst -sha256 -hmac "902ae3cb34ecee2779aa4d3e1d226686"- Full curl:
curl -X GET 'https://openapi.bitbaby.com/spot/open/sapi/v1/openOrders?symbol=BTCUSDT&limit=10' \
-H 'X-CH-APIKEY: vmPUZE6mv9SD5V5e14y7Ju91duEh8A' \
-H 'X-CH-TS: 1588591856950' \
-H 'X-CH-SIGN: <hex from previous step>' \
-H 'Content-Type: application/json'Example 2: POST /sapi/v1/order/test
| Param | Value |
|---|---|
| symbol | BTCUSDT |
| side | BUY |
| type | LIMIT |
| volume | 1 |
| price | 9300 |
- body (the same string is signed and transmitted):
{"symbol":"BTCUSDT","price":"9300","volume":"1","side":"BUY","type":"LIMIT"}- PreHash:
1588591856950POST/sapi/v1/order/test{"symbol":"BTCUSDT","price":"9300","volume":"1","side":"BUY","type":"LIMIT"}- HMAC-SHA256 (bash + openssl):
echo -n '1588591856950POST/sapi/v1/order/test{"symbol":"BTCUSDT","price":"9300","volume":"1","side":"BUY","type":"LIMIT"}' \
| openssl dgst -sha256 -hmac "902ae3cb34ecee2779aa4d3e1d226686"
# (stdin)= c50d0a74bb9427a9a03933d0eded03af9bf50115dc5b706882a4fcf07a26b761- Full curl:
curl -X POST 'https://openapi.bitbaby.com/spot/open/sapi/v1/order/test' \
-H 'X-CH-APIKEY: vmPUZE6mv9SD5V5e14y7Ju91duEh8A' \
-H 'X-CH-TS: 1588591856950' \
-H 'X-CH-SIGN: c50d0a74bb9427a9a03933d0eded03af9bf50115dc5b706882a4fcf07a26b761' \
-H 'Content-Type: application/json' \
-d '{"symbol":"BTCUSDT","price":"9300","volume":"1","side":"BUY","type":"LIMIT"}'