# Key levels (classified nodes) for one or more symbols

`GET https://api.skylit.ai/v1/gex/levels`

API: Heatseeker. Credits: 1.

The strikes Skylit classifies as nodes (king, gatekeeper, pika, barney,
significant) for up to 10 symbols, strongest first, with each level's
distance from spot. Same live source, filters and 5-second cache as
`/v1/heatmap`; 1 credit per request.

Each symbol also carries `summary`: total net exposure, the strongest
positive and negative strikes (the walls), and the flip level where
cumulative net exposure changes sign. It is computed from the strikes
this request returned, so widen `maxStrikes` for a wider view.

A call that cannot finish within 20 seconds answers `504`
`gateway_timeout` (refunded); retry, or request fewer symbols.

## Authentication

Send your Skylit API key as a bearer token: `Authorization: Bearer <key>`. No other header is accepted.

## Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `symbols` | query | string | yes | One ticker, or a comma-separated list for a single cross-asset call (e.g. `SPY` or `SPXW,SPY,QQQ`). Each is returned as an element of `data.symbols`. At most 10 distinct symbols (more → `400` `invalid_parameter`). Unknown symbols in a list are omitted; if none is available → `404` `symbol_not_found`. Index options are served per option root, and the roots hold different contracts. `SPXW` is the PM-settled S&P 500 options (every daily and weekly expiration, 0DTE included), the board the Skylit app's Trinity view uses. `SPX` is only the AM-settled monthlies, so it has no 0DTE or weekly gamma and reads very differently from `SPXW`. The same split applies to `NDXP` / `NDX` and `RUTW` / `RUT`. To match the app's Trinity or read 0DTE, request `SPXW,SPY,QQQ`. |
| `metric` | query | string | no | Which Greek exposure to return per strike. (one of `gamma`, `vanna`; default `gamma`) |
| `maxStrikes` | query |  | no | Maximum number of strikes around spot to return: an integer from 1 to 1000, or `all` for every strike the snapshot lists (SPXW lists about 730). Values above 1000 return `400 invalid_parameter`; they are never silently reduced. Values below 1 are treated as 1. The single-symbol stream (`/v1/stream?symbol=`) accepts at most 400 and no `all`. (default `92`) |
| `maxExpirations` | query |  | no | How many of the nearest expirations to net into each strike's `value`: an integer from 1 to 60, or `all`. Values above 60 return `400 invalid_parameter`. Ignored when `expirations` is set. (default `5`) |
| `includeEmpty` | query | boolean | no | By default, an interior strike whose every returned cell is below 50 in absolute value (listed but effectively untraded) is left out, judged on the selected metric alone. So gamma and vanna for the same instant can return different strike lists. The outermost strikes are never removed. `true` keeps every strike in the window, so the list is the snapshot's own contiguous ladder and is identical for gamma and vanna. Not supported on the single-symbol stream (`symbol=`). (default `false`) |
| `expirations` | query | string | no | Net each strike over exactly these expirations (`YYYY-MM-DD`, comma-separated) — one for a single-expiration heatmap (`2026-05-22`) or several for a custom set (`2026-05-22,2026-06-19`). Supersedes `maxExpirations`, and reaches any expiration the snapshot has, not just the nearest ones. Requested dates the symbol does not have are ignored; the `expirations` array in the response lists what was actually used. If none of them match, the response is `404` with `code: expiration_not_found` and the available dates in the message. On `/v1/heatmap`, expirations that have already expired are not available (they are trimmed from the live snapshot) — replay them with `/v1/historical` instead. |

## Example request

```bash
curl "https://api.skylit.ai/v1/gex/levels?symbols=SPXW,SPY,QQQ" \
  -H "Authorization: Bearer $SKYLIT_API_KEY"
```

## Responses

### 200

Levels per symbol.

Shape (placeholder values):

```json
{
  "data": {
    "symbols": [
      {
        "symbol": "string",
        "asOf": "string",
        "spot": 0,
        "previousClose": 0,
        "kingNode": {
          "strike": 0,
          "value": 0,
          "nodeType": "king",
          "distancePct": 0
        },
        "levels": [
          {
            "strike": 0,
            "value": 0,
            "nodeType": "king",
            "distancePct": 0
          }
        ],
        "summary": {
          "netExposure": 0,
          "positiveWall": {
            "strike": 0,
            "value": 0,
            "nodeType": "king",
            "distancePct": 0
          },
          "negativeWall": {
            "strike": 0,
            "value": 0,
            "nodeType": "king",
            "distancePct": 0
          },
          "flip": {
            "level": 0,
            "distancePct": 0
          },
          "lowStrike": 0,
          "highStrike": 0
        }
      }
    ]
  },
  "meta": {
    "metric": "gamma",
    "resolution": "1s",
    "mode": "live",
    "cached": false,
    "delayed": false,
    "delayMinutes": 0,
    "attribution": {
      "text": "Powered by Skylit",
      "url": "string",
      "required": false,
      "license": "personal",
      "shareable": false,
      "shareClass": "derived",
      "terms": "string"
    }
  }
}
```

### 400

Request validation failed.

### 401

Missing API key (`unauthorized`), sent by the gateway.

### 402

Out of credits (`insufficient_credits`).

### 403

Unknown, revoked or expired key (`forbidden`, from the gateway), or an
admin-suspended account (`account_suspended`).

### 404

Unknown symbol, no data available, or none of the requested
`expirations` exist for the symbol (`code: expiration_not_found`).

### 429

Per-minute rate limit exceeded.

Headers: `Retry-After`.

### 503

Heatmap data is temporarily unavailable.

### 504

The request did not finish in time (`gateway_timeout`). Refunded;
retry, or narrow the request.
