用户数据流 (listenKey)
接口描述
bot 订阅私有 WebSocket 频道(订单、余额、持仓)时,需用 REST 颁发的 listenKey 鉴权 WebSocket 连接。生命周期与 Binance 一致:
POST /fapi/v1/listenKey— 申请(或刷新)用户的 listenKey- 连接 WebSocket,发送
{"type":"auth","listenKey":"<key>"} auth_result.success === true后即可订阅私有频道- 可选每隔 < 60min 调一次
PUT /fapi/v1/listenKey续期(WS 在线时也会自动刷 TTL) DELETE /fapi/v1/listenKey撤销
每用户同时只有一个活跃 listenKey
重复 POST 返回同一个活跃 key 并刷新 TTL,不会生成新 key。与 Binance 行为一致。TTL 为 3600 秒。
POST /fapi/v1/listenKey
申请或刷新调用者的 listenKey。
HTTP 请求
POST /fapi/v1/listenKey (HMAC SHA256)
请求权重
1
请求参数
| 名 称 | 类型 | 是否必需 | 描述 |
|---|---|---|---|
| recvWindow | LONG | NO | 详见 接口鉴权 |
| timestamp | LONG | YES | 时间戳 |
响应示例
{
"listenKey": "a1b2c3d4e5f6g7h8i9j0klmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01"
}
key 为 64 字符字母数字字符串([A-Za-z0-9])。
PUT /fapi/v1/listenKey
将调用者活跃 listenKey 的 TTL 再延长 3600 秒。
HTTP 请求
PUT /fapi/v1/listenKey (HMAC SHA256)
请求权重
1
请求参数
无 body。用户的 listenKey 是隐式的(每用户一个活跃 key)。
响应示例
{ "listenKey": "a1b2c3..." }
错误
| Code | Message | 原因 |
|---|---|---|
-1125 | This listenKey does not exist. | 调用者无活跃 listenKey,需先 POST 申请。 |
DELETE /fapi/v1/listenKey
撤销调用者的活跃 listenKey。
HTTP 请求
DELETE /fapi/v1/listenKey (HMAC SHA256)
请求权重
1
请求参数
无 body。
响应示例
{}
幂等 — 即使调用者无活跃 key 也返回 {}。
WebSocket 鉴权
拿到 listenKey 后,连标准 WebSocket 端点并发送:
{ "type": "auth", "listenKey": "a1b2c3..." }
成功响应:
{ "type": "auth_result", "success": true, "message": null }
之后即可订阅任何私有频道(orders, balances, positions 等)。详见 WebSocket 通用信息。
WS 自动续期
经过 listenKey 鉴权的 WebSocket,每条路由消息都会刷新 Redis 中两个 key (fapi:listen_key:<key> 与反向映射) 的 TTL。维持长连的 bot 不需要显式调用 PUT /fapi/v1/listenKey —— 只要连接活跃,TTL 会一直滚动延长。WS 进入维护重连前,客户端可调 PUT 锁住 key 以便重连复用。
代码示例
cURL
API_KEY="your_api_key"
API_SECRET="your_api_secret"
TIMESTAMP=$(date +%s%3N)
QUERY_STRING="timestamp=${TIMESTAMP}"
SIGNATURE=$(echo -n "${QUERY_STRING}" | openssl dgst -sha256 -hmac "${API_SECRET}" | awk '{print $2}')
# 申请 listenKey
curl -s -X POST -H "X-MBX-APIKEY: ${API_KEY}" \
"https://api.ztdx.io/fapi/v1/listenKey?${QUERY_STRING}&signature=${SIGNATURE}"
# 续期(每 ~50 分钟一次)
curl -s -X PUT -H "X-MBX-APIKEY: ${API_KEY}" \
"https://api.ztdx.io/fapi/v1/listenKey?${QUERY_STRING}&signature=${SIGNATURE}"
# 撤销
curl -s -X DELETE -H "X-MBX-APIKEY: ${API_KEY}" \
"https://api.ztdx.io/fapi/v1/listenKey?${QUERY_STRING}&signature=${SIGNATURE}"
Python
import time, hmac, hashlib, json, requests, websocket
API_KEY = "your_api_key"
API_SECRET = "your_api_secret"
BASE_URL = "https://api.ztdx.io"
WS_URL = "wss://api.ztdx.io/ws/"
def sign(qs: str) -> str:
return hmac.new(API_SECRET.encode(), qs.encode(), hashlib.sha256).hexdigest()
def signed_request(method: str, path: str) -> dict:
ts = int(time.time() * 1000)
qs = f"timestamp={ts}"
sig = sign(qs)
r = requests.request(
method,
f"{BASE_URL}{path}?{qs}&signature={sig}",
headers={"X-MBX-APIKEY": API_KEY},
)
r.raise_for_status()
return r.json()
# 1. 申请 listenKey
listen_key = signed_request("POST", "/fapi/v1/listenKey")["listenKey"]
print(f"listenKey: {listen_key}")
# 2. 连接 + 鉴权
ws = websocket.WebSocket()
ws.connect(WS_URL)
ws.send(json.dumps({"type": "auth", "listenKey": listen_key}))
print(ws.recv()) # {"type":"auth_result","success":true,...}
# 3. 订阅私有频道
ws.send(json.dumps({"type": "subscribe", "channel": "orders"}))
ws.send(json.dumps({"type": "subscribe", "channel": "balances"}))
# 4. 接收事件
while True:
print(ws.recv())