跳到主要内容

用户数据流 (listenKey)

接口描述

bot 订阅私有 WebSocket 频道(订单、余额、持仓)时,需用 REST 颁发的 listenKey 鉴权 WebSocket 连接。生命周期与 Binance 一致:

  1. POST /fapi/v1/listenKey — 申请(或刷新)用户的 listenKey
  2. 连接 WebSocket,发送 {"type":"auth","listenKey":"<key>"}
  3. auth_result.success === true 后即可订阅私有频道
  4. 可选每隔 < 60min 调一次 PUT /fapi/v1/listenKey 续期(WS 在线时也会自动刷 TTL)
  5. 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

请求参数

名称类型是否必需描述
recvWindowLONGNO详见 接口鉴权
timestampLONGYES时间戳

响应示例

{
"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..." }

错误

CodeMessage原因
-1125This 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())