User Data Stream (listenKey)
Description
Bots subscribing to private WebSocket channels (orders, balances, positions) authenticate the WebSocket connection with a listenKey issued by REST. The lifecycle mirrors Binance:
POST /fapi/v1/listenKey— issue (or refresh) the user's listenKey- Open the WebSocket and send
{"type":"auth","listenKey":"<key>"} - Subscribe to private channels after
auth_result.success === true - Call
PUT /fapi/v1/listenKeyperiodically (recommended: every 30 minutes) to extend TTL DELETE /fapi/v1/listenKeyto revoke
Repeated POST returns the same active key and refreshes its TTL — it does not mint a new one. This matches Binance behavior. The TTL is 3600 seconds.
POST /fapi/v1/listenKey
Issue or refresh the caller's listenKey.
HTTP Request
POST /fapi/v1/listenKey (HMAC SHA256)
Request Parameters
| Name | Type | Required | Description |
|---|---|---|---|
| recvWindow | LONG | NO | Ignored — the server enforces a fixed ±60 second timestamp window regardless of this value. |
| timestamp | LONG | YES | Timestamp |
Response Example
{
"listenKey": "a1b2c3d4e5f6g7h8i9j0klmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01"
}
The key is a 64-character alphanumeric string ([A-Za-z0-9]).
PUT /fapi/v1/listenKey
Extend the TTL of the caller's active listenKey by another 3600 seconds.
HTTP Request
PUT /fapi/v1/listenKey (HMAC SHA256)
Request Parameters
No body. The user's listenKey is implicit (one active key per user).
Response Example
{ "listenKey": "a1b2c3..." }
Errors
| Code | Message | Cause |
|---|---|---|
-1125 | This listenKey does not exist. | The caller has no active listenKey. Issue one via POST first. |
DELETE /fapi/v1/listenKey
Revoke the caller's active listenKey.
HTTP Request
DELETE /fapi/v1/listenKey (HMAC SHA256)
Request Parameters
No body.
Response Example
{}
Idempotent — returns {} even when the caller had no active key.
WebSocket Authentication
After obtaining a listenKey, connect to the standard WebSocket endpoint and send:
{ "type": "auth", "listenKey": "a1b2c3..." }
A successful auth returns:
{ "type": "auth_result", "success": true, "message": null }
After this the connection can subscribe to any private channel (orders, balances, positions, etc.) — see WebSocket General Info.
The TTL is refreshed only at the moment of WebSocket authentication — an open connection does not extend it afterwards. For long-running connections, call PUT /fapi/v1/listenKey every 30 minutes. Otherwise the key expires 1 hour after the last refresh, and a reconnect will fail authentication with Invalid or expired listenKey, requiring a new POST /fapi/v1/listenKey.
Code Examples
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}')
# Issue listenKey
curl -s -X POST -H "X-MBX-APIKEY: ${API_KEY}" \
"https://api.prex.world/fapi/v1/listenKey?${QUERY_STRING}&signature=${SIGNATURE}"
# Keep alive (run every ~30 minutes)
curl -s -X PUT -H "X-MBX-APIKEY: ${API_KEY}" \
"https://api.prex.world/fapi/v1/listenKey?${QUERY_STRING}&signature=${SIGNATURE}"
# Revoke
curl -s -X DELETE -H "X-MBX-APIKEY: ${API_KEY}" \
"https://api.prex.world/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.prex.world"
WS_URL = "wss://api.prex.world/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. Issue listenKey
listen_key = signed_request("POST", "/fapi/v1/listenKey")["listenKey"]
print(f"listenKey: {listen_key}")
# 2. Connect + auth
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. Subscribe to private channels
ws.send(json.dumps({"type": "subscribe", "channel": "orders"}))
ws.send(json.dumps({"type": "subscribe", "channel": "balances"}))
# 4. Read events
while True:
print(ws.recv())