Binance User Data Streams Without listenKey: The Subscription Model

For years a Binance account stream began with a REST call that returned a listenKey, and the key was renewed on a timer. That model is gone from the documentation. The replacement is subtler than a new URL: the account stream is now one subscription among many on a WebSocket API session, identified by a subscriptionId, limited per connection, and ended by events rather than by an expiring string.

CoinSoso EditorialPublished Article #00148Updated

Cover artwork: CoinSoso · AI-generated, not a photograph of a real venue, product or market capture.

Key takeaways

  • Binance deprecated listenKey-based user data streams on wss://stream.binance.com in April 2025, removed the listenKey documentation on 24 October 2025, and retired the legacy REST and WebSocket API methods on 20 February 2026 at 07:00 UTC.
  • The replacement is userDataStream.subscribe on the WebSocket API: the subscription belongs to the connection, returns a subscriptionId, and requires an authenticated session using an Ed25519 API key.
  • A session supports up to 1,000 active subscriptions and 65,535 subscriptions over its lifetime, and a single connection is valid for 24 hours, so reconnection is part of the design rather than an error path.
  • eventStreamTerminated is the signal that a subscription has ended — after a listen token expires, after session.logout, or after userDataStream.unsubscribe — and it must trigger a resubscribe and a REST reconciliation.
  • session.logout closes subscriptions created with userDataStream.subscribe but not those opened with userDataStream.subscribe.signature, which is the detail that separates a single-account bot from an account-farm process.

The key that stopped being the unit

A listenKey was easy to reason about because it was a string with a lifetime. You asked for one, you kept it alive, you gave it to a stream URL, and when it died you got a new one. The account was the subject; the key was a handle to it.

The WebSocket API model changes the subject. A user data stream is now a subscription on a session: it is created by a method call, it returns a subscriptionId, it shares a connection with other subscriptions, and it ends when the session ends or when it is explicitly stopped. The account is still the thing being observed, but the thing you manage is the subscription.

Binance’s changelog records the move in three steps. On 7 April 2025 it deprecated receiving user data on wss://stream.binance.com:9443 with a listenKey and pointed clients at the WebSocket API, noting that the replacement requires an Ed25519 API key. On 24 October 2025 it removed the listenKey documentation entirely and said the old REST and WebSocket API methods would remain available only until a retirement announcement. That announcement came on 21 January 2026, and the methods stopped being available on 20 February 2026 at 07:00 UTC.

The practical reading: the old path has already closed, and the new path is not a drop-in URL swap.

What a subscription actually is

The mechanics are documented, and each one changes how a client has to be built.

It belongs to a connection. Binance states that there can be only one active subscription for a given account on a given connection. Two processes watching the same account therefore need two connections, or one process that fans events out.

It is identified, not named. userDataStream.subscribe returns a subscriptionId, and every event carries it. A process that follows several accounts has to map the id back to the account; the event payload identifies the account only through that subscriptionId, not through a field that names the account.

It is authenticated with Ed25519. The method requires an authenticated session created by session.logon, and Binance’s note is explicit that only Ed25519 keys are supported for that logon. The alternative, userDataStream.subscribe.signature, works from any session — authenticated or not — and takes an API key signature for one or more accounts.

It is capped twice. A single session supports up to 1,000 active subscriptions at once, and up to 65,535 subscriptions over its lifetime. The second number is the one that surprises long-running processes: a reconnect every minute for a month is fine, but a resubscribe loop inside a single session is not.

It is observable, but not self-proving. session.status reports userDataStream as null (not available), true (at least one active) or false (none), and session.subscriptions lists the ids. A true says a subscription exists; it does not say an event has arrived.

One WebSocket API session carrying several account subscriptions session Ed25519 logon 24-hour limit sub 0 sub 1 sub 2 account A subscribe subscriptionId 0 account B subscribe.signature subscriptionId 1 reconnect new session no subscriptions logon again resubscribe REST snapshot compare The subscription lives and dies with the session, not with the account.
Subscriptions are per connection. A reconnect does not restore them, which is why the recovery path has to begin with logon and end with a REST reconciliation.

