Foreign Exchange
Daily ECB euro reference rates and EUR-triangulated conversions.
Where the data comes from
Every value this category returns is attributable to one of these publishers, and every payload carries the source tag with it.
| Source | Publisher | What we hold | Licence |
|---|---|---|---|
| ecb | European Central Bank | Ten curated ECB key-interest-rate, €STR, and euro-area AAA central-government yield-curve spot-rate series | ECB information reuse terms (ecb-reuse) |
Required notices
- Reproduced ECB information must appear accurately and cite the ECB as source.
- Where ECB information is incorporated in documents that are sold, buyers must be informed that the information is available free of charge from the ECB website.
- The ECB does not charge for the €STR or license its use.
Full licence text, attribution strings, and every source on the surface are in Attribution.
How the rates work
The euro is always the pivot. A pair with EUR on one side is served from the published fixing directly, or as its inverse; any other pair is triangulated through the euro, flagged derived: true, and names the arithmetic it used in meta.derived_method. That flag is the whole story an agent needs about how much processing sits between the publisher and the number — check it before you quote a rate as published.
Dates resolve rather than fail. Ask for a weekend or a holiday and you get the newest prior fixing, with requested_date and rate_date both echoed in the payload so the substitution is visible instead of silent. Values are exact decimal strings, never floats.
Worked workflows
Convert one amount on one date
The single-answer path. Give it an amount, two currencies, and optionally a date:
fx_convert(amount="1000", from_currency="USD", to_currency="EUR", date="2026-08-07")The payload is scalar — one object, no list, and pagination is null:
{
"data": {
"amount": "1000",
"from_currency": "USD",
"to_currency": "EUR",
"requested_date": "2026-08-07",
"rate_date": "2026-08-07",
"rate": "0.914500",
"converted": "914.500000",
"derived": false,
"unit": "EUR per USD",
"currency": "EUR",
"as_of": "2026-08-07T16:00:00Z"
},
"meta": {
"source": "ecb",
"as_of": "2026-08-07T16:00:00Z",
"attribution": "...",
"derived_method": "conversion from ECB reference rate"
},
"pagination": null
}Values above are illustrative; the field names are the real ones. Omit date for the latest available fixing.
Read a fixing series
For history — a chart, a volatility calculation, a period average — ask for the series rather than looping conversions:
fx_get_rates(base="EUR", quote="USD", start="2026-08-01", end="2026-08-07", limit=100){
"data": {
"base": "EUR",
"quote": "USD",
"unit": "USD per EUR",
"currency": "USD",
"rates": [
{ "date": "2026-08-07", "value": "1.093400", "as_of": "2026-08-07T16:00:00Z", "derived": false }
]
},
"meta": { "source": "ecb", "as_of": "2026-08-07T16:00:00Z", "attribution": "...", "derived_method": null },
"pagination": { "limit": 100, "has_more": true, "next_cursor": "eyJ2IjoxLCJrIjpbLi4uXX0" }
}Rates come back newest-first. When has_more is true, continue with the cursor and every other argument unchanged:
fx_get_rates(base="EUR", quote="USD", start="2026-08-01", end="2026-08-07", limit=100, cursor="eyJ2IjoxLCJrIjpbLi4uXX0")Cross two non-euro currencies
Nothing special is required — ask for the pair and read the flag:
fx_get_rates(base="GBP", quote="JPY", limit=30)Every rate in that response carries derived: true, and meta.derived_method states the triangulation. Treat a derived cross as what it is: two reference fixings divided, not a quoted market cross.
Coverage and caveats
- These are reference rates, not prices. The ECB publishes them for information purposes only and strongly discourages using them for transaction purposes. They are not transaction or execution prices, and no tool here will turn them into one.
- Coverage is the euro reference set. A currency the ECB does not publish against the euro is a
bad_parameter, not an empty result. A date outside the published history comes back asout_of_coveragefromfx_convert. - A reversed date window or an unparseable cursor is
bad_parametertoo — the surface refuses ambiguous input rather than guessing at it. - Check freshness before you trust recency.
platform_get_freshness(limit=50)reports the last successful refresh and the freshest value timestamp for the FX dataset, so an agent can tell "the market did not move" from "our connector has not run".
Tools and endpoints
Each tool's full input schema, provenance, and bounds are on its own page; the REST endpoints mirror them one for one.
| Tool | What it does | Page size |
|---|---|---|
| fx_convert | Convert one amount with ECB reference rates and explicit date resolution. | scalar result |
| fx_get_rates | Get daily ECB euro reference rates or EUR-triangulated cross-rates. | default 100 · min 1 · max 500 |
Over HTTP: Foreign Exchange REST endpoints.