GET /v1/rates/historical
Returns historical OHLCV (Open, High, Low, Close, Volume) candle data for a single pair. Supports 5-minute, hourly, and daily intervals with cursor-based pagination for fetching large ranges efficiently.
Authentication
This endpoint requires an API key. See Authentication.
Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
pair | string | Yes | Pair identifier (e.g., USDTNGN). See Pairs for the full list. |
start | string | Yes | Start date in YYYY-MM-DD format (inclusive). |
end | string | Yes | End date in YYYY-MM-DD format (inclusive). Maximum range is 5 years from start. |
interval | string | No | Candle interval. One of 5m, 1h, or 1d. Default: 1h. |
limit | integer | No | Maximum number of candles to return per page. Must be between 1 and your tier's page cap. Defaults to your tier cap if omitted. |
cursor | string | No | Pagination cursor returned in the previous response as next_cursor. Pass this to fetch the next page. Omit for the first page. |
Tier page caps:
| Tier | Max limit |
|---|---|
| Free | 500 |
| Builder | 2,500 |
| Professional | 5,000 |
| Enterprise | 10,000 |
Response
| Field | Type | Description |
|---|---|---|
pair | string | The requested pair. |
interval | string | The interval used for aggregation. |
candles | array | Array of OHLCV candle objects ordered chronologically. |
candles[].timestamp | string | ISO 8601 UTC timestamp marking the start of the candle period. |
candles[].open | number | VWAP at the start of the period. |
candles[].high | number | Highest VWAP observed during the period. |
candles[].low | number | Lowest VWAP observed during the period. |
candles[].close | number | VWAP at the end of the period. |
candles[].volume | number | Total base volume traded across all exchanges during the period. |
has_more | boolean | true if there are more candles beyond this page. Use next_cursor to fetch them. |
next_cursor | string | Opaque cursor to pass as the cursor parameter on the next request. Only present when has_more is true. |
warning | string | Present only when data quality issues are detected, such as gaps in the requested range. |
Examples
First page
curl -X GET "https://api.moxiemetrx.com/v1/rates/historical?pair=USDTNGN&start=2026-01-01&end=2026-03-01&interval=1h&limit=100" \
-H "X-API-Key: your_key"
import requests
response = requests.get(
"https://api.moxiemetrx.com/v1/rates/historical",
params={
"pair": "USDTNGN",
"start": "2026-01-01",
"end": "2026-03-01",
"interval": "1h",
"limit": 100,
},
headers={"X-API-Key": "your_key"},
)
data = response.json()
print(f"Returned {len(data['candles'])} candles, has_more={data['has_more']}")
const response = await fetch(
"https://api.moxiemetrx.com/v1/rates/historical?pair=USDTNGN&start=2026-01-01&end=2026-03-01&interval=1h&limit=100",
{ headers: { "X-API-Key": "your_key" } }
);
const data = await response.json();
console.log(`Returned ${data.candles.length} candles, has_more=${data.has_more}`);
interface Candle {
timestamp: string;
open: number;
high: number;
low: number;
close: number;
volume: number;
}
interface HistoricalResponse {
pair: string;
interval: string;
candles: Candle[];
has_more: boolean;
next_cursor?: string;
warning?: string;
}
const response = await fetch(
"https://api.moxiemetrx.com/v1/rates/historical?pair=USDTNGN&start=2026-01-01&end=2026-03-01&interval=1h&limit=100",
{ headers: { "X-API-Key": "your_key" } }
);
const data: HistoricalResponse = await response.json();
console.log(`Returned ${data.candles.length} candles, has_more=${data.has_more}`);
Response:
{
"pair": "USDTNGN",
"interval": "1h",
"has_more": true,
"next_cursor": "2026-01-05T04:00:00+00:00",
"candles": [
{
"timestamp": "2026-01-01T00:00:00Z",
"open": 1398.50,
"high": 1401.20,
"low": 1397.80,
"close": 1400.10,
"volume": 142580.0
},
{
"timestamp": "2026-01-01T01:00:00Z",
"open": 1400.10,
"high": 1402.00,
"low": 1399.50,
"close": 1401.30,
"volume": 98210.0
}
]
}
Fetching all pages
import requests
def fetch_all_candles(pair: str, start: str, end: str, interval: str = "1h") -> list:
params = {"pair": pair, "start": start, "end": end, "interval": interval, "limit": 500}
headers = {"X-API-Key": "your_key"}
all_candles = []
while True:
response = requests.get(
"https://api.moxiemetrx.com/v1/rates/historical",
params=params,
headers=headers,
)
response.raise_for_status()
data = response.json()
all_candles.extend(data["candles"])
if not data["has_more"]:
break
params["cursor"] = data["next_cursor"]
return all_candles
candles = fetch_all_candles("USDTNGN", "2026-01-01", "2026-03-01")
print(f"Total candles: {len(candles)}")
async function fetchAllCandles(pair, start, end, interval = "1h") {
const allCandles = [];
let cursor = null;
while (true) {
const params = new URLSearchParams({ pair, start, end, interval, limit: 500 });
if (cursor) params.set("cursor", cursor);
const response = await fetch(
`https://api.moxiemetrx.com/v1/rates/historical?${params}`,
{ headers: { "X-API-Key": "your_key" } }
);
const data = await response.json();
allCandles.push(...data.candles);
if (!data.has_more) break;
cursor = data.next_cursor;
}
return allCandles;
}
const candles = await fetchAllCandles("USDTNGN", "2026-01-01", "2026-03-01");
console.log(`Total candles: ${candles.length}`);
Intervals
| Interval | Description | Notes |
|---|---|---|
5m | 5-minute candles | Native resolution. No aggregation applied. |
1h | 1-hour candles | Default. Aggregated from 5-minute data. |
1d | Daily candles | Aggregated from 5-minute data. Day boundary is 00:00 UTC. |
Pagination
This endpoint uses cursor-based pagination. The cursor is an ISO 8601 timestamp representing the last candle returned on the current page. Passing it as cursor on the next request returns candles strictly after that point -- so pages never overlap or skip rows.
The cursor is opaque -- treat it as a string and do not parse or modify it. Its format may change.
Flow:
- Make the first request without
cursor. - If
has_moreistrue, passnext_cursorascursoron the next request (keep all other params identical). - Repeat until
has_moreisfalse.
Errors
| Status | Code | Cause |
|---|---|---|
400 | validation_error | Invalid interval, bad date format, end before start, start in the future, range > 5 years, limit out of range, invalid cursor |
400 | validation_error | limit exceeds your tier's page cap |
401 | unauthorized | Missing or invalid API key |
429 | rate_limit_exceeded | Per-minute or monthly quota exceeded |
The 5m interval returns raw data without aggregation. If an exchange was temporarily unavailable during a 5-minute window, that candle may be missing entirely. The response will include a warning field when gaps are detected.
Free tier accounts can only access the last 7 days of historical data. Builder, Professional, and Enterprise plans have access to the full history. See Pricing for details.