Listen key auth pattern — binance USD-M and COIN-M futures.
The credential is not a frame: the venue issues a listen key over REST and
the key travels in the WebSocket URL's path. pre_auth/3 resolves which
endpoint issues and which refreshes it for the requested market type;
Bourse.WS.ListenKey performs the calls and Bourse.WS.connect/3 embeds the
result. This module stays network-free so endpoint resolution can be tested
without a venue.
Scope — binance spot is not a listen key venue any more
Binance removed the spot and margin listen key endpoints on 2026-02-20; a
POST /api/v3/userDataStream now answers HTTP 410 Gone (observed on
testnet.binance.vision 2026-08-06). Spot's user data stream is opened over
the WebSocket API instead — see Bourse.WS.Auth.WsApiSignature. Only the
futures endpoints below still issue keys.
Config
auth_config = %{
pre_auth: %{
type: :listen_key,
default_market_type: :linear,
endpoints: %{linear: :fapiPrivate_post_listenkey},
keepalive_endpoints: %{linear: :fapiPrivate_put_listenkey},
keepalive_ms: 1_800_000
}
}endpoints values are generated raw endpoint names — the same atoms
__endpoints__/0 reports on the exchange module — so the resolved endpoint
is dispatchable rather than a name that has to be translated first.
opts[:market_type] selects the entry (:future/:delivery/:contract
normalize to :linear/:inverse). Without it the venue's
default_market_type applies, because the market type a venue's private
stream covers is the venue's fact, not the caller's choice — binanceusdm has
only linear markets and would otherwise resolve a spot endpoint it does not
serve.
Returns from pre_auth/3
{:ok, %{endpoint:, keepalive_endpoint:, market_type:, keepalive_ms:, credentials:}}
| {:error, {:no_endpoint_for_market_type, %{requested:, normalized:, available:}}}