> ## Documentation Index
> Fetch the complete documentation index at: https://takeprofit.com/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# WebSocket API

> The streaming half of the TakeProfit Platform API: how the handshake authenticates, the query parameters the channels share, what frames each stream delivers, keepalive pings, how a stream ends and how to reconnect, and what a subscription costs.

Live market data over WebSocket: candles, volume footprint profiles and order books. Subscription parameters go in the query string of the connection URL, and the server pushes JSON text frames until you disconnect. The client sends nothing after the handshake.

```bash theme={null}
websocat -H "x-api-key: $TAKEPROFIT_API_KEY" \
  "wss://public-api.takeprofit.com/api/v1/marketdata/candles/stream?exchange=CXBNCE&symbol=BTC%2FUSDT&timeframe=1m"
```

Base URL: `wss://public-api.takeprofit.com/api/v1/marketdata`. History is a separate protocol — see the [REST API](https://takeprofit.com/docs/platform-api/rest/overview).

## Streams

> **[Candles](https://takeprofit.com/docs/platform-api/websocket/candles.md)**
>
> The latest candle, then live updates of the forming one.

> **[Volume footprint](https://takeprofit.com/docs/platform-api/websocket/footprint.md)**
>
> An optional historical snapshot, then complete profile replacements.

> **[Order book](https://takeprofit.com/docs/platform-api/websocket/orderbook.md)**
>
> One snapshot of the top levels per side, then incremental updates.

| Stream | Path | Required parameters |
| - | - | - |
| Candles | `/candles/stream` | `exchange`, `symbol`, `timeframe` |
| Footprint | `/footprint/stream` | `exchange`, `symbol`, `timeframe` |
| Order book | `/orderbook/stream` | `exchange`, `symbol` |

## The handshake

The API key goes in the `x-api-key` header of the upgrade request, exactly as in REST. One header value is required; duplicate or comma-combined values are rejected. A failed handshake answers with a regular HTTP response and a JSON body:

| Status | Meaning |
| - | - |
| `400` | Invalid query, or no WebSocket upgrade |
| `401` | Authentication failed |
| `403` | Permission denied: the key lacks the `MARKETDATA:ALL:READ` scope |
| `405` | A method other than `GET` |
| `429` | Not enough credits left in the window for the stream's price |
| `503` | Service unavailable, retry with exponential backoff |

Unknown query parameters and repeated scalar parameters are rejected, and historical range parameters such as `from`, `to` and `limit` are not accepted: use REST for history.

## Parameters the streams share

| Parameter | Applies to | Notes |
| - | - | - |
| `exchange`, `symbol` | all streams | Required. The same pair the REST Securities endpoints return. |
| `timeframe` | candles, footprint | Required. Footprint takes minute to month frames. |
| `throttlingDelay` | all streams | Milliseconds, up to 60000. A positive delay coalesces updates into at most one frame per delay; `0` or omitted forwards every upstream batch. |
| `sessionType` | candles, footprint | Session filter. Candles default to `MAINSESSION`; footprint delivers every session type when omitted. |
| `properties` | candles | Candle fields to include, such as `close,volume`. The timestamp is always present. |
| `rowSize`, `rowSizeValue` | footprint | Price row height in ticks, or an absolute value that pins the price grid. |
| `since` | footprint | Start of the initial snapshot. Omitted means no snapshot: the first live profile arrives when the next period opens. |
| `depth` | order book | Levels per side, default 200; `0` streams the full book. |

## Frames

Every frame carries a `type` and a `meta` echo of the normalized subscription parameters. Candle frames also carry a numeric `tag` echoed from the upstream subscription: it is informational, and you can ignore it.

| Frame | Stream | What it means |
| - | - | - |
| `candle` | candles | A replayed or updated candle. |
| `rowSize` | footprint | The price grid resolved for this subscription. Echo it back as `rowSizeValue` in REST to load history on the same grid. |
| `rangeTruncated` | footprint | The history depth limit moved your `since` forward. Its presence tells a trimmed answer apart from a security with no data that far back. |
| `footprint` | footprint | One complete profile. `isLast` marks the frame that ends the initial snapshot. |
| `snapshot` | order book | The full top-`depth` view, exactly once per connection. |
| `update` | order book | Changed levels only; size `"0"` removes a level. |
| `error` | all streams | A terminal error; the socket closes right after it. |

Order book levels are keyed by numeric price, so `"1.5"` and `"1.50"` are the same level. An upstream resync is absorbed into a regular `update`, so you never see a second `snapshot`.

Error frames carry a stable code: `canceled`, `invalid_argument`, `unauthenticated`, `permission_denied`, `not_found`, `conflict`, `rate_limited`, `too_much_data`, `deadline_exceeded`, `unimplemented`, `unavailable` or `upstream_error`. On the order book, `too_much_data` means the client did not read the stream fast enough for its `depth`.

## Keepalive and reconnects

* **The server pings every 30 seconds.** A client that does not answer with a pong within 5 seconds is disconnected. Most WebSocket libraries answer pings on their own; if your connections drop about 35 seconds in, check that yours does. There is no idle timeout besides that.
* **One connection carries one subscription.** The query string is the whole subscription, and nothing can be added to an open connection. Open a connection per stream.
* **The server closes with code `1000`.** A terminal error first arrives as an `error` frame, then the close. The normal end of the upstream stream and an exhausted quota (`rate_limited`) close with the same code, so read the last frame to tell them apart.
* **Reconnect with exponential backoff**, and treat a `503` on the handshake the same way. A reconnect is a new subscription and is charged again.

## Credits

Streams spend their own quota of 1,000 credits per 300 seconds, shared by all API keys on your account and separate from REST. A subscription costs 10 credits for candles, 25 for footprint and 50 for the order book, charged when upstream data confirms it rather than per frame, and charged again in every window the connection stays open in. A stream that dies on a terminal upstream error before it is confirmed is not charged.

The handshake needs the full price of the stream in remaining credits, otherwise it is rejected with `429`. If an open stream cannot renew because the window is spent, it ends with an `error` frame with code `rate_limited`. How many streams the quota holds at once is worked out in [Credits and limits](https://takeprofit.com/docs/platform-api/limits.md#what-streams-cost).


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.