Skip to Content
🚀 Spot APICode Examples

Code Examples

📋 Table of Contents


💻 Code Examples

JavaScript Examples
const https = require('https'); const crypto = require('crypto'); const { URL } = require('url'); function generateNonce(length = 16) { const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'; return Array.from({ length }, () => chars.charAt(Math.floor(Math.random() * chars.length))).join(''); } function sortObject(obj) { if (Array.isArray(obj)) { return obj.map(sortObject); } else if (typeof obj === 'object' && obj !== null) { return Object.keys(obj) .sort() .reduce((acc, key) => { acc[key] = sortObject(obj[key]); return acc; }, {}); } return obj; } function flattenObject(obj, parentKey = '', result = {}) { if (typeof obj !== 'object' || obj === null) return result; for (const [key, value] of Object.entries(obj)) { if (value == null) continue; const newKey = parentKey ? `${parentKey}.${key}` : key; if (Array.isArray(value)) { value.forEach((v, i) => flattenObject(v, `${newKey}[${i}]`, result)); } else if (typeof value === 'object') { flattenObject(value, newKey, result); } else { if (String(value).trim() !== '') result[newKey] = String(value); } } return result; } function sortQueryParams(query) { if (!query) return ''; const pairs = query.split('&').filter(Boolean); const params = pairs.map(p => p.split('=')).filter(p => p.length === 2); params.sort((a, b) => a[0].localeCompare(b[0])); return params.map(([k, v]) => `${k}=${v}`).join('&'); } function generateSignature(method, url, body, secret, timestamp, nonce) { const urlObj = new URL(url); let query = sortQueryParams(urlObj.search.slice(1)); let bodyData = ''; if (['POST', 'PUT'].includes(method.toUpperCase()) && body) { const sortedBody = sortObject(body); const flatBody = flattenObject(sortedBody); bodyData = Object.entries(flatBody) .map(([k, v]) => `${k}=${v}`) .join('&'); } // POST: (bodyData.isEmpty() ? "" : bodyData + "&") + "timestamp=xxx&nonce=xxx" // GET: (query.isEmpty() ? "&" : query + "&") + "timestamp=xxx&nonce=xxx" let signData = ''; if (method.toUpperCase() === 'GET') { signData = (query ? `${query}&` : '&') + `timestamp=${timestamp}&nonce=${nonce}`; } else { signData = (bodyData ? `${bodyData}&` : '') + `timestamp=${timestamp}&nonce=${nonce}`; } const hmac = crypto.createHmac('sha256', secret); hmac.update(signData); return hmac.digest('hex'); } function sendGetRequest(url, headers) { return new Promise((resolve, reject) => { const req = https.get(url, { headers }, res => { let data = ''; res.on('data', chunk => (data += chunk)); res.on('end', () => { console.log('状态码:', res.statusCode); console.log('响应:', data); resolve(data); }); }); req.on('error', reject); }); } (async () => { const apiKey = '8aB3yCz4QpW9sT7rM0dN2uE5kH1xJ6fVtLqO8bRzP3cS9yD0mG4nF7aU'; const apiSecret = 'W7eR1tF6pA2yQ3dK5sM9xL8bG4jC0vHnUoOzTqP1rE5iN2mS7uY6aZ0l'; const url = 'https://openapi.bittap.com/stapi/v1/account'; const method = 'GET'; const timestamp = Date.now(); const nonce = generateNonce(); const sign = generateSignature(method, url, null, apiSecret, timestamp, nonce); const headers = { 'X-BT-APIKEY': apiKey, 'X-BT-SIGN': sign, 'X-BT-TS': timestamp, 'X-BT-NONCE': nonce, }; console.log('sign:', sign); await sendGetRequest(url, headers); })();

Java Examples
public class OpenApiDemo { private static final String API_KEY = ""; private static final String API_SECRET = ""; private static final String BASE_URL = "https://openapi.bittap.com"; private static final String SEPARATOR = "&"; private static final String EQUALS = "="; private static final OkHttpClient CLIENT = new OkHttpClient(); private static final ObjectMapper MAPPER = new ObjectMapper(); public static void main(String[] args) throws Exception { // Batch place orders testBatchCreate(); // Cancel order testCancelOrder(); // Batch cancel testBatchCancel(); // Query open orders testOpenOrders(); // Query historical orders testHisOrders(); // Query trade records testTrades(); // Query account balance testAccount(); } // ----------------- API Calls ------------------- // 1. Batch place orders public static void testBatchCreate() throws Exception { String url = BASE_URL + "/stapi/v1/batchOrders"; ObjectNode body = MAPPER.createObjectNode(); body.put("symbol", "BTC-USDT"); ArrayNode items = body.putArray("items"); ObjectNode order1 = MAPPER.createObjectNode(); order1.put("clientOrderId", UUID.randomUUID().toString().replace("-", "")); order1.put("type", "LIMIT"); order1.put("price", "100002"); order1.put("quantity", "0.0011"); order1.put("timeInForce", "GTC"); order1.put("selfTradePreventionMode", "EXPIRE_BOTH"); order1.put("side", "BUY"); items.add(order1); ObjectNode order2 = MAPPER.createObjectNode(); order2.put("clientOrderId", UUID.randomUUID().toString().replace("-", "")); order2.put("type", "LIMIT"); order2.put("price", "100002"); order2.put("quantity", "0.0011"); order2.put("timeInForce", "GTC"); order2.put("selfTradePreventionMode", "EXPIRE_BOTH"); order2.put("side", "BUY"); items.add(order2); sendSignedPost(url, body); } // 2. Cancel order public static void testCancelOrder() throws Exception { String url = BASE_URL + "/stapi/v1/cancelOrder"; ObjectNode body = MAPPER.createObjectNode(); body.put("clientOrderId", "00295c0dadbb47a5b5a0d3fe4ad83fc9"); sendSignedPost(url, body); } // 3. Batch cancel orders public static void testBatchCancel() throws Exception { String url = BASE_URL + "/stapi/v1/batchCancelOrders"; ObjectNode body = MAPPER.createObjectNode(); body.put("symbol", "BTC-USDT"); sendSignedPost(url, body); } // 4. Query open orders public static void testOpenOrders() throws Exception { String url = BASE_URL + "/stapi/v1/openOrders"; sendSignedGet(url); } // 5. Query historical orders public static void testHisOrders() throws Exception { String url = BASE_URL + "/stapi/v1/hisOrders?symbol=BTC-USDT"; sendSignedGet(url); } // 6. Query trade records public static void testTrades() throws Exception { String url = BASE_URL + "/stapi/v1/trades?pageNumber=1&pageSize=10"; sendSignedGet(url); } // 7. Query account balance public static void testAccount() throws Exception { String url = BASE_URL + "/stapi/v1/account"; sendSignedGet(url); } // ----------------- Utility Methods ------------------- private static void sendSignedPost(String url, ObjectNode body) throws Exception { long timestamp = System.currentTimeMillis(); String nonce = UUID.randomUUID().toString().replace("-", ""); // 1. Sort JSON JsonNode sortedNode = sortJsonNode(body); // 1. Flatten body String bodyData = convertJsonToQueryString(sortedNode); // 2. Concatenate signature string String signData = (bodyData.isEmpty() ? "" : bodyData + "&") + "timestamp=" + timestamp + "&nonce=" + nonce; String sign = hmacSha256Hex(signData, API_SECRET); String bodyJson = MAPPER.writeValueAsString(body); RequestBody requestBody = RequestBody.create( bodyJson, MediaType.parse("application/json; charset=utf-8")); Request request = new Request.Builder() .url(url) .post(requestBody) .addHeader("X-BT-APIKEY", API_KEY) .addHeader("X-BT-SIGN", sign) .addHeader("X-BT-TS", String.valueOf(timestamp)) .addHeader("X-BT-NONCE", nonce) .build(); try (Response response = CLIENT.newCall(request).execute()) { System.out.println("POST " + url); System.out.println("Response: " + response.code() + " " + (response.body() != null ? response.body().string() : "")); } } private static void sendSignedGet(String url) throws Exception { long timestamp = System.currentTimeMillis(); String nonce = UUID.randomUUID().toString().replace("-", ""); // Parse existing query from URL String query = ""; int idx = url.indexOf("?"); if (idx != -1) { query = url.substring(idx + 1); } query = sortQueryParams(query); String signData = (query.isEmpty() ? "&" : query + "&") + "timestamp=" + timestamp + "&nonce=" + nonce; String sign = hmacSha256Hex(signData, API_SECRET); String finalUrl = url; Request request = new Request.Builder() .url(finalUrl) .get() .addHeader("X-BT-APIKEY", API_KEY) .addHeader("X-BT-SIGN", sign) .addHeader("X-BT-TS", String.valueOf(timestamp)) .addHeader("X-BT-NONCE", nonce) .build(); try (Response response = CLIENT.newCall(request).execute()) { System.out.println("GET " + finalUrl); System.out.println("Response: " + response.code() + " " + (response.body() != null ? response.body().string() : "")); } } private static String convertJsonToQueryString(JsonNode jsonNode) { if (jsonNode == null || jsonNode.isNull()) { return ""; } MultiValueMap<String, String> params = new LinkedMultiValueMap<>(); flattenJson(jsonNode, "", params); StringBuilder queryString = new StringBuilder(); boolean first = true; for (Map.Entry<String, String> entry : params.toSingleValueMap().entrySet()) { if (!first) { queryString.append("&"); } else { first = false; } queryString.append(entry.getKey()).append("=").append(entry.getValue()); } return queryString.toString(); } private static void flattenJson(JsonNode node, String path, MultiValueMap<String, String> params) { if (node.isObject()) { Iterator<Map.Entry<String, JsonNode>> fields = node.fields(); while (fields.hasNext()) { Map.Entry<String, JsonNode> field = fields.next(); if (field.getValue().isNull()) { continue; } String newPath = path.isEmpty() ? field.getKey() : path + "." + field.getKey(); flattenJson(field.getValue(), newPath, params); } } else if (node.isArray()) { for (int i = 0; i < node.size(); i++) { JsonNode jsonNode = node.get(i); if (jsonNode.isNull() || jsonNode.isArray() && jsonNode.isEmpty()) { continue; } String newPath = path + "[" + i + "]"; flattenJson(node.get(i), newPath, params); } } else { // Basic type if (node.asText().isBlank()) { return; } params.add(path, node.asText()); } } private static String hmacSha256Hex(String data, String secret) throws Exception { Mac mac = Mac.getInstance("HmacSHA256"); SecretKeySpec keySpec = new SecretKeySpec(secret.getBytes(StandardCharsets.UTF_8), "HmacSHA256"); mac.init(keySpec); byte[] raw = mac.doFinal(data.getBytes(StandardCharsets.UTF_8)); StringBuilder sb = new StringBuilder(raw.length * 2); for (byte b : raw) sb.append(String.format("%02x", b)); return sb.toString(); } private static JsonNode sortJsonNode(JsonNode node) { try { if (node == null || node.isNull()) return node; if (node.isObject()) { ObjectNode out = MAPPER.createObjectNode(); TreeMap<String, JsonNode> sorted = new TreeMap<>(); Iterator<Map.Entry<String, JsonNode>> fields = node.fields(); while (fields.hasNext()) { Map.Entry<String, JsonNode> f = fields.next(); sorted.put(f.getKey(), sortJsonNode(f.getValue())); } for (Map.Entry<String, JsonNode> e : sorted.entrySet()) { out.set(e.getKey(), e.getValue()); } return out; } else if (node.isArray()) { ArrayNode arr = MAPPER.createArrayNode(); for (JsonNode el : node) arr.add(sortJsonNode(el)); return arr; } else { return node; } } catch (Exception ex) { return node; } } private static String sortQueryParams(String query) { if (StringUtils.isBlank(query)) { return ""; } try { // Use LinkedMultiValueMap to handle parameters with same key MultiValueMap<String, String> paramMap = new LinkedMultiValueMap<>(); String[] paramPairs = query.split(SEPARATOR); for (String pair : paramPairs) { String[] keyValue = pair.split(EQUALS, 2); if (keyValue.length == 2) { paramMap.add(keyValue[0], keyValue[1]); } } // Convert MultiValueMap to Map, values with same key become array Map<String, Object> convertedMap = new LinkedHashMap<>(); for (Map.Entry<String, List<String>> entry : paramMap.entrySet()) { String key = entry.getKey(); List<String> values = entry.getValue(); if (values.size() == 1) { convertedMap.put(key, values.get(0)); } else { convertedMap.put(key, values); } } // Use Jackson to convert Map to JsonNode JsonNode jsonNode = MAPPER.valueToTree(convertedMap); // Sort JsonNode JsonNode sortedJsonNode = sortJsonNode(jsonNode); // Convert sorted JsonNode to query string return convertJsonToQueryString(sortedJsonNode); } catch (Exception e) { return query; } } }

Python Examples
import requests import json import time import hmac import hashlib import uuid from urllib.parse import urlparse, parse_qsl, urlencode ### ===================================== ### API CONFIGURATION ### ===================================== API_KEY = "" # Please fill in your API Key API_SECRET = "" # Please fill in your API Secret BASE_URL = "https://openapi.bittap.com" ### ===================================== ### UTILITY FUNCTIONS ### ===================================== def sort_dict(d): """Recursively sort dictionary keys alphabetically""" if not isinstance(d, dict): return d sorted_dict = {} for k in sorted(d.keys()): v = d[k] if isinstance(v, dict): sorted_dict[k] = sort_dict(v) elif isinstance(v, list): sorted_dict[k] = [sort_dict(i) if isinstance(i, dict) else i for i in v] else: sorted_dict[k] = v return sorted_dict def flatten_dict(d, parent_key='', sep='.'): """Flatten nested JSON into dotted key format""" items = [] for k, v in d.items(): new_key = parent_key + sep + k if parent_key else k if v is None: continue if isinstance(v, dict): items.extend(flatten_dict(v, new_key, sep=sep).items()) elif isinstance(v, list): for i, item in enumerate(v): if item is None or (isinstance(item, list) and not item): continue if isinstance(item, dict): items.extend(flatten_dict(item, f"{new_key}[{i}]", sep=sep).items()) else: if str(item).strip(): items.append((f"{new_key}[{i}]", str(item))) else: if str(v).strip(): items.append((new_key, str(v))) return dict(items) def dict_to_query_string(d): """Convert dictionary to query string format""" return '&'.join(f"{k}={v}" for k, v in d.items()) def sort_query_params(query_string): """Sort URL query parameters alphabetically""" if not query_string: return "" params = parse_qsl(query_string, keep_blank_values=True) params.sort(key=lambda x: x[0]) return urlencode(params) def hmac_sha256_hex(data, secret): """Generate HMAC-SHA256 signature""" return hmac.new(secret.encode('utf-8'), data.encode('utf-8'), hashlib.sha256).hexdigest() ### ===================================== ### SIGNED REQUEST FUNCTIONS ### ===================================== def send_signed_post(endpoint, body): """Send a signed POST request""" url = BASE_URL + endpoint timestamp = int(time.time() * 1000) nonce = uuid.uuid4().hex sorted_body = sort_dict(body) flat_body = flatten_dict(sorted_body) body_data = dict_to_query_string(flat_body) sign_data = (body_data + "&" if body_data else "") + f"timestamp={timestamp}&nonce={nonce}" signature = hmac_sha256_hex(sign_data, API_SECRET) headers = { "X-BT-APIKEY": API_KEY, "X-BT-SIGN": signature, "X-BT-TS": str(timestamp), "X-BT-NONCE": nonce, "Content-Type": "application/json; charset=utf-8" } print(f"\n--- POST {url} ---") print("Request Body:", json.dumps(body)) print("Signature Data:", sign_data) print("Signature:", signature) resp = requests.post(url, headers=headers, json=body) print(f"Response [{resp.status_code}]:", resp.text) def send_signed_get(endpoint): """Send a signed GET request""" url = BASE_URL + endpoint timestamp = int(time.time() * 1000) nonce = uuid.uuid4().hex parsed_url = urlparse(url) sorted_query = sort_query_params(parsed_url.query) sign_data = (sorted_query + "&" if sorted_query else "&") + f"timestamp={timestamp}&nonce={nonce}" signature = hmac_sha256_hex(sign_data, API_SECRET) headers = { "X-BT-APIKEY": API_KEY, "X-BT-SIGN": signature, "X-BT-TS": str(timestamp), "X-BT-NONCE": nonce } print(f"\n--- GET {url} ---") print("Signature Data:", sign_data) print("Signature:", signature) resp = requests.get(url, headers=headers) print(f"Response [{resp.status_code}]:", resp.text) ### ===================================== ### API TEST FUNCTIONS ### ===================================== def test_batch_create(): endpoint = "/stapi/v1/batchOrders" body = { "symbol": "BTC-USDT", "items": [ { "clientOrderId": uuid.uuid4().hex, "type": "LIMIT", "price": "100002", "quantity": "0.0011", "timeInForce": "GTC", "selfTradePreventionMode": "EXPIRE_BOTH", "side": "BUY" } ] } send_signed_post(endpoint, body) def test_cancel_order(): endpoint = "/stapi/v1/cancelOrder" body = {"clientOrderId": "00295c0dadbb47a5b5a0d3fe4ad83fc9"} send_signed_post(endpoint, body) def test_batch_cancel(): endpoint = "/stapi/v1/batchCancelOrders" body = {"symbol": "BTC-USDT"} send_signed_post(endpoint, body) def test_open_orders(): send_signed_get("/stapi/v1/openOrders") def test_his_orders(): send_signed_get("/stapi/v1/hisOrders?symbol=BTC-USDT") def test_trades(): send_signed_get("/stapi/v1/trades?pageNumber=1&pageSize=10") def test_account(): send_signed_get("/stapi/v1/account") ### ===================================== ### MAIN EXECUTION ENTRY ### ===================================== if __name__ == "__main__": if not API_KEY or not API_SECRET: print("❌ ERROR: API_KEY and API_SECRET must be configured!") else: test_batch_create() test_cancel_order() test_batch_cancel() test_open_orders() test_his_orders() test_trades() test_account()

🔍 Frequently Asked Questions

Q: How to generate random string?

A: You can use the following methods:

  • JavaScript: Use crypto.randomUUID() or custom function
  • Java: Use UUID.randomUUID().toString().replace("-", "")
Q: How to handle nested objects?

A: Use recursive function to flatten nested objects, use dot notation to separate hierarchy levels.

Q: How to represent array parameters?

A: Array parameters use square bracket indexing, e.g., items[0].price=100&items[1].price=200

Q: What to do if signature verification fails?

A: Please check:

  1. Whether parameter sorting is correct
  2. Whether timestamp is within valid period
  3. Whether nonce is reused
  4. Whether API Secret is correct
Q: Which programming languages are supported?

A: We provide complete examples for JavaScript and Java, other languages can refer to the signature algorithm for self-implementation.


📚 Dependency Information

JavaScript Dependencies
{ "dependencies": { "crypto": "^1.0.1" } }
Java Dependencies
<dependencies> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-databind</artifactId> <version>2.15.2</version> </dependency> <dependency> <groupId>com.squareup.okhttp3</groupId> <artifactId>okhttp</artifactId> <version>4.11.0</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-core</artifactId> <version>6.0.11</version> </dependency> </dependencies>

🚀 Quick Start

  1. Choose programming language: Select JavaScript or Java based on your project needs
  2. Configure environment: Install necessary dependency packages
  3. Set up keys: Configure your API Key and Secret
  4. Run examples: Execute example code to verify signature algorithm
  5. Integrate into project: Integrate signature logic into your actual project

📖 More Resources

Last updated on: