Bourse.WS.Auth.ListenKey (bourse v0.7.0)

Copy Markdown View Source

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. USD-M uses query parameters while COIN-M uses a path segment. 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:}}}