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

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

API: Heatseeker. Credits: 5.

The snapshot nearest `at` for one or more symbols — same shape as
`/v1/heatmap` minus `velocityPct` (velocity is live-only). `at` may be
up to 365 days in the past; if no snapshot exists at/near that instant
the response is `404` with `code: no_data`.

## 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 `SPY,SPX,QQQ`). Each is returned as an element of `data.symbols`. |
| `at` | query | string (date-time) | yes | RFC3339 instant to replay (e.g. `2026-03-05T10:01:00Z`). Up to 365 days back. |
| `metric` | query | string | no | Which Greek exposure to return per strike. (one of `gamma`, `vanna`; default `gamma`) |
| `maxStrikes` | query | integer | no | Maximum number of strikes around spot to return. (default `92`; min 1; max 400) |
| `maxExpirations` | query | integer | no | How many of the nearest expirations to net into each strike's `value`. Ignored when `expirations` is set. (default `5`; min 1; max 60) |
| `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/historical?symbols=SPY,SPX,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": "1m",
    "mode": "historical",
    "cached": false
  }
}
```

### 400

Request validation failed.

### 401

Missing or invalid API key.

### 403

The API key is invalid, revoked or expired, or the account is suspended.

### 404

No snapshot at/near the requested instant, unknown symbol, or none
of the requested `expirations` exist in that snapshot.

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.
