FX
ECB reference rates, conversion with EUR triangulation, official VAT exchange rates and IAS 21 period rates.
| Operation | Summary |
|---|---|
GET /v1/fx/convert |
Convert an amount at the ECB reference rate |
GET /v1/fx/history |
List the daily ECB cross rates of a currency pair |
GET /v1/fx/period-rates |
Get the IAS 21 average or closing rate of a period |
GET /v1/fx/rates |
List ECB reference rates |
GET /v1/fx/tax-rates |
Get the official VAT exchange rate |
GET /v1/fx/tax-rates/convert |
Convert an amount at the official VAT exchange rate |
GET /v1/fx/convert
Convert an amount at the ECB reference rate
Convert an amount between two currencies at the ECB euro reference rate.
Currencies other than EUR are triangulated through EUR (data.path shows the route).
rate is the cross rate rounded to 10 decimals and converted the amount rounded
half-even to the minor unit of the target currency. fixing_date is the ECB day used.
For VAT or IAS 21 purposes use /tax-rates or /period-rates instead. 404 if there is
no fixing within 7 days before the date or a currency is not published by the ECB.
| Authentication | an API key, where the server requires one |
| Operation id | convert_v1_fx_convert_get |
Parameters
| In | Name | Type | Required | Description |
|---|---|---|---|---|
| query | from |
string | yes | ISO 4217 code of the currency to convert from, case-insensitive. (min length 3; max length 3) |
| query | to |
string | yes | ISO 4217 code of the currency to convert to, case-insensitive. (min length 3; max length 3) |
| query | amount |
decimal string | Amount in the from currency, as a decimal number. Default 1. (default "1") |
|
| query | date |
string (date) or null | Rate date (ISO 8601, e.g. 2026-09-25). The latest ECB fixing on or before it (up to 7 days back) is used. Defaults to today. | |
| query | dataset_version |
string or null | Pin the response to an archived dataset version (git SHA). Defaults to the current version. Also accepted as the X-Dataset-Version header. The version that answered is in meta.dataset_version; an archived version that does not exist gives 404. |
Example request
curl "$DATAVNEXT_URL/v1/fx/convert?from=USD&to=SEK" \
-H "X-API-Key: $DATAVNEXT_KEY"
Responses
| Status | Meaning | Body |
|---|---|---|
| 200 | OK | Envelope_Conversion_ |
| 401 | Missing or invalid API key. | Error |
| 404 | Nothing found for the identifier, or the pinned dataset_version is not archived. |
Error |
| 422 | The request is invalid: {"detail": "…"} for a rule the service checks, or FastAPI's {"detail": [{"loc", "msg", "type"}]} for a malformed parameter or body. |
HTTPValidationError |
Example response (shape)
{
"data": {
"source": "ecb",
"requested_date": "2026-09-25",
"fixing_date": "2026-09-25",
"from_currency": "USD",
"to_currency": "SEK",
"amount": "1000",
"rate": "9.9009032711",
"converted": "9900.90",
"path": [
"USD",
"EUR",
"SEK"
]
},
"meta": {
"dataset_version": "3f2a9c1b7d4e",
"as_of": "2026-09-25",
"sources": [
{
"authority": "European Central Bank",
"url": "https://data.ecb.europa.eu/data/datasets/EXR",
"reference": "Euro reference rates",
"verified_at": "2026-10-01",
"kind": "official"
}
],
"notes": [
"ECB euro reference rates are for information purposes; the most recent fixing on or before the requested date is used."
]
}
}
GET /v1/fx/history
List the daily ECB cross rates of a currency pair
The ECB cross rate of a pair on every fixing day of a range, oldest first.
Each point in data.points is the rate of one ECB fixing day, triangulated through EUR
and rounded to 10 decimals half-even, so it equals the rate of /convert for that
day. Weekends and holidays have no point (the ECB publishes none); a day on which the
ECB did not publish both currencies is left out too. The mean of the points is the IAS 21
average that /period-rates returns for a calendar period. 422 if base and quote are
equal, the range is reversed or longer than the limit; 404 if the range holds no fixing of
both currencies.
| Authentication | an API key, where the server requires one |
| Operation id | history_v1_fx_history_get |
Parameters
| In | Name | Type | Required | Description |
|---|---|---|---|---|
| query | base |
string | yes | ISO 4217 code of the base currency (the unit being priced), case-insensitive. (min length 3; max length 3) |
| query | quote |
string | yes | ISO 4217 code of the quote currency, case-insensitive; each rate is units of quote per one unit of base. Must differ from base. (min length 3; max length 3) |
| query | start |
string (date) | yes | First day of the range (ISO 8601, e.g. 2026-08-01). |
| query | end |
string (date) | yes | Last day of the range (ISO 8601), on or after start; the range covers at most 1830 days. |
| query | dataset_version |
string or null | Pin the response to an archived dataset version (git SHA). Defaults to the current version. Also accepted as the X-Dataset-Version header. The version that answered is in meta.dataset_version; an archived version that does not exist gives 404. |
Example request
curl "$DATAVNEXT_URL/v1/fx/history?base=USD"e=CHF&start=2026-08-01&end=2026-08-31" \
-H "X-API-Key: $DATAVNEXT_KEY"
Responses
| Status | Meaning | Body |
|---|---|---|
| 200 | OK | Envelope_FxHistory_ |
| 401 | Missing or invalid API key. | Error |
| 404 | Nothing found for the identifier, or the pinned dataset_version is not archived. |
Error |
| 422 | The request is invalid: {"detail": "…"} for a rule the service checks, or FastAPI's {"detail": [{"loc", "msg", "type"}]} for a malformed parameter or body. |
HTTPValidationError |
Example response (shape)
{
"data": {
"source": "ecb",
"base": "USD",
"quote": "CHF",
"start": "2026-09-21",
"end": "2026-09-25",
"points": [
{
"date": "2026-09-24",
"rate": "0.8231234567"
},
{
"date": "2026-09-25",
"rate": "0.8282908356"
}
]
},
"meta": {
"dataset_version": "3f2a9c1b7d4e",
"as_of": "2026-09-25",
"sources": [
{
"authority": "European Central Bank",
"url": "https://data.ecb.europa.eu/data/datasets/EXR",
"reference": "Euro reference rates",
"verified_at": "2026-10-01",
"kind": "official"
}
],
"notes": [
"ECB euro reference rates are for information purposes; the most recent fixing on or before the requested date is used."
]
}
}
GET /v1/fx/period-rates
Get the IAS 21 average or closing rate of a period
IAS 21 average or closing rate for a calendar period, derived from ECB fixings.
data.rate is units of quote per one unit of base, rounded to 10 decimals;
fixings is the number of daily ECB fixings used, from first_fixing to last_fixing.
meta.notes explains the method. 422 if the period is malformed or has not ended, or
base and quote are equal; 404 if the stored ECB fixings for the period are incomplete or
a currency is not published.
| Authentication | an API key, where the server requires one |
| Operation id | period_rates_v1_fx_period_rates_get |
Parameters
| In | Name | Type | Required | Description |
|---|---|---|---|---|
| query | base |
string | yes | ISO 4217 code of the base currency (the unit being priced). (min length 3; max length 3) |
| query | quote |
string | yes | ISO 4217 code of the quote currency; rate is units of quote per one unit of base. Must differ from base. (min length 3; max length 3) |
| query | period |
string | yes | Calendar period: YYYY-MM (month), YYYY-Qn (quarter) or YYYY (year). It must have ended before today. |
| query | kind |
"average" | "closing" |
'average': mean of the daily cross rates over the period (income and expenses, IAS 21.40); 'closing': the last fixing on or before the period end (monetary items, IAS 21.23). Default 'average'. (default "average") |
|
| query | dataset_version |
string or null | Pin the response to an archived dataset version (git SHA). Defaults to the current version. Also accepted as the X-Dataset-Version header. The version that answered is in meta.dataset_version; an archived version that does not exist gives 404. |
Example request
curl "$DATAVNEXT_URL/v1/fx/period-rates?base=CHF"e=EUR&period=2026-08" \
-H "X-API-Key: $DATAVNEXT_KEY"
Responses
| Status | Meaning | Body |
|---|---|---|
| 200 | OK | Envelope_PeriodRate_ |
| 401 | Missing or invalid API key. | Error |
| 404 | Nothing found for the identifier, or the pinned dataset_version is not archived. |
Error |
| 422 | The request is invalid: {"detail": "…"} for a rule the service checks, or FastAPI's {"detail": [{"loc", "msg", "type"}]} for a malformed parameter or body. |
HTTPValidationError |
Example response (shape)
{
"data": {
"source": "ecb",
"base": "CHF",
"quote": "EUR",
"period": "2026-08",
"period_start": "2026-08-01",
"period_end": "2026-08-31",
"kind": "average",
"rate": "1.0681709886",
"fixings": 21,
"first_fixing": "2026-08-03",
"last_fixing": "2026-08-31"
},
"meta": {
"dataset_version": "3f2a9c1b7d4e",
"sources": [
{
"authority": "European Central Bank",
"url": "https://data.ecb.europa.eu/data/datasets/EXR",
"reference": "Euro reference rates",
"verified_at": "2026-10-01",
"kind": "official"
},
{
"authority": "IFRS Foundation",
"url": "https://www.ifrs.org/issued-standards/list-of-standards/ias-21-the-effects-of-changes-in-foreign-exchange-rates/",
"reference": "IAS 21.9, 21.21, 21.23, 21.39",
"verified_at": "2026-09-29",
"kind": "official"
}
],
"notes": [
"Average: the arithmetic mean of the daily cross rates on every ECB fixing day in the period (each day triangulated through EUR, then averaged), rounded to 10 decimals."
]
}
}
GET /v1/fx/rates
List ECB reference rates
ECB euro reference rates, rebased to any published currency.
data.rates maps each currency to the units of that currency per one unit of base,
as decimal strings with 10 decimals. fixing_date is the ECB publication day actually
used (weekends and holidays fall back to the previous fixing); requested_date is what
you asked for and meta.as_of repeats it. 404 if there is no fixing within 7 days
before the date or the base currency is not published by the ECB.
| Authentication | an API key, where the server requires one |
| Operation id | rates_v1_fx_rates_get |
Parameters
| In | Name | Type | Required | Description |
|---|---|---|---|---|
| query | base |
string | ISO 4217 code of the base currency, case-insensitive. The ECB publishes its rates against EUR; any other base is derived from them. Default EUR. (default "EUR") |
|
| query | date |
string (date) or null | Rate date (ISO 8601, e.g. 2026-09-25). The latest ECB fixing on or before it (up to 7 days back) is used. Defaults to today. | |
| query | dataset_version |
string or null | Pin the response to an archived dataset version (git SHA). Defaults to the current version. Also accepted as the X-Dataset-Version header. The version that answered is in meta.dataset_version; an archived version that does not exist gives 404. |
Example request
curl "$DATAVNEXT_URL/v1/fx/rates" \
-H "X-API-Key: $DATAVNEXT_KEY"
Responses
| Status | Meaning | Body |
|---|---|---|
| 200 | OK | Envelope_FxRates_ |
| 401 | Missing or invalid API key. | Error |
| 404 | Nothing found for the identifier, or the pinned dataset_version is not archived. |
Error |
| 422 | The request is invalid: {"detail": "…"} for a rule the service checks, or FastAPI's {"detail": [{"loc", "msg", "type"}]} for a malformed parameter or body. |
HTTPValidationError |
Example response (shape)
{
"data": {
"source": "ecb",
"base": "EUR",
"requested_date": "2026-09-25",
"fixing_date": "2026-09-25",
"rates": {
"CHF": "0.9445000000",
"GBP": "0.8604500000",
"SEK": "11.2900000000"
}
},
"meta": {
"dataset_version": "3f2a9c1b7d4e",
"as_of": "2026-09-25",
"sources": [
{
"authority": "European Central Bank",
"url": "https://data.ecb.europa.eu/data/datasets/EXR",
"reference": "Euro reference rates",
"verified_at": "2026-10-01",
"kind": "official"
}
],
"notes": [
"ECB euro reference rates are for information purposes; the most recent fixing on or before the requested date is used."
]
}
}
GET /v1/fx/tax-rates
Get the official VAT exchange rate
The official VAT exchange rate for a foreign currency on a date.
data.rate is the published rate and quoted_as says how it is quoted (CHF per 1 USD
for Switzerland, USD per 1 EUR for Germany); tax_currency_per_unit is always the tax
currency per one unit of foreign currency. fixing_date is the publication date used
and period the month it covers. meta.notes states which rate applies and when it is
published. 422 for a jurisdiction or kind with no series, or for the tax currency
itself; 404 when the rate is not published yet or does not list the currency.
| Authentication | an API key, where the server requires one |
| Operation id | tax_rates_v1_fx_tax_rates_get |
Parameters
| In | Name | Type | Required | Description |
|---|---|---|---|---|
| query | jurisdiction |
string | yes | Country whose VAT exchange rate applies: 'CH' (ESTV, published by BAZG) or 'DE' (BMF, UStG §16 Abs. 6). Case-insensitive. |
| query | currency |
string | yes | ISO 4217 code of the foreign currency, case-insensitive. It must differ from the jurisdiction's tax currency (CHF or EUR). (min length 3; max length 3) |
| query | date |
string (date) or null | Tax point: the date of the supply or invoice (ISO 8601). It selects the month (monthly) or the latest published day (daily). Defaults to today. | |
| query | kind |
"daily" | "monthly" |
'monthly': the monthly average rate; 'daily': the daily rate (published for Switzerland). Default 'monthly'. (default "monthly") |
|
| query | dataset_version |
string or null | Pin the response to an archived dataset version (git SHA). Defaults to the current version. Also accepted as the X-Dataset-Version header. The version that answered is in meta.dataset_version; an archived version that does not exist gives 404. |
Example request
curl "$DATAVNEXT_URL/v1/fx/tax-rates?jurisdiction=CH¤cy=USD" \
-H "X-API-Key: $DATAVNEXT_KEY"
Responses
| Status | Meaning | Body |
|---|---|---|
| 200 | OK | Envelope_TaxFxRate_ |
| 401 | Missing or invalid API key. | Error |
| 404 | Nothing found for the identifier, or the pinned dataset_version is not archived. |
Error |
| 422 | The request is invalid: {"detail": "…"} for a rule the service checks, or FastAPI's {"detail": [{"loc", "msg", "type"}]} for a malformed parameter or body. |
HTTPValidationError |
Example response (shape)
{
"data": {
"series": "ch-vat-monthly",
"jurisdiction": "CH",
"kind": "monthly",
"requested_date": "2026-10-15",
"fixing_date": "2026-10-01",
"period": "2026-10",
"currency": "USD",
"tax_currency": "CHF",
"rate": "0.8218",
"quotation": "direct",
"quoted_as": "CHF per 1 USD",
"tax_currency_per_unit": "0.8218"
},
"meta": {
"dataset_version": "3f2a9c1b7d4e",
"as_of": "2026-10-15",
"sources": [
{
"authority": "Eidgenössische Steuerverwaltung (ESTV)",
"url": "https://www.estv.admin.ch/de/mwst-fremdwaehrungskurse",
"reference": "Fremdwährungskurse MWST",
"verified_at": "2026-10-01",
"kind": "official"
}
],
"notes": [
"Published by BAZG on the 25th of the previous month (or the next working day)."
]
}
}
GET /v1/fx/tax-rates/convert
Convert an amount at the official VAT exchange rate
Convert a foreign-currency amount into the tax currency at the official VAT rate, rounded half up to the tax currency's minor unit.
The response has the rate fields of /tax-rates plus amount and converted (decimal
strings, converted in the tax currency). Errors as for /tax-rates: 422 for a
jurisdiction or kind without a series or for the tax currency itself, 404 when the rate
is not published yet or does not list the currency.
| Authentication | an API key, where the server requires one |
| Operation id | tax_convert_v1_fx_tax_rates_convert_get |
Parameters
| In | Name | Type | Required | Description |
|---|---|---|---|---|
| query | jurisdiction |
string | yes | Country whose VAT exchange rate applies: 'CH' (ESTV, published by BAZG) or 'DE' (BMF, UStG §16 Abs. 6). Case-insensitive. |
| query | currency |
string | yes | ISO 4217 code of the foreign currency, case-insensitive. It must differ from the jurisdiction's tax currency (CHF or EUR). (min length 3; max length 3) |
| query | amount |
decimal string | Amount in the foreign currency, as a decimal number. Default 1. (default "1") |
|
| query | date |
string (date) or null | Tax point: the date of the supply or invoice (ISO 8601). It selects the month (monthly) or the latest published day (daily). Defaults to today. | |
| query | kind |
"daily" | "monthly" |
'monthly': the monthly average rate; 'daily': the daily rate (published for Switzerland). Default 'monthly'. (default "monthly") |
|
| query | dataset_version |
string or null | Pin the response to an archived dataset version (git SHA). Defaults to the current version. Also accepted as the X-Dataset-Version header. The version that answered is in meta.dataset_version; an archived version that does not exist gives 404. |
Example request
curl "$DATAVNEXT_URL/v1/fx/tax-rates/convert?jurisdiction=CH¤cy=USD" \
-H "X-API-Key: $DATAVNEXT_KEY"
Responses
| Status | Meaning | Body |
|---|---|---|
| 200 | OK | Envelope_TaxFxConversion_ |
| 401 | Missing or invalid API key. | Error |
| 404 | Nothing found for the identifier, or the pinned dataset_version is not archived. |
Error |
| 422 | The request is invalid: {"detail": "…"} for a rule the service checks, or FastAPI's {"detail": [{"loc", "msg", "type"}]} for a malformed parameter or body. |
HTTPValidationError |
Example response (shape)
{
"data": {
"series": "de-vat-monthly",
"jurisdiction": "DE",
"kind": "monthly",
"requested_date": "2026-08-20",
"fixing_date": "2026-08-01",
"period": "2026-08",
"currency": "USD",
"tax_currency": "EUR",
"rate": "1.1593",
"quotation": "indirect",
"quoted_as": "USD per 1 EUR",
"tax_currency_per_unit": "0.8625894937",
"amount": "1000",
"converted": "862.59"
},
"meta": {
"dataset_version": "3f2a9c1b7d4e",
"as_of": "2026-08-20",
"sources": [
{
"authority": "Bundesamt für Justiz (gesetze-im-internet.de)",
"url": "https://www.gesetze-im-internet.de/ustg_1980/__16.html",
"reference": "UStG §16 Abs. 6",
"verified_at": "2026-10-01",
"kind": "official"
}
],
"notes": [
"The average for the month in which the supply is made (or a prepayment is received; under cash accounting, the month the consideration is received). Rates are units of foreign currency per 1 EUR."
]
}
}
Schemas
Conversion
| Field | Type | Required | Description |
|---|---|---|---|
source |
string | yes | |
requested_date |
string (date) | yes | |
fixing_date |
string (date) | yes | |
from_currency |
string | yes | |
to_currency |
string | yes | |
amount |
string | yes | (pattern ^(?!^[-+.]*$)[+-]?0*\d*\.?\d*$) |
rate |
string | yes | (pattern ^(?!^[-+.]*$)[+-]?0*\d*\.?\d*$) |
converted |
string | yes | (pattern ^(?!^[-+.]*$)[+-]?0*\d*\.?\d*$) |
path |
array of string | yes |
Envelope_Conversion_
| Field | Type | Required | Description |
|---|---|---|---|
data |
Conversion |
yes | |
meta |
Meta |
yes |
Envelope_FxHistory_
| Field | Type | Required | Description |
|---|---|---|---|
data |
FxHistory |
yes | |
meta |
Meta |
yes |
Envelope_FxRates_
| Field | Type | Required | Description |
|---|---|---|---|
data |
FxRates |
yes | |
meta |
Meta |
yes |
Envelope_PeriodRate_
| Field | Type | Required | Description |
|---|---|---|---|
data |
PeriodRate |
yes | |
meta |
Meta |
yes |
Envelope_TaxFxConversion_
| Field | Type | Required | Description |
|---|---|---|---|
data |
TaxFxConversion |
yes | |
meta |
Meta |
yes |
Envelope_TaxFxRate_
| Field | Type | Required | Description |
|---|---|---|---|
data |
TaxFxRate |
yes | |
meta |
Meta |
yes |
FxHistory
| Field | Type | Required | Description |
|---|---|---|---|
source |
string | yes | |
base |
string | yes | |
quote |
string | yes | |
start |
string (date) | yes | |
end |
string (date) | yes | |
points |
array of FxPoint |
yes |
FxPoint
| Field | Type | Required | Description |
|---|---|---|---|
date |
string (date) | yes | |
rate |
string | yes | (pattern ^(?!^[-+.]*$)[+-]?0*\d*\.?\d*$) |
FxRates
| Field | Type | Required | Description |
|---|---|---|---|
source |
string | yes | |
base |
string | yes | |
requested_date |
string (date) | yes | |
fixing_date |
string (date) | yes | |
rates |
map of string | yes |
PeriodRate
| Field | Type | Required | Description |
|---|---|---|---|
source |
string | yes | |
base |
string | yes | |
quote |
string | yes | |
period |
string | yes | |
period_start |
string (date) | yes | |
period_end |
string (date) | yes | |
kind |
"average" | "closing" |
yes | |
rate |
string | yes | (pattern ^(?!^[-+.]*$)[+-]?0*\d*\.?\d*$) |
fixings |
integer | yes | |
first_fixing |
string (date) | yes | |
last_fixing |
string (date) | yes |
TaxFxConversion
| Field | Type | Required | Description |
|---|---|---|---|
series |
string | yes | |
jurisdiction |
string | yes | |
kind |
"daily" | "monthly" |
yes | |
requested_date |
string (date) | yes | |
fixing_date |
string (date) | yes | |
period |
string or null | ||
currency |
string | yes | |
tax_currency |
string | yes | |
rate |
string | yes | (pattern ^(?!^[-+.]*$)[+-]?0*\d*\.?\d*$) |
quotation |
"direct" | "indirect" |
yes | |
quoted_as |
string | yes | |
tax_currency_per_unit |
string | yes | (pattern ^(?!^[-+.]*$)[+-]?0*\d*\.?\d*$) |
amount |
string | yes | (pattern ^(?!^[-+.]*$)[+-]?0*\d*\.?\d*$) |
converted |
string | yes | (pattern ^(?!^[-+.]*$)[+-]?0*\d*\.?\d*$) |
TaxFxRate
| Field | Type | Required | Description |
|---|---|---|---|
series |
string | yes | |
jurisdiction |
string | yes | |
kind |
"daily" | "monthly" |
yes | |
requested_date |
string (date) | yes | |
fixing_date |
string (date) | yes | |
period |
string or null | ||
currency |
string | yes | |
tax_currency |
string | yes | |
rate |
string | yes | (pattern ^(?!^[-+.]*$)[+-]?0*\d*\.?\d*$) |
quotation |
"direct" | "indirect" |
yes | |
quoted_as |
string | yes | |
tax_currency_per_unit |
string | yes | (pattern ^(?!^[-+.]*$)[+-]?0*\d*\.?\d*$) |