Skip to main content

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:

  1. POST /fapi/v1/listenKey — issue (or refresh) the user's listenKey
  2. Open the WebSocket and send {"type":"auth","listenKey":"<key>"}
  3. Subscribe to private channels after auth_result.success === true
  4. Call PUT /fapi/v1/listenKey periodically (recommended: every 30 minutes) to extend TTL
  5. DELETE /fapi/v1/listenKey to revoke
One active listenKey per user

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

NameTypeRequiredDescription
recvWindowLONGNOIgnored — the server enforces a fixed ±60 second timestamp window regardless of this value.
timestampLONGYESTimestamp

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

CodeMessageCause
-1125This 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.

Keep the listenKey alive with PUT

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())