> TickerLayer documentation for AI agents and LLMs, the Markdown version of https://tickerlayer.com/docs/products/forex
> 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

# Forex

Major FX pairs and crosses as six-character symbols (e.g. EURUSD), priced as indicative OTC-style quotes.

- **Auth:** x-api-key header
- **Base path:** /forex
- **WebSocket:** forex.quotes · forex.trades
- **Symbol format:** Six-letter pairs (e.g. EURUSD, GBPJPY, USDTRY)

## Symbols

Pairs are six-letter codes such as `EURUSD`, `GBPJPY` and `USDTRY`; list the enabled ones with `GET /forex/symbols` ([Symbols](https://tickerlayer.com/docs/rest/symbols#forex-symbols)). A raw single-venue line is also served as `SYMBOL.RAW`, outside the symbol list: see [Raw line](https://tickerlayer.com/docs/products/forex#forex-raw-line).

## Symbol list

**Endpoint:** `GET /forex/symbols`

Returns enabled FX pairs and crosses, sorted by symbol ascending.

### Request

```bash
curl -sS "https://api.tickerlayer.com/forex/symbols" \
  -H "x-api-key: <YOUR_API_KEY>"
```

```python
import requests

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

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

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

### Response

```json
{
  "symbols": [
    { "symbol": "EURUSD", "name": "Euro / United States Dollar" },
    { "symbol": "GBPUSD", "name": "British Pound / United States Dollar" }
  ]
}
```

## Latest quote

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

Bid and ask from the aggregated FX quote cache when present; otherwise resolved via the REST aggregation path for the pair.

### Path parameters

| Parameter | Type | Required | Description |
| --- | --- | --- | --- |
| `symbol` | string | Yes | Enabled forex pair (e.g. EURUSD). Six-character concatenated pair, trimmed and uppercased before lookup. Retrieve the full list from GET /forex/symbols. |

### Request

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

```python
import requests

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

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

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

### Response

```json
{
  "symbol": "EURUSD",
  "bid": 1.0522,
  "ask": 1.0524,
  "bid_size": 42,
  "ask_size": 37,
  "timestamp": 1743512400000
}
```

### Notes

`404 unknown symbol` if the pair is not in the enabled registry.

## Last trade

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

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

### Path parameters

| Parameter | Type | Required | Description |
| --- | --- | --- | --- |
| `symbol` | string | Yes | Enabled forex pair (e.g. EURUSD). Six-character concatenated pair, trimmed and uppercased before lookup. Retrieve the full list from GET /forex/symbols. |

### Request

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

```python
import requests

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

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

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

### Response

```json
{
  "symbol": "EURUSD",
  "price": 1.0523,
  "size": 96,
  "timestamp": 1743512400000
}
```

### Notes

`size` is `number | null`: it may occasionally be null when no lot size exists in the consolidated view.

## Snapshot

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

Combined bid/ask, last price, previous daily close, and derived change metrics in one normalized aggregated view.

### Path parameters

| Parameter | Type | Required | Description |
| --- | --- | --- | --- |
| `symbol` | string | Yes | Enabled forex pair (e.g. EURUSD). Six-character concatenated pair, trimmed and uppercased before lookup. Retrieve the full list from GET /forex/symbols. |

### Request

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

```python
import requests

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

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

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

### Response

```json
{
  "symbol": "EURUSD",
  "bid": 1.0522,
  "ask": 1.0524,
  "bid_size": 42,
  "ask_size": 37,
  "last_price": 1.0523,
  "last_timestamp": 1743512400000,
  "prev_close": 1.0480,
  "change": 0.0043,
  "change_percent": 0.4103
}
```

### Notes

`last_size` appears when a trade size is available in the consolidated snapshot; otherwise it is omitted from the payload. `change_percent` is `null` when `prev_close` is zero or not yet available.

## Previous bar

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

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

### Path parameters

| Parameter | Type | Required | Description |
| --- | --- | --- | --- |
| `symbol` | string | Yes | Enabled forex pair (e.g. EURUSD). Six-character concatenated pair, trimmed and uppercased before lookup. Retrieve the full list from GET /forex/symbols. |

### 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/forex/agg/EURUSD/prev" \
  -H "x-api-key: <YOUR_API_KEY>"
```

```python
import requests

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

```javascript
const res = await fetch("https://api.tickerlayer.com/forex/agg/EURUSD/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/forex/agg/EURUSD/prev", nil)
req.Header.Set("x-api-key", "<YOUR_API_KEY>")
```

### Response

```json
{
  "symbol": "EURUSD",
  "result": {
    "o": 1.0500,
    "h": 1.0528,
    "l": 1.0488,
    "c": 1.0523,
    "v": 9820000000,
    "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 /forex/agg/:symbol/:multiplier/:timespan/:from/:to`

Historical FX bars between two UTC calendar dates.

### 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/forex/agg/EURUSD/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/forex/agg/EURUSD/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/forex/agg/EURUSD/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/forex/agg/EURUSD/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": "EURUSD",
  "results_count": 2,
  "results": [
    { "o": 1.0500, "h": 1.0528, "l": 1.0488, "c": 1.0523, "v": 9820000000, "t": 1733011200000 },
    { "o": 1.0475, "h": 1.0505, "l": 1.0460, "c": 1.0500, "v": 8750000000, "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 when no consolidated volume is published for that interval.

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

- `forex.quotes`: quotes
- `forex.trades`: trades

### Subscribe example

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

```json
{
  "action": "subscribe",
  "channels": [
    "forex.quotes",
    "forex.trades"
  ],
  "symbols": [
    "EURUSD",
    "GBPUSD"
  ]
}
```

### Example messages

**forex.quotes**

```json
{
  "type": "quote",
  "channel": "forex.quotes",
  "asset": "forex",
  "symbol": "EURUSD",
  "bid": "1.08512",
  "ask": "1.08518",
  "bid_size": "1000000",
  "ask_size": "1000000",
  "ts": 1743512400000
}
```

**forex.trades**

```json
{
  "type": "trade",
  "channel": "forex.trades",
  "asset": "forex",
  "symbol": "EURUSD",
  "price": "1.08515",
  "size": "1000000",
  "ts": 1743512400000
}
```

### Timestamps

Every frame carries a millisecond `ts` that is strictly increasing per symbol within its channel, so two ticks never share a timestamp and clients can sort or de-duplicate on it safely.

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

## Raw line: SYMBOL.RAW

The default feed is consolidated across venues, which keeps it stable for pricing, oracles and risk. For charting, backtesting and anything that must look like a broker terminal, add `.RAW` to the pair: the same pairs as an unblended single-venue tick stream, every tick as the venue printed it, with real tick volume and no smoothing. Same key, channels and message shape.

**subscribe**

```json
{
  "action": "subscribe",
  "channels": ["forex.quotes", "forex.trades"],
  "symbols": ["EURUSD.RAW", "GBPUSD.RAW", "XAUUSD.RAW"]
}
```

- **One venue:** Published as received: candles built from it match a raw-spread broker terminal, wicks included.
- **Sizes:** `forex.trades` carries the venue tick volume in `size`; quote `bid_size` and `ask_size` are `null`.
- **REST and history:** Also on `/forex/quote`, `/forex/trade/last` and `/forex/snapshot`. The aggregates endpoints accept `.RAW` too, with candles and tick volume from the same venue back to 2010.
- **Coverage:** The majors, the main crosses and emerging-market pairs, plus spot gold, silver, platinum and palladium. Still expanding: tell us if a pair you chart is missing.
