# `CCXT.WS.Subscription`
[🔗](https://github.com/ZenHive/ccxt_client/blob/main/lib/ccxt/ws/subscription.ex#L1)

WebSocket subscription pattern dispatcher.

Parallel of `CCXT.WS.Auth`: a function-head dispatcher that routes a
pattern atom to the matching per-pattern module. Each pattern module
implements the `CCXT.WS.Subscription.Behaviour` callbacks.

## Supported Patterns

| Pattern atom                  | Exchanges                                 | Frame shape                                      |
|-------------------------------|-------------------------------------------|--------------------------------------------------|
| `:op_subscribe`               | bybit, bitmex                             | `%{"op"=>"subscribe","args"=>[strings]}`         |
| `:op_subscribe_objects`       | okx                                       | `%{"op"=>"subscribe","args"=>[objects]}`         |
| `:method_subscribe`           | binance, xt, aster                        | `%{"method"=>"SUBSCRIBE","params"=>[strings]}`   |
| `:method_params_subscribe`    | kraken, cryptocom                         | `%{"method"=>"subscribe","params"=>%{"channel"=>[strings]}}` |
| `:method_subscription`        | hyperliquid                               | `%{"method"=>"subscribe","subscription"=>%{"type"=>…}}` |
| `:method_topics`              | exmo                                      | `%{"method"=>"subscribe","topics"=>[strings]}`   |
| `:method_as_topic`            | coinex, phemex                            | `%{"method"=>"ticker.subscribe","params"=>[],"id"=>…}` |
| `:jsonrpc_subscribe`          | deribit                                   | JSON-RPC 2.0 envelope with correlation id        |
| `:event_subscribe`            | gate, bitfinex, woo, bitrue               | `%{"event"=>"subscribe","channel"=>…}` variants  |
| `:type_subscribe`             | kucoin, coinbaseexchange                  | `%{"type"=>"subscribe","topic"=>…}` variants     |
| `:sub_subscribe`              | htx, huobi                                | `%{"sub"=>…}` — **one frame per channel**, no `id` (see `SubBased` moduledoc) |
| `:reqtype_sub`                | bingx                                     | `%{"reqType"=>"sub","dataType"=>…}` — **one frame per channel** |
| `:action_subscribe`           | alpaca, lbank                             | `%{"action"=>"subscribe","params"=>%{…}}`        |
| `:custom`                     | bithumb, upbit, deepcoin, … (escape hatch)| dispatches on `config[:custom_type]`             |

## Return shape

`build_subscribe/3` returns `{:ok, frame_or_frames}` where
`frame_or_frames` is `map() | [map()]`. Single-frame exchanges return a
map; multi-frame exchanges (HTX, BingX, Upbit-custom) return a list.

Pattern modules may also surface input-shape rejections as
`{:error, term()}` (e.g. `:multiple_maps_not_supported` /
`:mixed_channel_types` from `:event_subscribe` and
`:method_params_subscribe` when callers mix shapes). The dispatcher
passes those tuples through verbatim — it never wraps them in `{:ok, _}`.

Unknown patterns return `{:error, {:unknown_pattern, atom}}` — matches
`CCXT.WS.Auth`'s dispatcher-head behavior.

# `build_result`

```elixir
@type build_result() :: {:ok, frame() | [frame()]} | {:error, term()}
```

# `channel`

```elixir
@type channel() :: String.t() | map()
```

# `config`

```elixir
@type config() :: map()
```

# `frame`

```elixir
@type frame() :: map()
```

# `pattern`

```elixir
@type pattern() ::
  :op_subscribe
  | :op_subscribe_objects
  | :method_subscribe
  | :method_params_subscribe
  | :method_subscription
  | :method_topics
  | :method_as_topic
  | :jsonrpc_subscribe
  | :event_subscribe
  | :type_subscribe
  | :sub_subscribe
  | :reqtype_sub
  | :action_subscribe
  | :custom
```

# `build_subscribe`

```elixir
@spec build_subscribe(pattern(), [channel()], config()) :: build_result()
```

Builds the subscribe frame(s) for the pattern and channel list.

Returns `{:ok, map()}` for the common single-frame case, or
`{:ok, [map()]}` for multi-frame exchanges (HTX, BingX, Upbit-custom).
Callers should handle both shapes.

# `build_unsubscribe`

```elixir
@spec build_unsubscribe(pattern(), [channel()], config()) :: build_result()
```

Builds the unsubscribe frame(s) — same return shape as `build_subscribe/3`.

# `module_for_pattern`

```elixir
@spec module_for_pattern(pattern()) :: module() | nil
```

Returns the implementing module for a pattern, or `nil` if unknown.

# `patterns`

```elixir
@spec patterns() :: [pattern()]
```

Lists every supported subscription pattern atom.

---

*Consult [api-reference.md](api-reference.md) for complete listing*
