Guide/ECB rates

ECB reference rates, explained

The European Central Bank publishes one official FX reference rate per business day. Here is what that means, how it differs from live spot data, and how to read it from the API.

ERexchangerate.dev·Jun 19, 2026·6 min read

When you call /v1/latest/USD and get back source: ecb_daily, you are reading the European Central Bank's euro foreign-exchange reference rate: published once per business day around 16:00 CET, intended for reference and information, not for transactions. This is the most authoritative daily FX figure for EUR pairs, but it is a single snapshot — the market keeps moving after 16:00 CET, and the fix does not update until the next business day.

Key points
The ECB publishes its euro reference rates once per business day, around 16:00 CET.
The API exposes this as source: ecb_daily, distinct from live (aggregated spot) and fred_daily (Federal Reserve daily series).
On weekends and public holidays, no new ECB fix is published. Historical responses for those dates carry is_forward_filled: true.
All rates are indicative, for reference and analytics only, not for settlement or dealing.
History goes back to 1999, the start of the ECB's EXR series.

What the ECB reference rate is

Every business day, the European Central Bank publishes a set of euro foreign-exchange reference rates. These are computed around 16:00 CET through a concertation process with central banks in and outside the European System of Central Banks. The rates represent a consensus mid-market figure at that moment and are intended for information and reference use only, as the ECB's own documentation makes clear.

They are widely used in financial contracts, accounting, and regulatory reporting across the EU because they come from a public institution and are published on a fixed, transparent schedule. When you see source: ecb_daily in an API response, that is exactly what you are reading.

Indicative, not for settlement
ECB reference rates are not dealing rates. They reflect a market consensus at a point in time. Every /v1/latest response that carries an ECB-sourced rate includes a notice field confirming this: "Indicative rates, not for settlement. Source: incl. ECB statistics."

Three source classes in the API

Every response from the API carries a source field that tells you which data class the rate comes from. There are three:

source valueecb_dailylive
ProviderEuropean Central BankAggregated spot consensus
FrequencyOnce per business dayIntraday (~60s), trading week
Published~16:00 CET on weekdaysThrough the trading week
Between fixesPrior fix carried; market movement not capturedContinues updating through the trading week
Weekend / holidayNo new fix; prior value carriedInterbank closed; last consensus carried
History availableBack to 1999Recent window
Suited forAccounting, reporting, audit trailReal-time display, pricing

The third class, fred_daily, comes from the US Federal Reserve's daily series and is most relevant for USD pairs where the Federal Reserve publishes its own reference figures. It follows a similar cadence to ecb_daily: once per business day, with gaps on US public holidays.

Reading an ECB-sourced response

Request the latest rates for any base currency and check source to know what you are looking at:

bash · latest rates, EUR basecopy
curl -s https://api.exchangerate.dev/v1/latest/EUR \
  -H "Authorization: Bearer exr_live_..."
json · response excerptcopy
{
  "result": "success",
  "base": "EUR",
  "source": "ecb_daily",
  "market_session": "open",
  "timestamp": "2026-06-19T14:05:33Z",
  "data_updated_at": "2026-06-19T14:00:00Z",
  "rates": {
    "USD": 1.14235,
    "GBP": 0.86781,
    "JPY": 184.320
  },
  "notice": "Indicative rates, not for settlement. Source: incl. ECB statistics."
}

Two timestamp fields appear on every response. data_updated_at is when the underlying rate was last written to the data store. For ecb_daily this will be around 16:00 CET on the most recent business day. timestamp is when the API built the response. If you are caching responses, data_updated_at is the field to track for staleness.

Between fixes, weekends, and forward-fill

The ECB fix is a once-a-day snapshot. Between the ~16:00 CET publication and the following business day's fix, ecb_daily data does not update — any intraday or overnight market movement is not captured. The ECB also does not publish on weekends or public holidays, so a Saturday or Sunday request returns Friday's fix. The API handles non-publication dates with the is_forward_filled field:

bash · historical date on a weekendcopy
curl -s https://api.exchangerate.dev/v1/2026-06-13/USD \
  -H "Authorization: Bearer exr_live_..."
json · forward-filled responsecopy
{
  "result": "success",
  "base": "USD",
  "source": "fred_daily",
  "market_session": "weekend",
  "is_forward_filled": true,
  "rates": {
    "EUR": 0.87531,
    "GBP": 0.75945,
    "JPY": 161.412
  }
}

When is_forward_filled is true, the rate in the response is the last published value carried forward from the prior business day. It is not a new observation. For many use cases (displaying a rate on a weekend, populating a chart) this is fine. For accounting or audit trails where you need to record whether a fix actually existed on a given date, you should check this flag.

Live rates update intraday, between fixes
The live source updates approximately every 60 seconds through the trading week — including between the ECB's daily fixes and overnight. If you need a rate that reflects where the market is right now rather than where it was at 16:00 CET yesterday, check whether the response carries source: live.

Checking source in Python

A common pattern is to read the rate and branch on source to decide how to present it:

python · source-aware rate fetchcopy
import requests

API = "https://api.exchangerate.dev/v1"
KEY = "exr_live_..."

resp = requests.get(
    f"{API}/latest/USD",
    headers={"Authorization": f"Bearer {KEY}"},
    timeout=10,
)
resp.raise_for_status()
data = resp.json()

rate = data["rates"]["EUR"]        # 0.87531
source = data["source"]            # ecb_daily
session = data["market_session"]   # open

if source == "ecb_daily":
    print(f"ECB reference rate as of last business day: {rate}")
elif source == "live":
    print(f"Indicative spot rate ({session}): {rate}")
else:
    print(f"Rate ({source}): {rate}")

History back to 1999

The ECB started its EXR series when the euro was introduced. The API exposes this full history through the dated endpoint /v1/{date}/{base} and the range endpoint /v1/range. Both return is_forward_filled where applicable. You can pull a time series for a specific currency pair across any window:

bash · weekly EUR/USD seriescopy
curl -s "https://api.exchangerate.dev/v1/range?base=EUR&symbols=USD&start_date=2026-06-10&end_date=2026-06-16" \
  -H "Authorization: Bearer exr_live_..."

Note the parameter names: start_date and end_date (snake_case), and symbols as a comma-separated string. The range returns one row per published business day, each with its own source and is_forward_filled; weekend dates are not included as rows.

The ECB fix is one observation per business day. Live spot, forward-fill, and triangulated crosses are all context around that anchor.

ER
exchangerate.dev
FX data guides for developers building with indicative rates.

Keep reading

ReferenceReading source and market_sessionRead BlogWhat ECB-based FX APIs miss between fixesRead GuideIndicative vs executable FX ratesRead
More ComparisonsFixer vs exchangerate.devOpen Exchange Rates vs exchangerate.devCurrencylayer vs exchangerate.devCurrencylayer vs ExchangeRate-API
LearnReading source and market_session in your pipelineIndicative vs executable FX rates: what a rates API actually gives you
Live RatesEUR/USDGBP/USDUSD/JPY