The event set, and what each event claims

The payloads did not change with the transport. What changed is that a client now has to read subscriptionId before it reads the body, and has to know which events are deltas and which are snapshots.

Event What it means What it does not mean
outboundAccountPosition A balance changed, and the payload lists the assets possibly affected by that change That every listed balance is the complete set of assets you hold
balanceUpdate A deposit, withdrawal or transfer between accounts changed one asset by a delta That the delta has settled on-chain
executionReport An order was created, filled, cancelled, expired or rejected, with x as the execution type and X as the order status That the order is still open — X is the field that answers that
listStatus The state of an OCO or order list changed That its child orders are all in their final state
eventStreamTerminated The subscription ended That the account changed
externalLockUpdate Part of the spot balance was locked or unlocked by an external system, such as margin collateral That a trade occurred

Two details in that table are the ones that cause reconciliation bugs. outboundAccountPosition describes the assets possibly changed by the event that produced the update; it is not a full wallet dump, and treating it as one will erase balances the client did not ask about. executionReport is a lifecycle event, not a fill event: the same order produces several reports, and the fill quantities are z (cumulative) and l (last), not q (original quantity).

The stream also supports SBE as well as JSON, with Binance noting that for user data subscriptions the SBE schema must be 2:1 or later. A JSON client and an SBE client can therefore disagree about what is available without disagreeing about the account.

Three ways a subscription ends

eventStreamTerminated is the only event that is about the subscription rather than the account, and Binance lists exactly three triggers:

  1. a listen token subscription expires because the token expired;
  2. a logon subscription ends after session.logout;
  3. the subscription is stopped with userDataStream.unsubscribe.

The asymmetry between the second and third is worth designing around. session.logout closes only the subscriptions created with userDataStream.subscribe; subscriptions opened with userDataStream.subscribe.signature survive it. userDataStream.unsubscribe called with no parameter closes all subscriptions; called with a subscriptionId, it closes that one if it exists.

A process that loses its connection without either call gets no termination event at all. The 24-hour connection limit is the documented version of that failure: Binance tells clients to expect a disconnect after the 24-hour mark. The event is a courtesy on the clean paths, not a guarantee on the unclean ones.

Designing for a subscription that can vanish

The old listenKey client had one timer: renew before expiry. The subscription client needs a state machine.

Treat logon as a prerequisite, not a step. Verify at boot that the key is Ed25519 and that session.status reports userDataStream as available. An HMAC key fails here, and it fails at the first subscription rather than at the first event.

Persist the mapping from subscriptionId to account. The id is small and local, and it is the only field that tells a fan-out process which account an event belongs to. Losing the mapping after a reconnect means every event is ambiguous.

Resubscribe before you resume trading logic. On a new connection, authenticate, resubscribe, and only then clear a “stream healthy” flag. Events that arrive between the old connection’s last message and the new subscription are lost; the REST snapshot is the only way to know what happened in the gap.

Reconcile with REST on every reconnect. Compare open orders, balances and recent fills against the exchange state, then apply the stream as a delta on top. A client that trusts the stream as a complete record will eventually hold a position the exchange closed during the gap.

Watch the subscription budget. One thousand active subscriptions is generous for a single account and small for an account farm. The 65,535 lifetime cap is the harder limit: a resubscribe loop that runs every second will exhaust it inside a day, and the documented remedy is a new connection.

Handle the termination event explicitly. eventStreamTerminated should move the client into a recovering state, not into a retry loop that assumes the subscription is still there. The event carries the subscriptionId and an event time, and nothing else.

Do not infer account state from termination. A terminated stream means you stopped watching, not that the account stopped changing. The distinction is the whole reason the reconciliation step exists.

What this does not change

The event payloads, the field names, the order lifecycle and the account semantics are the same as they were under listenKey. A client that already parses executionReport correctly does not need to relearn the payload; it needs to relearn how the stream is created and how it is kept alive.

