Docs /

API reference

The complete REST contract: authentication, limits, response fields, endpoints, and errors. If you are making your first request, the quickstart is the faster place to begin.

Introduction

exchangerate.dev is a REST API for indicative foreign exchange rates — live intraday on trading days for actively traded currencies, with source, market_session, and honest freshness on every response. Try the free exchange rate API anonymously, or start with a free key — no credit card required.

Indicative rates — not for settlement
Rates are indicative only — not for settlement, regulated trading, or as a “source of record.” The market_session and source fields tell you exactly what you are looking at on every call.

Quickstart

Make your first data call without signup. The standalone 60-second quickstart has the request, exact response shape, and optional API-key step.

Authentication

You can evaluate data routes without a key. Pass your key in the Authorization: Bearer header for account-tier quotas and attribution. Anonymous access is limited to 12 requests/minute and 100 requests/hour per IP. Never embed an account key in public browser JavaScript; use anonymous access or a server-side proxy. Account quota resets at 00:00 UTC on the 1st.

NameTypeDescription
AuthorizationheaderBearer <your-key>. Optional for anonymous evaluation; required for account-tier quotas.
X-RateLimit-RemainingresponseCalls remaining in the current window.
X-RateLimit-ResetresponseUnix timestamp when the window resets.

Rate limits

Anonymous limits are per IP; account limits are per key and calendar month. On 429 the response includes Retry-After.

Free10,000/month12 req/minFree
Basic100,000/month120 req/min$10/mo
Pro1,000,000/month500 req/min$30/mo

Response metadata

Keep this metadata with the rate. It is the API's freshness and derivation context.

FieldMeaning and applicability
source and sourcessource is the least-fresh contributing rate; sources maps returned currencies. Enum values: live (intraday indicative), ecb_daily and fred_daily (daily reference), banxico_daily only on /v1/rate/usd-mxn-banxico, and dof_daily only on /v1/rate/usd-mxn-dof. The two Mexican-peso reference values never apply to latest, historical, convert, or range routes.
market_sessionopen, weekend, or interbank_closed; it describes the market state for the response.
data_updated_at, effective_at, and timestampdata_updated_at is the oldest contributing observation. effective_at maps each currency to its own observation time on latest and batch-convert responses. timestamp is when this response was served. Times are UTC ISO-8601 strings.
derived_symbols, derived, and derivation_bps_maxderived_symbols lists triangulated rates in multi-currency responses. Single-pair responses use derived; derivation_bps_max can be null, including for a derived pair without a fixed ceiling, so use derived to detect triangulation.
noticeA short reminder that rates are indicative, not for settlement. Daily-reference responses include the reference-data notice.

Operation registry

Every public integration operation is listed once by method and OpenAPI path. See the OpenAPI 3.1 schema or ReDoc for complete schemas.

Path and query base values must match when both are sent; conflicts return 400.

json · GET /v1/latest/USD?symbols=EUR,GBP
{
  "result": "success",
  "base": "USD",
  "source": "live",
  "sources": {
    "EUR": "live",
    "GBP": "live"
  },
  "market_session": "open",
  "timestamp": "2026-06-15T12:00:00Z",
  "data_updated_at": "2026-06-15T12:00:00Z",
  "effective_at": {
    "EUR": "2026-06-15T12:00:00Z",
    "GBP": "2026-06-15T12:00:00Z"
  },
  "rates": {
    "EUR": 0.86207,
    "GBP": 0.74627
  },
  "derived_symbols": [],
  "notice": "Indicative rates, not for settlement."
}
OperationPurposeParametersRequestResponseEndpoint errors
GET /v1/latestLatest rates with USD as the default base.base, path_base, symbols (query; optional)/v1/latest?base=USD&symbols=EUR,GBPLatestResponsedata and limit errors
GET /v1/latest/{path_base}Latest rates with a path base.path_base (path); base, symbols (query); path/query base must match/v1/latest/USD?symbols=EUR,GBPLatestResponseconflicting base, data, and limit errors
GET /v1/{date}Historical snapshot for a date.date (path); base, path_base, symbols (query)/v1/2024-01-15?base=EUR&symbols=USD,GBPHistoricalResponsebad date or unavailable data
GET /v1/{date}/{path_base}Historical snapshot with a path base.date, path_base (path); base, symbols (query); path/query base must match/v1/2024-01-15/EUR?symbols=USD,GBPHistoricalResponseconflicting base, bad date, or unavailable data
GET /v1/convert/{from_ccy}/{to_ccy}Convert one unit or a query-supplied amount.from_ccy, to_ccy (path); amount (query, default 1)/v1/convert/USD/EUR?amount=100ConvertResponseinvalid pair, amount, or unavailable data
GET /v1/convert/{from_ccy}/{to_ccy}/{amount}Convert a path-supplied amount.from_ccy, to_ccy, amount (path)/v1/convert/USD/EUR/100ConvertResponseinvalid pair, amount, or unavailable data
POST /v1/convertConvert several amounts in one request.JSON body: from and pairs (required)POST /v1/convertConvertBatchResponseinvalid request, amount, or unavailable data
GET /v1/rangeDaily time series with JSON, CSV, or Parquet output.symbols, start_date, end_date required by API validation; base, cursor, format optional/v1/range?base=USD&symbols=EUR,GBP&start_date=2024-01-01&end_date=2024-06-30RangeResponsemissing parameter, bad date, or unavailable data
GET /v1/currenciesList supported currencies and their display facts.none/v1/currenciesCurrenciesResponsestandard endpoint errors
GET /v1/rate/{slug}Return one flat pair quote by slug.slug (path)/v1/rate/eur-usdRateResponseinvalid pair or unavailable data
POST /v1/account/provisionCreate an account organization and first key when absent.session auth; optional JSON body: signup_attribution, marketing_consentPOST /v1/account/provisionApiKeyCreatedResponseauthentication or account errors
GET /v1/accountRead account, active key, and monthly usage.session authentication/v1/accountAccountResponseauthentication or account errors
GET /v1/account/usage/dailyRead daily usage for up to 90 days.session auth; days (query, optional)/v1/account/usage/daily?days=30DailyUsageResponseauthentication or account errors
DELETE /v1/accountCancel billing and delete account data.session authenticationDELETE /v1/accountDeleteAccountResponseauthentication, account, or billing errors
POST /v1/keys/rotateRotate the active API key with a grace period.session authenticationPOST /v1/keys/rotateApiKeyCreatedResponseauthentication or account errors
DELETE /v1/keysRevoke the active API key.session authenticationDELETE /v1/keyssuccess envelopeauthentication or account errors
POST /v1/consentRecord acceptance of a policy version.session auth; JSON body: policy_version (required)POST /v1/consentConsentResponseauthentication or validation errors

