# Levels string (FT1)

> The same readings as one pasteable line, the FT1 levels string, for the TradingView and thinkorswim scripts, which cannot call an API: up to 8 symbols, each with its top g gamma strikes.

Source: https://firmtape.com/docs/developers/live/levels-string

The same readings as one pasteable line, the FT1 levels string, for the TradingView and thinkorswim scripts, which cannot call an API: up to 8 symbols, each with its top `g` gamma strikes.

`GET /api/v1/levels.txt`

Plan LIVE · Key scope live · Limit 120 a minute per key; a 304 is free · Version 1.0.0 · Since 2026-09-30

**This endpoint serves:** [LIVE: Platform integrations](https://firmtape.com/docs/live#integrations), [LIVE: Levels API](https://firmtape.com/docs/live#levels-api). **Plan:** [LIVE](https://firmtape.com/features/live). LIVE: today's session every second, alerts, ASK, the levels API and the platform integrations, and 5 LAB credits a month. Every finished session is free in REPLAY.

## Parameters

| Name | What it does | Default | Error |
| --- | --- | --- | --- |
| `sym` (required) query, string | Comma list, up to 8. |  | missing_sym, too_many_symbols |
| `g` query, integer | Gamma strikes per symbol, 0 to 30. | 20 | bad_g |
| `errors` query, 200 | `200`: an error answers 200 with the same body and the real status in `X-FirmTape-Status`, for clients that cannot read a status. |  |  |
| `key` query, string | Legacy: the key in the address, for platforms that cannot send headers. Prefer the header. |  |  |

## Response

One line of text, starting `FT1`. Each block carries the key's mark `k=`.

## Errors

| Status | Code | What to do |
| --- | --- | --- |
| 400 | `missing_sym`, `too_many_symbols`, `bad_g` | A parameter is wrong. Pass `sym`, one symbol or a comma list. |
| 401 | `no_key`, `bad_key` | No key. Send `Authorization: Bearer <key>` with a key of the product's scope. |
| 403 | `live_required` | No LIVE plan. Start or renew LIVE; `pricing` names the page. |
| 429 | `rate_limited`, `too_many_places` | Over a limit. Wait `Retry-After` seconds; poll with `If-None-Match`, a 304 is free. |

## Caching

Answers carry an `ETag`: send it back as `If-None-Match` and an unchanged reading answers 304 with no body, not counted against the limit.

## Request

```sh
curl \
  -H "Authorization: Bearer $FIRMTAPE_LIVE_KEY" \
  "https://firmtape.com/api/v1/levels.txt?sym=SPX,ES"
```

```python
import os, requests

H = {"Authorization": f"Bearer {os.environ['FIRMTAPE_LIVE_KEY']}"}
r = requests.get("https://firmtape.com/api/v1/levels.txt?sym=SPX,ES", headers=H)
print(r.status_code, r.text[:500])
```

```js
const r = await fetch("https://firmtape.com/api/v1/levels.txt?sym=SPX,ES", {
  method: "GET",
  headers: { Authorization: `Bearer ${process.env.FIRMTAPE_LIVE_KEY}` },
});
console.log(r.status, await r.text());
```

## Example response

```json
FT1|ES|...

```

## Changes

- 2026-09-30: Added.
