What ECB-based FX APIs miss between fixes
The ECB publishes its reference fix once per business day around 16:00 CET. Any API sourced only from that fix is stale the moment the market moves after 16:00 — and stays stale until the next day's fix. Here's what that means for a "latest" endpoint, and how intraday-sourced data differs.
Call GET /v1/latest/USD during a trading day and you get back source: "live" and market_session: "open", a rate that reflects where the market is right now — not where it was at 16:00 CET yesterday. An API sourced only from the ECB reference fix returns the prior fix with no indication that hours of intraday movement have happened since. The difference can be several tenths of a percent, compounded by news events that land after the fix.
source: "live" and market_session so you know exactly what you have.data_updated_at field shows when the underlying rate was last written. It is the fastest way to confirm freshness without parsing source.How the ECB fix works
The European Central Bank publishes its EXR reference rates once per business day, typically around 16:00 Central European Time. The series goes back to 1999 and is widely used because it is free, official, and consistent. These properties make it a natural upstream source for FX APIs.
The catch: the fix is a single snapshot per business day. Between the 16:00 CET publication and the next day's fix, the market keeps moving — through the afternoon and overnight — and across the weekend the fix sits unchanged from Friday until Monday. An API that reads only from this series has nothing new to show until the next fix, so it returns the last available value regardless of what has happened since.
market_session, no source, and no data_updated_at field. A caller reading "latest" at 09:00 the next morning has no way to know the number is almost 17 hours old.The staleness timeline: frozen vs. moving
The table below shows what each type of API returns at different points around a business day. The times are illustrative of the general pattern:
The gap is largest first thing in the morning: between the previous day's 16:00 CET fix and the next one, an ECB-only API can be 16–24 hours stale during a full trading day, before accounting for any weekend at all.
Reading a live call with freshness fields
The response from a live-sourced endpoint carries three fields that tell you exactly what you have: source, market_session, and data_updated_at. Here is a call and what to inspect:
If source is "live", the rate is updated intraday (~60s), not pinned to the last daily fix. data_updated_at tells you precisely when. A response with no market_session field and no data_updated_at is a strong indicator of an ECB-only API returning a stale value.
Why it matters for anything reading "latest"
If your code calls /latest and acts on the result, the staleness of an ECB-only response is invisible. You get a 200 status, valid JSON, and a plausible-looking number. There is no error to catch.
- A dashboard that refreshes every 15 minutes will show the same EUR/USD all day until the next ECB fix, even as the real rate moves.
- A cost-reporting job that runs at 08:00 will convert using yesterday's 16:00 fix, missing any overnight move.
- A pricing engine that reads FX rates before invoicing international customers will see the wrong number for most of each trading day.
- Any application that logs
data_updated_atfor auditing will find the ECB-only response gives it nothing useful to log between fixes.
A 200 response with yesterday's number is harder to catch than an error. The data looks right — it's just not current.
Checking staleness in code
The most direct guard is to check data_updated_at against your own clock. If the gap is larger than you expect — more than a few minutes for a live source, or more than 24 hours for a reference fix — something is worth flagging:
notice field on every response states this. Do not use these rates to settle trades.Looking up a past weekend date
For historical data, the endpoint GET /v1/{date}/{base} returns a single day. Weekend and holiday dates come back with is_forward_filled: true for reference-rate tiers, meaning no fix was published that day and the prior value was carried forward. Live-tier weekend rows carry the last intraday consensus from the trading week (interbank FX is closed), labeled market_session: weekend:
is_forward_filled: true means the value here is the most recent prior publication; nothing was published on the date you asked for. This lets backtests and reporting pipelines treat weekend dates correctly rather than treating a carried-forward value as a fresh observation.