The migration is also not a reason to reopen the security questions the old model raised. The account stream carries order and balance data that is valuable to an attacker, and the credential that opens it is now an Ed25519 key that can also sign orders unless its permissions say otherwise. The isolation rules in sub-accounts and API key isolation apply unchanged: a read-only key for the stream, IP restrictions where the venue allows them, and no key that can withdraw.

For the market-data side of the same API, the stream mechanics in building a local order book from Binance depth streams are a separate subscription with a separate failure mode. For the limits that decide how often a client may call REST to reconcile, see API rate limits and order weights. And if the reconnect logic is being written alongside order entry, the fields that survive a cancel-replace are covered in cancel-replace or amend on Binance.

Risk note. The endpoints, method names, limits and event triggers in this article were read from Binance’s Spot API documentation and changelog on 2026-11-02. The legacy listenKey methods were retired on 20 February 2026 and are not part of a current integration; check the changelog for later changes. Nothing here is investment advice.

Sources

How this was researched. Written from primary documentation and the exchange or protocol's own published material, with sources listed at the end of the article.

Primary sources for the factual claims on this page. A date appears only where a human has actually read the source; where it is missing, the check is still outstanding.

  1. Binance Spot API — User Data Streams (subscription model, event types, eventStreamTerminated)(read 2026-11-02)
  2. Binance Spot API — WebSocket API: userDataStream.subscribe, subscribe.signature, session limits, session.status(read 2026-11-02)
  3. Binance Spot API — CHANGELOG (2025-04-07 deprecation; 2025-10-24 removal of listenKey documentation; 2026-01-21 retirement announcement; 2026-02-20 shutdown)(read 2026-11-02)

Frequently asked questions

Does Binance still accept listenKey?

No. The REST endpoints POST, PUT and DELETE /api/v3/userDataStream and the WebSocket API methods userDataStream.start, userDataStream.ping and userDataStream.stop stopped being available on 20 February 2026 at 07:00 UTC, following the retirement announcement of 21 January 2026. The listenKey documentation for receiving the stream on wss://stream.binance.com had already been removed on 24 October 2025. New integrations must use userDataStream.subscribe.

Why does userDataStream.subscribe require an Ed25519 API key?

Binance's own note on the method says it requires an authenticated WebSocket connection using Ed25519 keys, established with session.logon. An HMAC key can still sign REST requests, but it cannot open this subscription. If your key inventory predates the migration, that is the first thing to audit.

What happens to my subscriptions when the 24-hour connection limit is reached?

They end with the connection. Subscriptions are properties of a session, not of an account, so a reconnect starts with none. The client has to authenticate again, resubscribe, and reconcile balances and open orders against REST before it treats the stream as authoritative.

Can one WebSocket connection follow several accounts?

Yes, through userDataStream.subscribe.signature, which lets any session — authenticated or not — subscribe to one or more accounts for which it can provide an API key signature. Each account gets its own subscriptionId. The limit is 1,000 active subscriptions per session, and one subscription per account per connection.

How do I know a subscription is still alive?

Call session.status and read the userDataStream field: null means user data subscriptions are not available on that endpoint, true means at least one is active, and false means none are. session.subscriptions lists the active subscriptionIds. Neither call proves that events are flowing, so pair it with a periodic REST snapshot.

Where to go next

Independent research. Each card shows the platform’s invite code, and its Create Account button is a referral link that may earn us a commission at no extra cost to you. Whether an account can be opened is decided by the platform at sign-up.

Binance

One of the largest global exchanges by traded volume, with a very broad product range.

20% Trading Fee Rebate

Use invite code con888 when signing up to enjoy trading fee benefits.

Download Android App

Download from the exchange's official download service. Verify the source and follow the on-screen installation instructions.

Do not install an APK from an unknown source, or one that has been modified or cannot be checked.

Read review →

OKX

A large global exchange offering spot, derivatives and a self-custody wallet.

20% Trading Fee Rebate

Enter invite code con888 when signing up to check available trading fee benefits.

Download Android App

Download from the exchange's official download service. Verify the source and follow the on-screen installation instructions.

Do not install an APK from an unknown source, or one that has been modified or cannot be checked.

Read review →