GET /v1/latest

Latest rates for all supported pairs, or a filtered subset via ?symbols=.

curl
GET /v1/latest[/{BASE}]

# Examples
curl /v1/latest/USD                         # base=USD (default)
curl /v1/latest/EUR?symbols=USD,GBP,JPY     # EUR base, 3 symbols
NameTypeDescription
basestringBase currency (default USD). Also accepts path: /v1/latest/EUR.
symbolsstringComma-separated list to filter rates (e.g. EUR,GBP). Omit for all.

GET /v1/{YYYY-MM-DD}

Historical snapshot — returns the reference rate as published on that date. Published coverage starts on 1999-01-04. The historical data guide covers weekends, ranges, pagination, and downloads.

curl
GET /v1/2024-01-15/EUR?symbols=USD,GBP

# On a weekend or holiday: returns the most recent published fix
# is_forward_filled: true will be set in the response

GET /v1/convert

Single or batch currency conversion. The POST form accepts multiple pairs in one call.

curl
# Single
GET /v1/convert/USD/EUR/100

# Batch POST (counts as N calls)
POST /v1/convert
{
  "from": "USD",
  "pairs": [["EUR", 100], ["GBP", 50], ["JPY", 1000]]
}

GET /v1/rate/{slug}

Single-pair quote by slug (e.g. eur-usd) — a flat, single-pair shape distinct from /v1/convert (which nests per-pair results under conversions[] and adds amount/converted). Slug is case-insensitive; malformed or unknown pairs return invalid_pair.

curl
GET /v1/rate/{slug}

curl https://api.exchangerate.dev/v1/rate/eur-usd \
  -H "Authorization: Bearer YOUR_KEY"

# Response
{
  "result": "success",
  "pair": "eur-usd",
  "base": "EUR",
  "quote": "USD",
  "rate": 1.0824,
  "source": "live",
  "sources": { "USD": "live" },
  "market_session": "open",
  "timestamp": "2026-06-16T14:02:11Z",
  "data_updated_at": "2026-06-16T14:01:41Z",
  "derived": false,
  "derivation_bps_max": null,
  "notice": "Indicative rates, not for settlement."
}

GET /v1/range

Daily time-series for a date window. JSON responses are capped at 366 rows/page with keyset pagination; pass format=csv or format=parquet to download the full window as a single file.

curl
GET /v1/range?base=USD&symbols=EUR,GBP&start_date=2024-01-01&end_date=2024-06-30

# Response includes next_cursor + has_more for pagination

GET /v1/currencies

Full list of supported currencies with name, type, decimal precision, minor units, and derived flag. This endpoint takes no parameters.

curl
GET /v1/currencies

GET /v1/account

Your org, active key, and current-month usage.

response
{
  "result": "success",
  "email": "you@example.com",
  "org": { "id": "...", "tier": "pro", "status": "active" },
  "key": { "prefix": "exr_live_ab12", "plaintext": null, "created_at": "2026-06-01T00:00:00Z", "last_used_at": "2026-07-01T18:02:00Z" },
  "usage": { "calls_this_month": 142820, "limit": 1000000, "resets_on": "2026-08-01" }
}

Errors

Every error uses the same envelope. A 429 response also includes a Retry-After header.

json · error envelope
{
  "result": "error",
  "code": "missing_parameter",
  "message": "missing required parameter: symbols"
}

Data errors: invalid_pair, unsupported_base, bad_date, invalid_amount, invalid_request, missing_parameter, data_unavailable, no_data_for_date, live_unavailable, source_unavailable, and service_unavailable.

Authentication and limit errors: invalid_api_key, auth_unavailable, forbidden, rate_limited, ip_rate_limited, quota_exceeded, and quota_unavailable.

Python

Use any HTTP client. The Python integration guide has a compact production example.

Node

Use built-in fetch or another HTTP client. The JavaScript conversion guide covers server-safe use.

MCP server

Use exchangerate.dev as a tool in any MCP-compatible AI agent. The dedicated MCP quickstart has setup, authentication, and the tool table.