Skip to Content
📈 Futures API鉴权认证

认证与安全

📋 目录


🔐 请求鉴权要求

创建 API

在使用 API 前,您需前往 Bittap 官网-个人中心-API 管理 或者 BittapApp-个人中心-API 管理 进行创建 创建完成后,请妥善保管API key 和 API secret 为了安全起见,请在创建 API 时同时设置白名单 请勿将 API key / Secret key 泄露给第三方;若不慎泄露,请立即生成新的 API 进行使用

权限设置

新创建的 API 默认没有任何权限,需要您手动开启现货 / 合约的 API 权限

必需请求头

所有需要认证的接口都必须包含以下请求头:

请求头类型必需说明
X-BT-APIKEYString您的 API Key
X-BT-SIGNString请求签名
X-BT-TSLong请求时间戳(毫秒)
X-BT-NONCEString随机字符串
签名参数

签名计算需要以下参数:

  • timestamp: 当前时间戳(毫秒)
  • nonce: 随机字符串,建议使用 UUID
  • appSecret: 您的 API Secret

🔑 签名规则

1. 参数排序规则

所有参数按照以下规则进行排序:

  1. 按 key 的字典序升序排列
  2. 相同 key 的参数按 value 的字典序升序排列
  3. 数组参数按索引顺序排列
2. 参数拼接规则

URL参数

  1. 包含问号(?)后的所有参数。
  2. 将key进行字典排序然后进行拼接。
  3. 过滤空数组、null、空字符串。
  4. 示例:param1=value1&param2=value2。

Body参数

  1. JSON对象需扁平化为查询字符串格式。
  2. 数组必须转换为key[index]=value格式。
  3. 嵌套对象使用点号(.)表示层级。
  4. 将key进行字典排序然后进行拼接。
  5. 过滤空数组、null、空字符串。

注意事项

  1. GET请求只取urlQuery参数,POST请求取body参数,忽略url参数。
  2. 必须包含timestamp和nonce参数。
  3. 参数之间用&连接。
  4. 对于没有参数的GET请求,签名的原始字符串以&开头。
&timestamp=1752647583398&nonce=e4c5e38c57a741f6a4658713
  1. 有参数的请求,签名的原始字符串以参数开头
name=andy&timestamp=1752647583398&nonce=e4c5e38c57a741f6a4658713
3. 特殊处理规则
  • 嵌套对象: 使用点号分隔,如 user.name=张三
  • 数组: 使用方括号索引,如 hobbies[0]=阅读
  • 空值: 跳过 null 和空字符串
  • 布尔值: 转换为字符串
4. 签名计算

使用 HMAC-SHA256 算法计算签名:

signature = HMAC-SHA256(data, appSecret)

其中 data 是排序拼接后的参数字符串。


📝 签名示例

示例 1: 简单参数

请求参数:

{ "a": 2, "b": 1, "c": 3 }

排序拼接:

a=2&b=1&c=3

最终签名串:

a=2&b=1&c=3&timestamp=1752647583398&nonce=e4c5e38c57a741f6a4658713
示例 2: 嵌套对象

请求参数:

{ "a": [ {"b": 4, "c": 3}, {"x": 8, "y": 9} ], "b": { "data": { "aa": [3, 2, 1] }, "a": 2, "z": 1 } }

排序拼接后:

a[0].b=4&a[0].c=3&a[3].x=8&a[3].y=9&b.a=2&b.data.aa[0]=3&b.data.aa[1]=2&b.data.aa[2]=1&b.z=1&timestamp=1752647583398&nonce=e4c5e38c57a741f6a4658713
示例 3: GET 请求

URL 参数:

categories=homeConfig,appConfig&a=2&a=1&c=1&d=123

排序后:

a[0]=1&a[1]=2&c=1&categories=homeConfig,appConfig&d=123
示例 4: 数组请求体

请求体:

[{"key1":"xxx","key2":"xx"}]

转换后:

[0].key1=xxx&[0].key2=xx

⚙️ 签名计算步骤

步骤 1: 准备参数
const timestamp = Date.now(); const nonce = generateNonce(); const params = { symbol: "BTC-USDT", quantity: 0.001, price: 50000 };
步骤 2: 扁平化对象
function flattenObject(obj, parentKey = '', result = {}) { for (const [key, value] of Object.entries(obj)) { const currentKey = parentKey ? `${parentKey}.${key}` : key; if (value == null) continue; if (Array.isArray(value)) { value.forEach((item, index) => { if (item != null) { const arrayKey = `${currentKey}[${index}]`; if (typeof item === 'object') { flattenObject(item, arrayKey, result); } else { result[arrayKey] = item.toString(); } } }); } else if (typeof value === 'object') { flattenObject(value, currentKey, result); } else { result[currentKey] = value.toString(); } } return result; }
步骤 3: 排序参数
const flattened = flattenObject(params); const sortedParams = Object.entries(flattened) .sort((a, b) => a[0].localeCompare(b[0])) .map(([key, value]) => `${key}=${value}`) .join('&');
步骤 4: 添加必需参数
const signData = `${sortedParams}&timestamp=${timestamp}&nonce=${nonce}`;
步骤 5: 计算签名
const crypto = require('crypto'); function generateSignature(data, secret) { const hmac = crypto.createHmac('sha256', secret); hmac.update(data); return hmac.digest('hex'); } const signature = generateSignature(signData, appSecret);
步骤 6: 发送请求
const response = await fetch('/api/endpoint', { method: 'POST', headers: { 'Content-Type': 'application/json', 'X-BT-APIKEY': apiKey, 'X-BT-SIGN': signature, 'X-BT-TS': timestamp, 'X-BT-NONCE': nonce }, body: JSON.stringify(params) });

⚠️ 注意事项

  1. 时间戳: 服务器时间与客户端时间差异不能超过 5 分钟
  2. 随机字符串: 每次请求必须使用不同的 nonce
  3. 参数编码: 所有参数值需要进行 URL 编码
  4. 签名验证: 服务器会验证签名的正确性和时效性
  5. 安全存储: 请妥善保管您的 API Secret,不要泄露给他人

🔍 常见问题

Q: 为什么签名验证失败?

A: 请检查以下几点:

  • 参数排序是否正确
  • 时间戳是否在有效期内
  • nonce 是否重复使用
  • API Secret 是否正确
Q: 如何处理数组参数?

A: 数组参数需要按照索引顺序展开,如 items[0].price=100&items[1].price=200

Q: 嵌套对象如何表示?

A: 使用点号分隔,如 user.profile.name=张三

最后更新于: