# Replay — per-strike heatmap at a past instant (one or more symbols)

`GET https://api.skylit.ai/v1/historical`

API: Heatseeker. Credits: 5.

The latest snapshot at or before `at` for one or more symbols — same
shape as `/v1/heatmap` minus `velocityPct` (velocity is live-only),
including `layout=matrix` for the per-expiration grid. Precision is
1 second where 1-second history exists for that day and 1 minute
otherwise; `meta.resolution` says which. `at` may go back to
2023-03-28, where heatmap history begins (coverage per symbol varies;
`/v1/symbols` lists each symbol's first date). If no snapshot exists
at/near that instant the response is `404` with `code: no_data`.
A read 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`. |
| `at` | query | string (date-time) | yes | RFC3339 instant to replay (e.g. `2026-03-05T10:01:00Z`). Not before 2023-03-28. |
| `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. |
| `layout` | query | string | no | `net` (default) returns one net value per strike. `matrix` also returns `matrix`, the per-expiration grid those values are summed from. (one of `net`, `matrix`; default `net`) |

## Example request

```bash
curl "https://api.skylit.ai/v1/historical?symbols=SPXW,SPY,QQQ&at=<at>" \
  -H "Authorization: Bearer $SKYLIT_API_KEY"
```

## Responses

### 200

Historical heatmap snapshot(s).

Headers: `X-RateLimit-Limit`, `X-RateLimit-Remaining`, `X-RateLimit-Reset`.

SPY at a past minute (truncated):

```json
{
  "data": {
    "symbols": [
      {
        "symbol": "SPY",
        "asOf": "2026-03-05T10:01:00Z",
        "spot": 512.4,
        "previousClose": 510.02,
        "priceChange": 2.38,
        "priceChangePercent": 0.47,
        "expirations": [
          "2026-03-05",
          "2026-03-06"
        ],
        "strikes": [
          {
            "strike": 512,
            "value": 1500200,
            "nodeType": "king"
          },
          {
            "strike": 515,
            "value": 410000,
            "nodeType": "gatekeeper"
          }
        ]
      }
    ]
  },
  "meta": {
    "metric": "gamma",
    "resolution": "1s",
    "mode": "historical",
    "cached": false
  }
}
```

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

No snapshot at/near the requested instant, none of the requested
symbols is available, or none of the requested `expirations` exist
in that snapshot.

symbolNotFound:

```json
{
  "error": {
    "code": "symbol_not_found",
    "message": "Symbol \"ZZZZQ\" is not available."
  }
}
```

noData:

```json
{
  "error": {
    "code": "no_data",
    "message": "No snapshot available for SPY at 2025-01-01T10:01:00Z."
  }
}
```

expirationNotFound:

```json
{
  "error": {
    "code": "expiration_not_found",
    "message": "None of the requested expirations are available for SPY. Available: 2026-03-05, 2026-03-06, 2026-03-07."
  }
}
```

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