> ## 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.

# Quickstart

> Make a first Platform API request - find a security, load historical candles over REST with the x-api-key header, then subscribe to live candles over WebSocket.

This guide takes you from an API key to live candles in three requests.

## Before you start

* An API key. See [Authentication](/docs/platform-api/authentication).
* `curl` for REST requests and any WebSocket client that can send headers, for example [websocat](https://github.com/vi/websocat).

Keep the key in an environment variable so it does not end up in your shell history or code:

```bash theme={null}
export TAKEPROFIT_API_KEY="your-api-key"
```

## 1. Find a security

Every data request needs an `exchange` and a `symbol`. Look them up with search:

```bash theme={null}
curl -G "https://public-api.takeprofit.com/api/v1/marketdata/search" \
  -H "x-api-key: $TAKEPROFIT_API_KEY" \
  --data-urlencode "query=BTC/USDT" \
  --data-urlencode "limit=3"
```

Each hit contains an `exchange` and `symbol` pair you can pass to the other endpoints. Always take the pair from here: exchange codes are TakeProfit's own, not the MIC of the listing venue, so Apple comes back as `exchange=BATS`, not `XNAS`. The same symbol usually trades on several exchanges, so pick the one you want:

```json theme={null}
{
  "hits": [
    {
      "symbol": "BTC/USDT",
      "exchange": "CXBNCE",
      "name": "Bitcoin / Tether",
      "type": "Crypto",
      "baseAsset": "BTC",
      "quoteAsset": "USDT"
    },
    {
      "symbol": "BTC/USDT",
      "exchange": "CXBPOT",
      "name": "Bitcoin / Tether",
      "type": "Crypto",
      "baseAsset": "BTC",
      "quoteAsset": "USDT"
    },
    {
      "symbol": "BTC/USDT.P",
      "exchange": "CXBNF8",
      "name": "Bitcoin / Tether Perpetual",
      "type": "Crypto",
      "baseAsset": "BTC",
      "quoteAsset": "USDT"
    }
  ]
}
```

## 2. Load historical candles

Ask for hourly candles from a given timestamp. The range is optional — without it you get the most recent 1000 candles — so `from`, `to`, `period` and `limit` are there to narrow the window. Note that `period` counts seconds (`86400`), it is not a timeframe id:

```bash theme={null}
curl -G "https://public-api.takeprofit.com/api/v1/marketdata/candles" \
  -H "x-api-key: $TAKEPROFIT_API_KEY" \
  --data-urlencode "exchange=CXBNCE" \
  --data-urlencode "symbol=BTC/USDT" \
  --data-urlencode "timeframe=1h" \
  --data-urlencode "from=2026-09-01T00:00:00Z" \
  --data-urlencode "limit=3"
```

Prices and volumes come as decimal strings, so no precision is lost:

```json theme={null}
{
  "meta": { "exchange": "CXBNCE", "symbol": "BTC/USDT", "timeframe": "1h" },
  "candles": [
    {
      "timestamp": "2026-09-01T00:00:00Z",
      "open": "78581.3",
      "high": "78900.01",
      "low": "78562",
      "close": "78652",
      "volume": "522.70913",
      "sessionType": "MAINSESSION"
    },
    {
      "timestamp": "2026-09-01T01:00:00Z",
      "open": "78652",
      "high": "78797.99",
      "low": "78375.83",
      "close": "78410.62",
      "volume": "440.9443",
      "sessionType": "MAINSESSION"
    }
  ]
}
```

Trailing zeros are trimmed, so a price can come back as `78562` rather than `78562.00`. Parse the strings with a decimal type, never a float.

Valid timeframe ids come from `GET /api/v1/marketdata/timeframes`.

## 3. Subscribe to live candles

Open a WebSocket connection with the subscription parameters in the query string and the key in the handshake header:

```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"
```

The server first sends the latest candle, then an update every time the forming candle changes. You send nothing after the handshake:

```json theme={null}
{
  "type": "candle",
  "meta": { "exchange": "CXBNCE", "symbol": "BTC/USDT", "timeframe": "1m" },
  "tag": 1,
  "isLast": true,
  "candle": {
    "timestamp": "2026-09-24T02:38:00Z",
    "open": "84194.63",
    "high": "84242.01",
    "low": "84194.62",
    "close": "84242.01",
    "volume": "5.09024",
    "sessionType": "MAINSESSION"
  }
}
```

The first frame carries `"isLast": true` — it closes the history the stream starts from. Every later frame for the forming candle arrives with `"isLast": false` and the same `timestamp`, so update the candle in place instead of appending it.

## Errors

A REST error, or a rejected WebSocket handshake, comes back as an HTTP status with a JSON body:

```json theme={null}
{ "error": { "code": "invalid_argument", "message": "unknown query parameter \"limit\"" } }
```

Every error uses that shape, and `code` is stable enough to branch on: `invalid_argument` for a bad or unknown parameter, `unauthenticated` for a missing or rejected key, `not_found` for an exchange or symbol that is not served.

| Status | Meaning |
| - | - |
| `400` | Invalid or unknown query parameter |
| `401` | Missing or invalid API key |
| `403` | The key has no access to this data |
| `404` | Security or data not found |
| `429` | Credit quota exhausted |
| `502`, `503`, `504` | Temporary upstream problem, retry later |

## Next steps

* Browse the endpoints in the **REST API** and **WebSocket API** groups of this tab.
* Read the [Overview](/docs/platform-api/overview) for what each group returns and how credits are charged.
