> TickerLayer documentation for AI agents and LLMs, the Markdown version of https://tickerlayer.com/docs/products/stocks
> REST base URL https://api.tickerlayer.com, API key in the `x-api-key` header. WebSocket wss://stream.tickerlayer.com?apiKey=YOUR_API_KEY.
> Any docs page reads as Markdown at its URL plus `.md`. Index: https://tickerlayer.com/llms.txt · Full API reference: https://tickerlayer.com/llms-full.txt

# Stocks

Stocks supports US and international equities. Use market-qualified symbols in the same CC:SYMBOL format across REST and WebSocket, for example US:AAPL or DE:BMW.

- **Auth:** x-api-key header
- **Base path:** /stocks
- **WebSocket:** stocks.quotes · stocks.trades · stocks.agg · stocks.status
- **Symbol format:** CC:SYMBOL (e.g. US:KO, DE:BMW, TR:THYAO)

Equity responses reflect a consolidated, normalized aggregated view across supported markets. Individual fields may be optional depending on market conditions; see each route for response details.

## Symbols

**Format:** CC:SYMBOL

**Examples:** `US:AAPL` `DE:BMW` `ES:IBE` `TR:THYAO` `SA:2222`

**Discovery:** [Symbols reference](https://tickerlayer.com/docs/rest/symbols) `GET /stocks/symbols`

**Market filter:** ?market=US optional, any two-letter market code

`CC` is a two-letter ISO-style market code; `SYMBOL` is the listing ticker. Plain tickers without a prefix are rejected. Omit `market` on list calls to return all markets enabled on your account. Path examples use a literal colon; some HTTP clients encode it automatically.

## Available markets

These are the markets you can buy today; new markets are added here the day they go live. Most markets list their 50 most traded stocks.

**Live now:** 20 markets

- Argentina
- Brazil
- China
- France
- Germany
- Hong Kong
- India
- Italy
- Japan
- Mexico
- Romania
- Saudi Arabia
- South Korea
- Spain
- Sweden
- Taiwan
- Thailand
- Turkey
- United Arab Emirates
- United States

Latency varies by market (real-time or delayed). Need a market that is not listed? [Request it from the symbols directory](https://tickerlayer.com/symbols).

## New US listings

We track new US listings continuously. Once a new symbol passes review it becomes available across REST and WebSocket, and it appears on any active [`US:*` stream](https://tickerlayer.com/docs/products/stocks#websocket-streaming) automatically, with no re-subscribe needed.

## Symbol list

**Endpoint:** `GET /stocks/symbols`

Returns enabled stocks with market-qualified symbols (CC:SYMBOL), sorted by market then symbol. Results are filtered to markets enabled on your account. Optional query market=CC further filters to one market (for example market=US or market=TR).

### Request

```bash
curl -sS "https://api.tickerlayer.com/stocks/symbols?market=US" \
  -H "x-api-key: <YOUR_API_KEY>"
```

```python
import requests

res = requests.get(
    "https://api.tickerlayer.com/stocks/symbols?market=US",
    headers={"x-api-key": "<YOUR_API_KEY>"},
)
print(res.json())
```

```javascript
const res = await fetch("https://api.tickerlayer.com/stocks/symbols?market=US", {
  headers: { "x-api-key": "<YOUR_API_KEY>" },
});
const data = await res.json();
console.log(data);
```

```go
req, _ := http.NewRequest("GET", "https://api.tickerlayer.com/stocks/symbols?market=US", nil)
req.Header.Set("x-api-key", "<YOUR_API_KEY>")
```

### Response

```json
{
  "symbols": [
    {
      "symbol": "US:AAPL",
      "base_symbol": "AAPL",
      "market": "US",
      "name": "Apple Inc."
    }
  ]
}
```

## Latest quote

**Endpoint:** `GET /stocks/quote/:symbol`

Best bid and ask from the aggregated quote cache when present; otherwise resolved via the REST aggregation path for the symbol.

### Path parameters

| Parameter | Type | Required | Description |
| --- | --- | --- | --- |
| `symbol` | string | Yes | Market-qualified symbol (CC:SYMBOL, e.g. US:AAPL, DE:BMW, TR:THYAO). Plain tickers are rejected. Discover enabled rows via GET /stocks/symbols (optional ?market=CC filter). |

### Request

```bash
curl -sS "https://api.tickerlayer.com/stocks/quote/US:AAPL" \
  -H "x-api-key: <YOUR_API_KEY>"
```

```python
import requests

res = requests.get(
    "https://api.tickerlayer.com/stocks/quote/US:AAPL",
    headers={"x-api-key": "<YOUR_API_KEY>"},
)
print(res.json())
```

```javascript
const res = await fetch("https://api.tickerlayer.com/stocks/quote/US:AAPL", {
  headers: { "x-api-key": "<YOUR_API_KEY>" },
});
const data = await res.json();
console.log(data);
```

```go
package main

import (
  "fmt"
  "io"
  "net/http"
)

func main() {
  req, _ := http.NewRequest("GET", "https://api.tickerlayer.com/stocks/quote/US:AAPL", nil)
  req.Header.Set("x-api-key", "<YOUR_API_KEY>")
  resp, _ := http.DefaultClient.Do(req)
  defer resp.Body.Close()
  body, _ := io.ReadAll(resp.Body)
  fmt.Println(string(body))
}
```

### Response

```json
{
  "symbol": "US:AAPL",
  "bid": 214.22,
  "ask": 214.25,
  "bid_size": 1200,
  "ask_size": 800,
  "timestamp": 1743512400000
}
```

### Notes

`400 invalid stock symbol; expected MARKET:BASE (example: US:AAPL)` when the path is not market-qualified. `403` when the market of the symbol is not enabled on your account; every route that takes a symbol answers the same way. `404 unknown symbol` if the symbol is not in the enabled registry. `503 market data temporarily unavailable` when lookup fails with no serviceable quote.

## Last trade

**Endpoint:** `GET /stocks/trade/last/:symbol`

Latest executed trade from the aggregated tape when present; when the live tape snapshot is empty, price and timestamp fall back to the consolidated quote mid.

### Path parameters

| Parameter | Type | Required | Description |
| --- | --- | --- | --- |
| `symbol` | string | Yes | Market-qualified symbol (CC:SYMBOL, e.g. US:AAPL, DE:BMW, TR:THYAO). Plain tickers are rejected. Discover enabled rows via GET /stocks/symbols (optional ?market=CC filter). |

### Request

```bash
curl -sS "https://api.tickerlayer.com/stocks/trade/last/US:AAPL" \
  -H "x-api-key: <YOUR_API_KEY>"
```

```python
import requests

res = requests.get(
    "https://api.tickerlayer.com/stocks/trade/last/US:AAPL",
    headers={"x-api-key": "<YOUR_API_KEY>"},
)
print(res.json())
```

```javascript
const res = await fetch("https://api.tickerlayer.com/stocks/trade/last/US:AAPL", {
  headers: { "x-api-key": "<YOUR_API_KEY>" },
});
const data = await res.json();
console.log(data);
```

```go
req, _ := http.NewRequest("GET", "https://api.tickerlayer.com/stocks/trade/last/US:AAPL", nil)
req.Header.Set("x-api-key", "<YOUR_API_KEY>")
```

### Response

```json
{
  "symbol": "US:AAPL",
  "price": 214.23,
  "size": 400,
  "timestamp": 1743512400000
}
```

### Notes

`503 market data temporarily unavailable` when no trade can be served yet. `size` may occasionally be null: the print carried no size, or the value came from a quote-only fallback.

## Snapshot

**Endpoint:** `GET /stocks/snapshot/:symbol`

Combined bid/ask, last trade price, previous daily close, and derived change metrics in a single call.

### Path parameters

| Parameter | Type | Required | Description |
| --- | --- | --- | --- |
| `symbol` | string | Yes | Market-qualified symbol (CC:SYMBOL, e.g. US:AAPL, DE:BMW, TR:THYAO). Plain tickers are rejected. Discover enabled rows via GET /stocks/symbols (optional ?market=CC filter). |

### Request

```bash
curl -sS "https://api.tickerlayer.com/stocks/snapshot/US:AAPL" \
  -H "x-api-key: <YOUR_API_KEY>"
```

```python
import requests

res = requests.get(
    "https://api.tickerlayer.com/stocks/snapshot/US:AAPL",
    headers={"x-api-key": "<YOUR_API_KEY>"},
)
print(res.json())
```

```javascript
const res = await fetch("https://api.tickerlayer.com/stocks/snapshot/US:AAPL", {
  headers: { "x-api-key": "<YOUR_API_KEY>" },
});
const data = await res.json();
console.log(data);
```

```go
req, _ := http.NewRequest("GET", "https://api.tickerlayer.com/stocks/snapshot/US:AAPL", nil)
req.Header.Set("x-api-key", "<YOUR_API_KEY>")
```

### Response

```json
{
  "symbol": "US:AAPL",
  "bid": 214.22,
  "ask": 214.25,
  "bid_size": 1200,
  "ask_size": 800,
  "last_price": 214.23,
  "last_size": 400,
  "last_timestamp": 1743512400000,
  "prev_close": 212.10,
  "change": 2.13,
  "change_percent": 1.004
}
```

### Notes

`last_size` is present only when a native trade size is available. `change_percent` is `null` when `prev_close` is zero or unavailable. An all-null snapshot returns `503`.

## Previous bar

**Endpoint:** `GET /stocks/agg/:symbol/prev`

Single most-recently completed UTC daily candle for the symbol.

### Path parameters

| Parameter | Type | Required | Description |
| --- | --- | --- | --- |
| `symbol` | string | Yes | Market-qualified symbol (CC:SYMBOL, e.g. US:AAPL, DE:BMW, TR:THYAO). Plain tickers are rejected. Discover enabled rows via GET /stocks/symbols (optional ?market=CC filter). |

### Query parameters

| Parameter | Type | Description |
| --- | --- | --- |
| `interval` | string | Returns the most recently settled bar at that interval instead of the previous daily bar, and adds `interval`, `bar_start`, `bar_end` and `as_of` to the response. Leave it out for the daily bar. Values: `1m`, `5m`, `15m`, `1h`, `4h`, `1d`. |

### Request

```bash
curl -sS "https://api.tickerlayer.com/stocks/agg/US:AAPL/prev" \
  -H "x-api-key: <YOUR_API_KEY>"
```

```python
import requests

res = requests.get(
    "https://api.tickerlayer.com/stocks/agg/US:AAPL/prev",
    headers={"x-api-key": "<YOUR_API_KEY>"},
)
print(res.json())
```

```javascript
const res = await fetch("https://api.tickerlayer.com/stocks/agg/US:AAPL/prev", {
  headers: { "x-api-key": "<YOUR_API_KEY>" },
});
const data = await res.json();
console.log(data);
```

```go
req, _ := http.NewRequest("GET", "https://api.tickerlayer.com/stocks/agg/US:AAPL/prev", nil)
req.Header.Set("x-api-key", "<YOUR_API_KEY>")
```

### Response

```json
{
  "symbol": "US:AAPL",
  "result": {
    "o": 228.5,
    "h": 230.8,
    "l": 227.9,
    "c": 229.4,
    "v": 52000000,
    "t": 1733011200000
  }
}
```

### Notes

`404 no bar available` when the daily bar cannot be resolved yet. A bar requested with `?interval=` is held for a short settle lag after it closes, so small clock differences between callers do not change which bar comes back, and it is the same bar the range endpoint returns for that window. `Cache-Control` and `ETag` mark when the value can next change. While the market is closed the last real bar is returned, still labelled with its own `bar_start`.

## Aggregate bars (OHLCV)

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

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

### Path parameters

| Parameter | Type | Required | Description |
| --- | --- | --- | --- |
| `symbol` | string | Yes | An enabled symbol of this asset class, for example `BTCUSD` or `US:KO`. Trimmed before lookup. |
| `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/stocks/agg/US:AAPL/1/day/2025-11-01/2025-11-30?sort=desc&limit=2" \
  -H "x-api-key: <YOUR_API_KEY>"
```

```python
import requests

res = requests.get(
    "https://api.tickerlayer.com/stocks/agg/US:AAPL/1/day/2025-11-01/2025-11-30",
    params={"sort": "desc", "limit": 2},
    headers={"x-api-key": "<YOUR_API_KEY>"},
)
print(res.json())
```

```javascript
const res = await fetch(
  "https://api.tickerlayer.com/stocks/agg/US:AAPL/1/day/2025-11-01/2025-11-30?sort=desc&limit=2",
  { headers: { "x-api-key": "<YOUR_API_KEY>" } },
);
const data = await res.json();
console.log(data);
```

```go
req, _ := http.NewRequest("GET",
  "https://api.tickerlayer.com/stocks/agg/US:AAPL/1/day/2025-11-01/2025-11-30?sort=desc&limit=2", nil)
req.Header.Set("x-api-key", "<YOUR_API_KEY>")
```

### Response

```json
{
  "symbol": "US:AAPL",
  "results_count": 2,
  "results": [
    { "o": 228.5, "h": 230.8, "l": 227.9, "c": 229.4, "v": 52000000, "t": 1733011200000 },
    { "o": 226.0, "h": 228.9, "l": 225.5, "c": 228.5, "v": 48000000, "t": 1732924800000 }
  ],
  "next_offset": 2
}
```

### Notes

- One request covers at most 31 days of 1-minute bars, 90 of 5-minute, 180 of 15-minute, 365 of hourly, 730 of 4-hour and 5000 of daily bars, counting `from` and `to` as whole UTC days. A longer range returns `400` with the limit in the message.
- `v` may occasionally be null per bar when no consolidated volume exists for that interval.
- US symbols: sub-daily bars cover the regular session (09:30 to the close, exchange time) and carry consolidated volume, including the session in progress. Hourly bars start at 09:30, 4-hour bars at 09:30 and 13:30. Pre-market and after-hours bars stream on [stocks.agg](https://tickerlayer.com/docs/products/stocks#stocks-agg-stream) with `"session": "extended"`.

## WebSocket

Stream live quotes and trades for this asset class over the public WebSocket.

**Connect**

```
wss://stream.tickerlayer.com/?apiKey=<YOUR_API_KEY>
```

### Available channels

- `stocks.quotes`: quotes
- `stocks.trades`: trades
- `stocks.agg`: settled bars ([documented here](https://tickerlayer.com/docs/products/stocks#stocks-agg-stream))

### Subscribe example

After the connection is ready, send a JSON text frame:

```json
{
  "action": "subscribe",
  "channels": [
    "stocks.quotes",
    "stocks.trades"
  ],
  "symbols": [
    "US:KO",
    "DE:BMW"
  ]
}
```

### Example messages

**stocks.quotes**

```json
{
  "type": "quote",
  "channel": "stocks.quotes",
  "asset": "stocks",
  "symbol": "US:KO",
  "bid": "62.41",
  "ask": "62.43",
  "bid_size": "100",
  "ask_size": "200",
  "ts": 1743512400000
}
```

**stocks.trades**

```json
{
  "type": "trade",
  "channel": "stocks.trades",
  "asset": "stocks",
  "symbol": "US:KO",
  "price": "62.42",
  "size": "100",
  "ts": 1743512400000
}
```

### Full-volume trades

On US `stocks.trades`, set `trade_mode` to `full_volume` to receive every volume-eligible execution, not only the price-forming ones. Expect a noticeably higher message rate; subscriptions without `trade_mode` are unaffected.

**Optional: US stocks.trades full_volume**

```json
{
  "action": "subscribe",
  "channel": "stocks.trades",
  "symbols": ["US:SPCX"],
  "trade_mode": "full_volume"
}
```

Each message then carries `ohlc`, so you do not have to classify trades yourself:

| Value | Meaning |
| --- | --- |
| `"ohlc": 1` | Apply the trade to the candle's open, high, low and close. |
| `"ohlc": 0` | Count the trade toward volume only. |

**Message: US stocks.trades with full_volume**

```json
{
  "type": "trade",
  "channel": "stocks.trades",
  "asset": "stocks",
  "symbol": "US:SPCX",
  "price": "111.56",
  "size": "37",
  "ts": 1785342925003,
  "ohlc": 0
}
```

### Whole-market streaming (`US:*`) on Enterprise

One token, `"symbols": ["US:*"]`, subscribes `stocks.quotes` and `stocks.trades` to the entire market, and new listings join the stream without a re-subscribe or reconnect. It is not enabled by default on any account: [talk to us](https://tickerlayer.com/consultation) to switch it on.

**Enterprise: whole US market with one token**

```json
{
  "action": "subscribe",
  "channels": ["stocks.quotes", "stocks.trades"],
  "symbols": ["US:*"]
}
```

### General WebSocket documentation

For authentication, subscribe/unsubscribe lifecycle, errors, limits, and heartbeats, see the [WebSocket overview](https://tickerlayer.com/docs/websocket), [Subscriptions](https://tickerlayer.com/docs/websocket/subscriptions) and [Message types](https://tickerlayer.com/docs/websocket/messages).

## OHLCV bars over WebSocket

The bars the aggregate routes return, delivered live and included with US stocks access. Subscribe to `stocks.agg` with US symbols and receive one `agg` frame per symbol each time a bar settles, on the grid `/stocks/agg` serves: a bar you receive live is the bar the REST route returns for that window later.

**1-minute (default)**

```json
{
  "action": "subscribe",
  "channels": ["stocks.agg"],
  "symbols": ["US:KO", "US:JPM"]
}
```

**Several intervals**

```json
{
  "action": "subscribe",
  "channels": ["stocks.agg"],
  "symbols": ["US:KO"],
  "interval": ["1m", "5m", "1d"]
}
```

**Extended hours**

```json
{
  "action": "subscribe",
  "channels": ["stocks.agg"],
  "symbols": ["US:KO"],
  "interval": ["1m", "5m"],
  "session": "extended"
}
```

**agg frame**

```json
{
  "type": "agg",
  "channel": "stocks.agg",
  "asset": "stocks",
  "symbol": "US:KO",
  "interval": "1m",
  "session": "regular",
  "o": 88.48,
  "h": 88.52,
  "l": 88.46,
  "c": 88.5,
  "v": 41230,
  "n": 312,
  "vw": 88.4917,
  "ts": 1789133400000
}
```

Numbers are numbers: `o h l c v` the bar, `n` the trade count, `vw` the volume-weighted average price, `session` where the bar starts (`pre`, `regular`, `post`) and `ts` the bar start in unix ms. A frame arrives a few seconds after its window closes.

| Interval | Arrives | Grid |
| --- | --- | --- |
| `1m` | Right after each traded minute; a minute without a trade has no bar. | Every minute of the session. |
| `5m` `15m` | As each window closes, rolled up from the minute bars. | On the clock from 09:30 ET: 09:30, 09:35 … and 09:30, 09:45 … |
| `1h` `4h` | As each window closes; the last one closes with the session. | Anchored at the open like the REST grid: 09:30, 10:30 … and 09:30, 13:30 ET. |
| `1d` | About two minutes after the closing bell. | Official open and close with consolidated volume, labelled at the session date's UTC midnight: the bar `GET /stocks/agg/:symbol/prev` returns. |

- **Sessions:** Intraday bars cover the regular session, 09:30 to 16:00 ET with early closes honored, and the closing auction lands in the daily bar. With `"session": "extended"`, 1m, 5m and 15m bars also arrive from 04:00 to 20:00 ET (17:00 on early closes), tagged `pre`, `regular` or `post`; regular-session bars are identical in both modes, and 1h, 4h and 1d always follow the regular grid.
- **Closed bars only:** No in-progress updates: one frame per symbol, interval and window, however busy the tape. Build a live candle from `stocks.trades` if you need one.
- **No snapshot:** The first frame arrives within one interval. Backfill with `/stocks/agg`, which serves the same bars; a bar that settles while you are disconnected is not replayed.
- **Intervals per symbol:** `interval` takes a string or an array. The latest subscribe for a symbol sets its intervals, and an unsubscribe removes it from all of them.
- **US equities only:** Symbols count toward your distinct-symbol cap like any channel; the market wildcard add-on enables `US:*` here too.

## Overnight session New

An add-on to US Stocks: a derived, aggregated reference quote for the most traded US stocks and ETFs while the listing markets are closed on weeknights (Sunday to Thursday, 20:00 to 04:00 New York). Our aggregation layer blends the sources behind each name and drops outliers, and a price is withdrawn as soon as its inputs no longer support it rather than left behind to be read as current.

- **Get it:** Pick it next to United States in [pricing](https://tickerlayer.com/pricing?feed=stocks&country=US&addon=us_overnight), or add it to a running US Stocks plan from your [dashboard](https://tickerlayer.com/dashboard?addon=us_overnight#plan-access): you pay for the days left in your period and it renews with the plan.
- **Separate channel:** `overnight.quotes` and the `/overnight` routes, so your `stocks.*` integration does not change. Outside the overnight session the channel is silent. Quotes only: there is no overnight trades channel.
- **Symbols:** The ones you already use: stocks as `US:KO`, ETFs under the ETF feed codes (`US500ETF`, `US100ETF`, `USGOLD`).

**Subscribe: overnight quotes**

```json
{
  "action": "subscribe",
  "channels": ["overnight.quotes"],
  "symbols": ["US:KO", "US:JPM"]
}
```

**quote frame**

```json
{
  "type": "quote",
  "channel": "overnight.quotes",
  "asset": "stocks",
  "symbol": "US:KO",
  "bid": "62.3914",
  "ask": "62.4367",
  "mid": "62.4141",
  "session": "overnight",
  "dispersion_bps": 5.25,
  "ts": 1789808856800
}
```

| Field | Meaning |
| --- | --- |
| `mid` | The aggregated reference price. Prices are strings, as on every stocks quote frame. |
| `bid` `ask` | Around the mid, at the aggregated half spread. |
| `dispersion_bps` | How far the sources stood from the published mid, in basis points: low means they agree. Gate on it to widen margins or pause on thin nights. It is 0 when a single input carries the quote, for example in the first minute after a Sunday or holiday open; bid and ask then sit at least 30 bps from the mid. |
| `ts` | Time of the newest contributing quote, unix ms. |
| `snapshot` | A frame is sent when the aggregated quote changes; the last one is replayed with `"snapshot": true` right after you subscribe. |

**REST: latest overnight quote**

```bash
curl -sS "https://api.tickerlayer.com/overnight/quote/US:KO" \
  -H "x-api-key: <YOUR_API_KEY>"
```

**Response**

```json
{
  "symbol": "US:KO",
  "bid": 62.3914,
  "ask": 62.4367,
  "mid": 62.4141,
  "session": "overnight",
  "dispersion_bps": 5.25,
  "timestamp": 1789808856800
}
```

`GET /overnight/symbols` lists the covered symbols and whether the session is open; `GET /overnight/snapshot?symbols=US:KO,US:JPM` returns several quotes in one call, or all of them when `symbols` is left out.

## Overnight full spread

By default bid and ask sit at the aggregated half spread. Subscribe with `"spread": "full"` (or add `?spread=full` to the REST routes) and they widen to the spread the night market is quoting, around the same mid: a thin book at the open shows as a wide spread instead of being averaged away. Same frame, same fields.

| Value | bid and ask |
| --- | --- |
| `"normalized"` | Default. The aggregated half spread around the mid. |
| `"full"` | The spread quoted at night around the same mid. A subscribe is answered with a spread message after the ack. |

**Subscribe at full spread**

```json
{
  "action": "subscribe",
  "channels": ["overnight.quotes"],
  "symbols": ["US:KO", "US:JPM"],
  "spread": "full"
}
```
