Documentation/Historical Exchange Rate API

Historical Exchange Rate API

Request daily reference history from 1999-01-04 or aligned market-rate intraday observations, then export JSON, CSV, or Parquet.

One historical date

Put the date and base currency in the path. The symbols filter is optional; without it, the response includes every supported quote currency.

bash · one historical snapshot
curl "https://api.exchangerate.dev/v1/2024-01-15/EUR?symbols=USD,GBP"

If the requested date is a weekend or market holiday, the endpoint carries forward the most recent published fix and sets is_forward_filled to true. It never invents a rate.

Pull a date range

The range endpoint needs symbols, start_date, and end_date. The base defaults to USD.

bash · daily EUR and GBP rates
curl "https://api.exchangerate.dev/v1/range?base=USD&symbols=EUR,GBP&start_date=2024-01-01&end_date=2024-06-30"
  • JSON returns up to 366 business-day rows at a time.
  • When has_more is true, pass next_cursor back as the next request's cursor.
  • A single request can span up to 1,830 days, roughly five years.
  • Range rows are published business-day observations; weekends and other non-publication dates are not inserted.
bash · follow the cursor
curl "https://api.exchangerate.dev/v1/range?base=USD&symbols=EUR,GBP&start_date=2021-01-01&end_date=2025-12-31&cursor=2022-06-01"

Pull intraday observations

For a recorded response and plan overview, start with the intraday exchange rate API guide.

Use /v1/timeseries for 1-minute through 4-hour market observations. Use its 1d interval when you want the same daily reference history served by the existing daily endpoints.

bash · aligned 15-minute cross
curl "https://api.exchangerate.dev/v1/timeseries?base=EUR&symbols=JPY&interval=15m&from=2026-09-14T12:00:00Z&to=2026-09-14T13:00:00Z"   -H "Authorization: Bearer YOUR_KEY"

Market collection began on 2026-09-14; this example uses a populated window from that day. The retention periods below describe how long collected rows are kept, not how far back every pair is already populated. The current open bucket can change.

  • 1m observations are retained for 30 days.
  • 5m, 15m, 1h, and 4h are retained without a scheduled expiry.
  • 1d remains the existing daily reference series.
  • Intraday gaps remain gaps; weekends and market closures do not create synthetic rows.
  • Derived crosses require real closing ticks on both USD legs within the same interval bucket and no more than five seconds apart. These are approximate rate observations, not simultaneous quotes or cross OHLC.
  • effective_at gives the older contributing source timestamp, preserving fractional seconds. Candle backfills have null observation times and cannot establish cross observations.
  • Supported windows with no observations return HTTP 200 with data: [], has_more: false and next_cursor: null. An unknown interval returns HTTP 400 unsupported_interval.
  • Coverage depends on the pair and interval. Requests containing unsupported pairs are rejected in full with unsupported_pair_interval and a rejected pair list. See the pair and interval coverage table.

For ongoing live updates after a historical query, see the WebSocket integration guide. WebSocket coverage is narrower than the daily reference catalog and requires an API key.

Download CSV or Parquet

Add format=csv or format=parquet. Exports return the full requested window as one file, so they do not use the JSON cursor.

bash · save a CSV
curl -L "https://api.exchangerate.dev/v1/range?base=USD&symbols=EUR,GBP&start_date=2024-01-01&end_date=2024-12-31&format=csv"   --output usd-rates-2024.csv

Weekends and missing observations

A one-date request for a weekend or market holiday returns the most recently published fix with is_forward_filled set to true. A range does not manufacture rows for those dates; it contains published business-day observations only. Treat a forward-filled value as the prior observation, not a new market event.

Provenance and derived rates

Daily range rows include source, is_forward_filled, and derived_symbols. Time-series rows include timestamp, source_type, market_session, and derived_symbols. Store those fields with the rates.

Avoid look-ahead bias in backtests

Backtests need a time split
A clean API response does not prevent look-ahead bias. Split training and test data by date, and do not let a future value leak into an earlier feature. The backfill guide shows the safe pattern.

For a worked Python example, read Historical FX time series in Python.

Limits and pricing

The date and range endpoints use the same request quota as the rest of the API. A CSV or Parquet range export counts as one call, and all plans include the range endpoint and pair-specific daily reference history, beginning in 1999 where observations exist. See pricing for current quotas and plan limits.