# OHLCV price bars for a symbol and resolution

`GET https://atlas-api.skylit.ai/v1/history`

API: Atlas. Credits: 1.

TradingView UDF history bars for one `symbol` at one `resolution`,
covering `[from, to)` (Unix seconds; `to` is exclusive). Returns column arrays (`t`, `o`,
`h`, `l`, `c`, `v`) of equal length, oldest-first. When the window
holds no bars the response is a `200` with `{ "s": "no_data" }` (plus
`nextTime` pointing at the nearest earlier bar when one exists), per the
UDF contract. Equity bars also carry sided-volume columns (`bv`/`sv`/`uv`
= buy / sell / unclassified) where available.

## Request-window limit

One call may span at most a fixed number of **trading days**, set by the
bar tier the resolution reads from — not by the resolution itself. `240`
and `60` share the 1-hour tier and therefore share its allowance.

| Tier   | Resolutions                | Max trading days / request |
|--------|----------------------------|---------------------------:|
| 1-min  | `1` `2` `3` `5` `15` `30`  |                         90 |
| 1-hour | `60` `240` `480`           |                        720 |
| 1-day  | `D` `W`                    |                      2,600 |

A window **wider than the cap is rejected with `400`**, carrying the two
numbers a client needs to react (`requested_days`, `max_days`). It is
never silently shortened — a short `{ "s": "ok" }` always means the data
ends there, never that your range was clipped. Page through anything
wider in windows of `max_days` or fewer.

A rejected `400` is refunded (failed calls are free). The caps are
fixed and published here, so check your range before sending it rather
than discovering the limit by retrying. `/v1/config` is free if you
would rather read the feed's capabilities first.

Cache-Control tracks data freshness: today `max-age=2`, the prior
session `max-age=60`, older complete days `immutable`. A `400` is
`no-store`.

## Authentication

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

## Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `symbol` | query | string | yes | Ticker (e.g. `SPY`). |
| `resolution` | query | string | yes | Bar size. Intraday minutes or `D`/`W`. (one of `1`, `2`, `3`, `5`, `15`, `30`, `60`, `240`, `480`, `D`, `W`) |
| `from` | query | integer (int64) | yes | Window start, Unix seconds (UTC). |
| `to` | query | integer (int64) | yes | Window end, Unix seconds (UTC). |
| `countback` | query | integer | no | When set, return exactly this many bars ending at `to` (takes precedence over `from`, per the UDF spec). (min 1) |
| `extended` | query | boolean | no | Include extended-hours (pre / post-market) bars. Default is regular trading hours only (09:30–16:00 ET). (default `false`) |

## Example request

```bash
curl "https://atlas-api.skylit.ai/v1/history?symbol=SPY&resolution=D&from=1748131200&to=1748736000" \
  -H "Authorization: Bearer $SKYLIT_API_KEY"
```

## Responses

### 200

Bars, or a `no_data` marker — both `200` per UDF.

Headers: `X-Credits-Remaining`, `Cache-Control`, `X-RateLimit-Limit`, `X-RateLimit-Remaining`, `X-RateLimit-Reset`.

SPY daily (truncated):

```json
{
  "s": "ok",
  "t": [
    1748304000,
    1748390400,
    1748476800
  ],
  "o": [
    742.1,
    744.02,
    733.9
  ],
  "h": [
    750.18,
    745.61,
    739.94
  ],
  "l": [
    741.55,
    732.88,
    731.2
  ],
  "c": [
    744.38,
    733.68,
    733.05
  ],
  "v": [
    61230400,
    74910200,
    58120900
  ]
}
```

Empty window:

```json
{
  "s": "no_data",
  "nextTime": 1746057600
}
```

### 400

The requested range is wider than the resolution's tier allows.
Refunded, like every failed call.

Headers: `X-Credits-Remaining`, `Cache-Control`.

171 trading days asked of the 90-day 1-minute tier:

```json
{
  "s": "error",
  "errmsg": "requested range spans 171 trading days; resolution \"1\" allows at most 90 per request. Narrow the range, or page through it in windows of 90 trading days or fewer.",
  "requested_days": 171,
  "max_days": 90
}
```

### 401

Missing or invalid API key.

### 402

Credit balance is below the request cost.

Headers: `X-Credits-Remaining`.

outOfCredits:

```json
{
  "error": {
    "code": "insufficient_credits",
    "message": "Out of credits."
  }
}
```

### 403

Account is not API-eligible (suspended).

suspended:

```json
{
  "error": {
    "code": "account_suspended",
    "message": "Account suspended."
  }
}
```

### 429

Per-minute rate limit exceeded.

Headers: `Retry-After`.

### 503

The credit ledger or datafeed is temporarily unavailable.
