> From TickerLayer docs, Perpetuals: https://tickerlayer.com/docs/products/perpetuals#perpetuals-agg-range
> REST base URL https://api.tickerlayer.com, API key in the `x-api-key` header. WebSocket wss://stream.tickerlayer.com?apiKey=YOUR_API_KEY. Full API reference: https://tickerlayer.com/llms-full.txt

## Aggregate bars (OHLCV)

**Endpoint:** `GET /perpetuals/agg/:symbol/:multiplier/:timespan/:from/:to`

Historical OHLCV bars between two UTC calendar dates (inclusive).

### Path parameters

| Parameter | Type | Required | Description |
| --- | --- | --- | --- |
| `symbol` | string | Yes | Perpetual contract symbol (for example XAUUSDT, TSMUSDT, BTCUSDT). Trimmed and uppercased before lookup. Retrieve the full list from GET /perpetuals/symbols. |
| `multiplier` | number | Yes | Bar size in units of `timespan`: `1`, `5` or `15` with `minute`; `1` or `4` with `hour`; `1` with `day`. Other pairs return `400`, and the message lists the valid ones. |
| `timespan` | string | Yes | Case-insensitive. Other values return `400`. Values: `minute`, `hour`, `day`. |
| `from` | string | Yes | First UTC date, inclusive, as `YYYY-MM-DD`. |
| `to` | string | Yes | Last UTC date, inclusive, as `YYYY-MM-DD`. Not before `from`. |

### Query parameters

| Parameter | Type | Description |
| --- | --- | --- |
| `limit` | number | Page size, up to `5000`. `results_count` is the size of this page and `total_count` the bars in the whole range; follow `next_offset` until it is `null`. Default: `500`. |
| `offset` | number | Zero-based row offset, applied after sorting. Default: `0`. |
| `sort` | string | Order of bars by timestamp `t`, applied before pagination. Values: `asc`, `desc`. Default: `desc`. |

### Request

```bash
curl -sS "https://api.tickerlayer.com/perpetuals/agg/XAUUSDT/1/day/2026-09-01/2026-09-14?sort=desc&limit=3" \
  -H "x-api-key: <YOUR_API_KEY>"
```

```python
import requests

res = requests.get(
    "https://api.tickerlayer.com/perpetuals/agg/XAUUSDT/1/day/2026-09-01/2026-09-14?sort=desc&limit=3",
    headers={"x-api-key": "<YOUR_API_KEY>"},
)
print(res.json())
```

```javascript
const res = await fetch("https://api.tickerlayer.com/perpetuals/agg/XAUUSDT/1/day/2026-09-01/2026-09-14?sort=desc&limit=3", {
  headers: { "x-api-key": "<YOUR_API_KEY>" },
});
const data = await res.json();
console.log(data);
```

```go
req, _ := http.NewRequest("GET", "https://api.tickerlayer.com/perpetuals/agg/XAUUSDT/1/day/2026-09-01/2026-09-14?sort=desc&limit=3", nil)
req.Header.Set("x-api-key", "<YOUR_API_KEY>")
```

### Response

```json
{
  "symbol": "XAUUSDT",
  "results_count": 3,
  "total_count": 14,
  "results": [
    { "o": 4298.4, "h": 4331.2, "l": 4290.1, "c": 4316.3, "v": 278600.08, "t": 1789344000000 },
    { "o": 4305.9, "h": 4312.7, "l": 4287.5, "c": 4298.4, "v": 214380.51, "t": 1789257600000 },
    { "o": 4279.2, "h": 4310.0, "l": 4271.8, "c": 4305.9, "v": 236911.37, "t": 1789171200000 }
  ],
  "next_offset": 3
}
```

### Notes

- Bars are built from traded prices on the contract's primary market source, one source per contract so a chart is never stitched from two series. `v` is that source's volume in base units, not the whole market. The live composite quote can sit a few ticks away from the latest bar close.
- Maximum span per request: 7 days for 1 minute bars, 31 for 5 minute, 90 for 15 minute, 365 for 1 hour, 730 for 4 hour. A few contracts carry shorter windows; the `400` message states the limit for that symbol.
- History starts when the contract was first listed, which for many perpetuals is recent. Bars are UTC, the day opens at 00:00 UTC, and the newest bar is still forming.
