Historical FX rates and time series in one call
Pull a multi-currency FX series across a date range with a single request to /v1/range. Daily history back to 1999, returned as a data array of daily rows ready to load into pandas.
One call to /v1/range returns a data array with one row per published day in your window, for as many currencies as you pass in symbols. No looping required. Each row carries its own date, rates, source, and is_forward_filled.
GET /v1/range returns a data array of daily rows in one call, no looping over single-day endpoints.start_date and end_date (snake_case). symbols is a comma-separated string.source and is_forward_filled. Reference sources publish on business days, so weekend dates are not returned as rows.The range endpoint
GET /v1/range takes four query parameters: base, symbols, start_date, and end_date. All four are required. symbols is a comma-separated list of currency codes. The response has a data key: an array of daily rows, plus has_more and next_cursor for paging through long ranges.
Each element of data is a self-contained daily row with its own date, rates, source, and is_forward_filled:
Note that the Saturday (2026-06-13) is absent. Reference sources publish on business days only, so the range returns the published days in the window rather than one row per calendar day.
Python example
The same request in Python with requests. Iterate the data array, reading each row by key:
The is_forward_filled flag
Every row carries is_forward_filled. For a normal business day it is false: that day had a published fix. It is true only when a row repeats the prior value because no fix was published on a day the range still includes, such as a recognised public holiday. Weekends are simply not present as rows.
data. To get the carried-forward value for one specific weekend or holiday date, request it directly with /v1/{date}/{base}, which returns the prior value and sets is_forward_filled: true./v1/range vs looping /v1/{date}/{base}
For a single day, /v1/{date}/{base} is the right call: it is simple, cacheable, and carries is_forward_filled at the response root. For anything spanning more than one date, /v1/range returns the whole series in one round trip.
History back to 1999
The ECB EXR series and FRED daily data go back to 1999 for many pairs. You can pass any start_date in that range. The source field on each row tells you which dataset powered it: ecb_daily, fred_daily, or live.
Loading into pandas
The data array loads into a DataFrame with pd.json_normalize, which flattens the nested rates object into rates.EUR, rates.GBP, and so on: