API Documentation

Everything you need to integrate real-time currency exchange rates into your application.

Get Free API Key → Quickstart Guide
No credit card required · Setup in 30 seconds

Live interbank mid-market rates, 160+ currencies

The real exchange rate, refreshed every 60 seconds — what you show a customer or price a product in.

Live API Response
GET /api/v1/rates?source=USD&target=EUR
Loading live rate…
Mid-market rate Get API Key →

Official central bank rates

The published figure an auditor or tax office expects — 119 central banks and tax authorities, by date.

Live API Response
GET /api/v1/central-bank/ecb/latest?source=USD&target=EUR
Loading published rate…
Published reference rate All sources →

Quickstart — Get Started in < 2 Minutes

  1. Sign up free or Log in → Get your API key from the profile page
  2. Copy your API key
  3. Try this request:
curl "https://allratestoday.com/api/v1/rates?source=USD&target=EUR" \
  -H "Authorization: Bearer YOUR_API_KEY"

Don't have an account? Create one for free.

Overview

The AllRatesToday exchange rate API gives your application programmatic access to two complementary families of exchange-rate data through one REST interface: live mid-market rates for 160+ currencies, refreshed around the clock, and the official reference rates published by 116 central banks and 3 tax authorities — ingested directly from each publisher's own release and stored unmodified, with the publisher's publication date on every row. Responses are JSON by default; every table endpoint can also answer in CSV, XML or Excel.

Global interbank market Live mid-market quotes refreshed ~every 60 seconds 105 official publishers 116 central banks 3 tax & customs authorities daily · weekly · monthly · quarterly AllRatesToday API Fetched as each source publishes Cross-source plausibility checks Stored unmodified with rate_date Full archives — ECB back to 1999 One key · one response shape JSON · CSV · XML · XLSX Your application REST from any language Node, Python, PHP, Go SDKs React hooks & components MCP server for AI agents Excel & Google Sheets Embeddable widget ingest serve
How a rate reaches your application: both rate families flow through the same ingestion, storage and API layer, so one key and one response shape cover live pricing and compliance work alike.

All endpoints live under a single base URL:

https://allratestoday.com

Every endpoint requires an API key except /api/v1/symbols (the currency list). Plans differ only in how many requests a month you may make — there is no feature gating on the mid-market endpoints, and only two central-bank endpoints are paid-only. See Rate Limits & Quotas and the pricing page.

The whole API on one page

Six mid-market endpoints and six official-rate endpoints. Everything else in this documentation is a client library, an integration, or reference material for these twelve.

EndpointAuthQuota costWhat it returns
GET /api/v1/ratesKey or session1Live mid-market rate for one or many target currencies. Add amount to convert.
GET /api/rateKey1One pair, minimal response body.
GET /api/historical-ratesKey or session1, or 12 for 1yDaily mid-market series for a preset period.
GET /api/v1/symbolsNone0All supported currency codes, names and symbols.
GET /api/v1/central-banksKey1Covered official sources and their latest available date.
GET /api/v1/central-banks/ratesKey1Every source's latest official rate for one pair, side by side.
GET /api/v1/central-bank/{bank}/latestKey1One source's most recent published table.
GET /api/v1/central-bank/{bank}/{date}Key, paid plan1The table published on (or most recently before) a given date.
GET /api/v1/central-bank/{bank}/historyKey, paid plan1 per month of rangeDaily official series for a currency or a pair.
GET /api/v1/central-bank/{bank}/availabilityKey1The dates a source actually published — its real calendar.
Endpoints that do not exist. There is no /api/convert, no /api/timeseries and no /api/latest — those paths return a 404 page, not JSON. Conversion is /api/v1/rates with &amount=; time series is /api/historical-rates. The old keyless /api/public/rates was retired and now answers 401 with a pointer to registration.

Two kinds of rate — which one do you need?

The API serves two deliberately separate families of rates. They answer different questions, and compliance rules often dictate which one you must use:

PropertyMid-market ratesOfficial central-bank & tax-authority rates
What it isThe live midpoint of the interbank market — where the market is trading right now, with no retail markup.The rate a central bank or tax authority itself published — a fixed, citable number with the publisher's own rate_date.
How often it changesRefreshes roughly every 60 seconds, around the clock.Once per publication cycle — daily for most banks, weekly (Fed), monthly (SNB, HMRC), or quarterly (US Treasury). Never changes after publication.
Use it forPrice display, checkout conversion, dashboards, alerts, anything that should track the market.Tax filings, customs valuations, statutory invoicing, audits, book closing — anywhere a regulation names the official source.
Endpoints/api/v1/rates, /api/rate, /api/historical-rates, /api/v1/symbols/api/v1/central-bank/{bank}/… — see Central Bank Rates
Weekend / holiday behaviourKeeps moving with whatever markets are open.Returns the most recent published date, explicitly flagged — the rate compliance rules require you to apply.

The two can differ by several percent: over Aug 2025–Aug 2026 the widest gap between the GBP/USD mid-market rate and HMRC's monthly rate-in-force was 3.7% — about £2,832 on a $100k invoice. Picking the right family is a correctness decision, not a preference. If a regulation or auditor names a source, use the official endpoints; otherwise the mid-market rate is the truer price.

Authentication

All API endpoints require authentication. Include your API key as a Bearer token:

Authorization: Bearer YOUR_API_KEY

Get your API key from your profile page after signing in.

API keys do not expire. A key remains valid until you rotate or revoke it from your profile page — there is no token endpoint to call and no refresh flow to implement, unlike OAuth-based providers whose access tokens expire every few minutes.

Requests without a valid key receive a 401 Unauthorized response:

// 401 response — missing or invalid API key
{
  "error": "Authentication required. Provide an API key via Authorization header or log in."
}

If a key is ever compromised, rotate it immediately — revocation takes effect instantly — and email support@allratestoday.com if you need help investigating unexpected usage.

Passing the key in the query string

Two endpoints also accept the key as a query parameter, for callers that cannot set a header — a browser address bar, a spreadsheet's IMPORTDATA, a webhook tester:

EndpointParameter
/api/v1/rates?api_key=
/api/rate?key= or ?apiKey=
Convenience only — not for production. Query strings are written to proxy logs, CDN logs, browser history and Referer headers. Use the Authorization header in any server you deploy; treat a key that has travelled in a URL as exposed and rotate it.

The other endpoints — /api/historical-rates and every /api/v1/central-bank/… path — accept the header only.

Session authentication

/api/v1/rates and /api/historical-rates also accept a logged-in browser session instead of a key, which is what the site's own pages and the playground use. The quota is charged to the session user's key exactly as if the key had been sent. This exists so our own pages work; build integrations against the API key.

Security

The AllRatesToday API is designed with security as a first-class concern. This section explains the transport, authentication, and data-handling guarantees you can rely on, plus the responsibilities that sit on your side as an integrator.

Transport (TLS / HTTPS)

  • All API traffic must be sent over HTTPS. Plain-text HTTP requests are permanently redirected (301) to HTTPS but should never be used for API calls — the redirect leaks your API key via the initial request.
  • We require TLS 1.2 or higher. Connections using older TLS versions (1.0, 1.1) or SSLv3 are rejected at the edge.
  • Certificates are issued by publicly-trusted CAs and automatically renewed. HSTS is enforced with max-age=31536000; includeSubDomains.

Network requirements (corporate firewalls)

  • The only domain to allow is allratestoday.com on port 443 — every endpoint, including the central-bank API, lives under it.
  • The API is served from Cloudflare's edge network, so there is no fixed origin IP. Do not allowlist individual IP addresses — allow Cloudflare's published IP ranges (they change; automate updates if your firewall supports it).
  • Certificates come from multiple public CAs and rotate automatically — trust the standard set of modern public root CAs rather than pinning a specific CA or certificate.
  • TLS-inspecting (SSL interception) proxies can break requests by re-signing with a private CA; if your organisation uses one, exclude allratestoday.com from inspection.
  • Prefer TLS 1.3; TLS 1.2 is the minimum accepted.

Authentication

  • Authentication uses a Bearer token in the Authorization header. Two endpoints additionally accept the key as a query parameter for non-programmatic callers — see Authentication — but query strings get logged by proxies, CDNs and browser history, so the header is the only form to use from a server.
  • Every API key is scoped to one account and can be rotated or revoked instantly from your profile page. Revocation is immediate: the next request with the old key returns 401.
  • Keys are stored server-side and remain retrievable from your profile page, so you can copy a key again later rather than rotating every environment when one is misplaced. The trade-off is that a key is a bearer credential in the full sense — anyone who can read it can spend your quota. Treat it like a password: secret store, never in git, never in a client bundle.
  • Keys are prefixed art_live_ followed by 32 characters. There is no separate test key, sandbox environment or mock mode — staging and production call the same URLs and spend the same quota. Most plans issue one key per account (the Large plan allows three), so if you need to separate environments, budget for it in your quota rather than expecting a free test tier.

API key handling (your responsibilities)

Never embed your API key in client-side code. Browsers, mobile apps, and any compiled binary can be decompiled. A key shipped to the browser is a public key — expect it to be scraped within hours.
  • Server-side only. Call the AllRatesToday API from your backend. Proxy the result to your frontend.
  • Use environment variables (process.env.ART_API_KEY). Never commit keys to git, never include them in container images.
  • Rotate keys periodically — at minimum every 90 days, and immediately if a key is ever exposed in logs, commits, or error reports.
  • Use one key per service. When a key leaks, you can revoke just that environment instead of rotating everything.

Abuse protection

  • Rate limiting is applied per API key (see Rate Limits). Exceeding the limit returns 429 Too Many Requests; it does not leak usage data to other keys.
  • WAF & DDoS: requests are filtered by Cloudflare's edge network, which applies OWASP Top 10 mitigations automatically. Malformed or abusive requests are rejected before reaching the API.
  • Automated monitoring flags anomalous usage patterns (e.g. sudden 100× spikes) and can lock a key pending verification.

Data handling & privacy

  • We log request metadata (timestamp, endpoint, status code, rate-limit counters) but never the response payload. Rate data is public.
  • We do not collect or store any personal data you send in query strings — but please don't send any: all the API needs is currency codes and optional date parameters.
  • Access logs are retained for 30 days for debugging and abuse investigation, then permanently deleted.
  • AllRatesToday is operated from the UK and complies with UK GDPR. See the privacy policy for the full data-handling statement.

Reporting a vulnerability

If you believe you have found a security issue in the AllRatesToday API, please report it privately to support@allratestoday.com. Please do not disclose the issue publicly (on GitHub, Twitter, blog posts, etc.) until we have had a reasonable chance to respond.

We aim to acknowledge reports within 24 hours and provide a remediation timeline within 72 hours. Responsible disclosure is credited publicly after the fix is deployed (if you want to be named).

Rate Limits & Quotas

There is one limit that matters: the number of requests your key may make. It is a quota, not a per-second throttle — you can burst as fast as you like, and nothing is refused until the quota is spent.

PlanRequestsPeriodAPI keys
Free300Lifetime — see below1
Small5,000Per calendar month1
Medium10,000Per calendar month1
Large100,000Per calendar month3
CustomAgreed per accountPer calendar month1
The free tier is 300 requests in total, not 300 per month. Free usage counts against a lifetime total that never resets. Once it is spent, the key returns 429 until the account moves to a paid plan. Plan for it: 300 calls is enough to evaluate the API and ship a prototype, not to run a cron job. Paid plans reset at 00:00 UTC on the first of each calendar month.

What counts as one request

  • Each HTTP call to an authenticated endpoint costs 1, whatever it returns. /api/v1/rates?source=USD&target=EUR,GBP,JPY is one request, not three — batching targets is free, and is the cheapest way to cut usage.
  • Historical data is billed by volume, because one call can hand over a year of archive. /api/historical-rates?period=1y costs 12; 1d, 7d and 30d cost 1. On the central-bank /history endpoint the charge is one unit per calendar month of the requested range per series, and every response reports what it cost in billed_requests.
  • /api/v1/symbols is keyless and costs 0. Cache it and stop paying for currency lists.
  • A rejected 401 (bad key), 403 or 429 is never charged, and neither is a 400 from an unsupported ?format=, which is validated before authentication. Everything past that point is counted when the request is accepted — so a call that then fails on a bad currency code, or on an upstream error, does spend a unit. Validate currency codes against /api/v1/symbols rather than discovering them through failed calls.
  • The quota is per key. A key that is rotated keeps the account's usage — rotating does not reset your counter.

Response headers

Quota headers are returned on the 429 response only — successful responses do not currently carry X-RateLimit-* or X-Monthly-* headers, so do not build a client that reads a remaining-count from a 200.

HeaderSent onValue
X-Monthly-Limit429Your plan's request allowance.
X-Monthly-Used429Requests spent in the current period.
X-Monthly-Resets429ISO 8601 timestamp of the next reset. On the free plan this date is informational — the lifetime counter does not reset.
Cache-Controlevery 200max-age=60 on rate endpoints, max-age=86400 on /api/v1/symbols. See Caching.

To watch your usage between calls, read the counters on your profile page, which shows today, this month, last month, and lifetime totals. There is no Retry-After header; use resets_at from the 429 body.

The 429 response

HTTP/1.1 429 Too Many Requests
X-Monthly-Limit: 5000
X-Monthly-Used: 5000
X-Monthly-Resets: 2026-09-01T00:00:00.000Z

{
  "error": "Request limit exceeded",
  "used": 5000,
  "limit": 5000,
  "plan": "small",
  "resets_at": "2026-09-01T00:00:00.000Z",
  "upgrade_url": "https://allratestoday.com/pricing"
}

A history request that would cross the limit is refused before any data is returned, and says so explicitly — “A 1y history request is billed as 12 API calls (one per month of data)” — rather than returning a truncated series.

We email you at 90% of your allowance and again when it is exhausted, so a quota does not run out silently in production. View plans and pricing · need a limit that is not on the list? Talk to us.

Handling a 429 in code

Retrying a quota 429 immediately never helps — the quota is not time-windowed at the second level, so a backoff loop just burns your own CPU. Fail over to a cached rate and alert instead:

const res = await fetch(url, { headers: { Authorization: `Bearer ${key}` } });

if (res.status === 429) {
  const { used, limit, resets_at } = await res.json();
  // Do not retry: the allowance is spent until resets_at (or until you upgrade).
  logger.error(`FX quota exhausted: ${used}/${limit}, resets ${resets_at}`);
  return lastKnownRate;   // serve stale rather than fail the checkout
}

if (!res.ok) throw new Error(`FX API ${res.status}`);
return (await res.json())[0].rate;

Authenticated Rates

GET /api/v1/rates

Authenticated endpoint with higher rate limits. Requires a Bearer token.

ParameterTypeDescription
sourceoptional string Source currency code (e.g. USD)
targetoptional string Target currency code (e.g. EUR). Supports comma-separated values for multiple targets (e.g. EUR,GBP,JPY)
timeoptional ISO 8601 Rate at a specific point in time
fromoptional YYYY-MM-DD Start date for historical range
tooptional YYYY-MM-DD End date for historical range
groupoptional string Series granularity for a from/to range: day, hour or minute. Resolution depends on the window size: minute applies to windows up to 1 day (~1,400 points), hour up to 30 days (720 points); longer windows return daily points regardless of group. For a long fine-grained series, chunk the range — e.g. twelve 30-day windows with group=hour covers a year at hourly resolution, and day-sized windows with group=minute can be sampled down to any interval (every 30 minutes, say).
amountoptional number Convert this amount instead of returning a bare rate. Changes the response shape to the conversion object shown under Convert, and requires exactly one source and one target — combining it with a comma-separated target list returns 400. Must be a non-negative number.
formatoptional string json (default), csv, xml or xlsx — see Response Formats. Ignored when amount is used.
api_keyoptional string Key as a query parameter, for callers that cannot set a header. Prefer the Authorization header — see Authentication.
One call, many currencies. target=EUR,GBP,JPY,CAD returns one array with four entries and costs a single request against your quota. If you price a page in a dozen currencies, fetch them in one call rather than looping — it is twelve times cheaper and one round trip instead of twelve.

Example:

curl "https://allratestoday.com/api/v1/rates?source=USD&target=EUR" \
  -H "Authorization: Bearer YOUR_API_KEY"

Response — always a JSON array, even for a single pair. A common integration bug is reading res.rate; it is res[0].rate.

[
  {
    "rate": 0.9215,
    "source": "USD",
    "target": "EUR",
    "time": "2026-04-03T12:00:00Z"
  }
]
FieldTypeNotes
ratenumberUnits of target per 1 unit of source. Full precision — round for display, never for storage.
source / targetstringISO 4217 codes, echoed back uppercase.
timeISO 8601When this rate was observed, in UTC. Store it alongside any rate you persist — an FX figure without a timestamp cannot be audited later.

Simple Rate

GET /api/rate Auth Required

Lightweight endpoint for fetching a single pair rate. The response carries the rate and nothing else — useful where bandwidth or parsing cost matters, or where you just want one number. It costs the same one request as /api/v1/rates, which returns more, so reach for this one only when the smaller body is the point.

ParameterTypeDescription
sourcerequired string Source currency code
targetrequired string Target currency code
key / apiKeyoptional string Key as a query parameter, accepted here so a plain cross-origin GET needs no preflight. The Authorization header works too and is what a server should send.
curl "https://allratestoday.com/api/rate?source=GBP&target=USD" \
  -H "Authorization: Bearer YOUR_API_KEY"
{ "rate": 1.2634, "source": "interbank" }

Without a valid key the endpoint returns 401 with a signup pointer:

{
  "error": "A valid API key is required",
  "hint": "Get a free API key at https://allratestoday.com/register"
}
What does "source": "interbank" mean? The source field in the response indicates the data provider. AllRatesToday delivers mid-market exchange rates sourced from institutional interbank market data — the same institutional-grade data used by banks and financial platforms worldwide, without any retail markup.

Convert

GET /api/v1/rates

Conversion is not a separate endpoint: it is /api/v1/rates with an amount. Adding the parameter switches the response from the rate array to a single conversion object. Exactly one source and one target are required — a comma-separated target list with an amount returns 400, because one converted figure across several currencies would be ambiguous.

ParameterTypeDescription
sourcerequired string Source currency code (e.g. USD)
targetrequired string Target currency code (e.g. EUR)
amountrequired number Amount to convert

Example — Convert $1,000 to EUR:

curl "https://allratestoday.com/api/v1/rates?source=USD&target=EUR&amount=1000" \
  -H "Authorization: Bearer YOUR_API_KEY"

Response:

{
  "from": { "currency": "USD", "amount": 1000 },
  "to": { "currency": "EUR", "amount": 923.4 },
  "rate": 0.9234,
  "source": "interbank"
}

The converted figure is rounded to 6 decimal places; rate is returned at full precision. For money you are going to book, convert from rate yourself with your own rounding rules and currency exponent (JPY has no minor unit, KWD has three) rather than taking to.amount as final.

SDK example:

// JavaScript
const result = await client.convert('USD', 'EUR', 1000);
console.log(`$1,000 = €${result.result}`);  // $1,000 = €923.4
# Python
result = client.convert("USD", "EUR", 1000)
print(f"$1,000 = €{result['result']}")

Historical Rates

GET /api/historical-rates Auth Required

Fetch historical exchange rate data for charting and analysis. Requires an API key.

ParameterTypeDescription
sourcerequired string Source currency code
targetrequired string Target currency code
periodoptional string One of 1d, 7d, 30d, 1y. Default 7d. Any other value falls back to 7d rather than erroring — check the period field in the response if you pass it dynamically.
formatoptional string json (default), csv, xml or xlsx — see Response Formats.
Billing: period=1y costs 12 requests, not 1. History is metered by volume — one request per month of data covered — so a single yearly pull cannot drain the archive for one unit. 1d, 7d and 30d each cost 1. If the call would exceed your allowance it is refused with 429 before any data is returned, and the message names the cost.

What each period actually returns

periodPointsGranularityQuota
1d24Hourly — modelled, not observed, see below1
7d~7One observed close per calendar day, plus today's live rate1
30d~30One observed close per calendar day, plus today's live rate1
1y~52Weekly — the daily series is downsampled to every 7th point to keep charts readable12
period=1d is a chart shape, not intraday market data. It is built from two real observations — yesterday's rate and the current rate — interpolated into 24 hourly points with a small synthetic variation applied so the line does not look drawn with a ruler. The endpoints are real; the path between them is not. Use it to draw a sparkline. Do not use it for backtesting, volatility measurement, or anything where an individual hour's value has to be true. For point-in-time accuracy use /api/v1/rates with time, and for figures that must be citable use the official central-bank rates.

Dates in the 1d response are full ISO 8601 timestamps; in every other period they are YYYY-MM-DD. If you parse the date field, handle both, or key off timestamp, which is milliseconds since epoch in all cases.

curl "https://allratestoday.com/api/historical-rates?source=USD&target=EUR&period=30d" \
  -H "Authorization: Bearer YOUR_API_KEY"
{
  "source": "USD",
  "target": "EUR",
  "data": [
    { "date": "2026-03-04", "rate": 0.9198, "timestamp": 1741046400000 },
    { "date": "2026-03-05", "rate": 0.9210, "timestamp": 1741132800000 }
  ],
  "source_api": "interbank",
  "period": "30d"
}

Time Series & Custom Date Ranges

Mid-market history is served by preset periods only. /api/historical-rates understands period; it does not read from or to. Sending them is not an error — they are silently ignored and you get the default 7-day window back, which is the failure mode most likely to reach production unnoticed. Always check the period field in the response to confirm what you actually received.

If you need an arbitrary fromto range, there are two supported routes:

1. Official rates over an exact range (recommended for reporting)

The central-bank history endpoint takes real from and to dates, returns one row per published date, and gives you a citable source and a fixed rate_date per row — which is what a report, an audit trail or a month-end close actually needs. It is a paid-plan endpoint and is billed per month of range.

curl "https://allratestoday.com/api/v1/central-bank/ecb/history?source=USD&target=EUR&from=2026-01-01&to=2026-03-31" \
  -H "Authorization: Bearer YOUR_API_KEY"

See Central Bank Rates for the full parameter list, and add &format=xlsx to get the range straight into a spreadsheet.

2. Mid-market series from a preset period

Take the nearest enclosing period and filter client-side. A quarter fits inside 30d only if it is the current month, so in practice this means 1y — which is weekly-sampled and costs 12 requests, so fetch it once and cache it rather than calling it per page view.

const res = await fetch(
  'https://allratestoday.com/api/historical-rates?source=USD&target=EUR&period=1y',
  { headers: { Authorization: `Bearer ${key}` } }
);
const { data, period } = await res.json();

// Confirm you got what you asked for — an unknown period silently becomes 7d.
if (period !== '1y') throw new Error(`Unexpected period: ${period}`);

const q1 = data.filter((p) => p.date >= '2026-01-01' && p.date <= '2026-03-31');
Response shape Both period and central-bank history return a data array of { date, rate, timestamp } objects sorted oldest first. There is no rates object keyed by date, and no pagination — every series is returned in one response, capped at 5,000 rows on the central-bank endpoint.

Symbols

GET /api/v1/symbols

Every supported currency code, name and symbol — 160 of them. Use it to build dropdowns, and to validate user input before spending a request on a pair that does not exist.

curl "https://allratestoday.com/api/v1/symbols"
The only keyless endpoint. No API key, no quota cost, and Access-Control-Allow-Origin: * — so it is the one endpoint you may safely call straight from a browser. Responses carry Cache-Control: public, max-age=86400; the list changes rarely, so cache it at build time or on first load rather than fetching it per page view. It also accepts ?format=csv|xml|xlsx (see Response Formats).

Response:

{
  "currencies": [
    { "code": "USD", "name": "US Dollar", "symbol": "$" },
    { "code": "EUR", "name": "Euro", "symbol": "€" },
    { "code": "GBP", "name": "British Pound", "symbol": "£" },
    { "code": "JPY", "name": "Japanese Yen", "symbol": "¥" },
    ...
  ],
  "count": 160
}

A currency appearing here means the code is recognised, not that every pair built from it is quoted at every moment — thinly traded pairs can be temporarily unavailable upstream and return 502. Handle that case rather than assuming a listed code always resolves.

SDK example:

// JavaScript — build a currency dropdown
const data = await fetch('https://allratestoday.com/api/v1/symbols').then(r => r.json());
const options = data.currencies.map(c => ({
  value: c.code,
  label: `${c.code} — ${c.name}`,
}));

// React example
<select>
  {options.map(o => <option key={o.value} value={o.value}>{o.label}</option>)}
</select>
# Python
import requests
data = requests.get("https://allratestoday.com/api/v1/symbols").json()
for c in data["currencies"]:
    print(f"{c['code']}: {c['name']} ({c['symbol']})")

Central Bank Rates

Official exchange rates as published by central banks and national tax authorities — the rates required for tax filings, customs valuations, audits, and compliant invoicing. Coverage — 116 central banks and 3 tax authorities, plus the computed composite (120 sources in total). Use the Code column as the {bank} path parameter in the endpoints below.

CodeSourceCountryHome ccyType
fed US Federal Reserve (H.10) United States USD Central bank
boe Bank of England United Kingdom GBP Central bank
pboc People's Bank of China (CFETS) China CNY Central bank
rba Reserve Bank of Australia Australia AUD Central bank
cbr Bank of Russia Russia RUB Central bank
tcmb Central Bank of Türkiye Türkiye TRY Central bank
bcb Banco Central do Brasil (PTAX) Brazil BRL Central bank
bi Bank Indonesia Indonesia IDR Central bank
rbi Reserve Bank of India India INR Central bank
boc Bank of Canada Canada CAD Central bank
bnm Bank Negara Malaysia Malaysia MYR Central bank
cbsl Central Bank of Sri Lanka Sri Lanka LKR Central bank
cnb Czech National Bank Czech Republic CZK Central bank
ecb European Central Bank Eurozone EUR Central bank
nbp Narodowy Bank Polski Poland PLN Central bank
norges Norges Bank Norway NOK Central bank
riksbank Sveriges Riksbank Sweden SEK Central bank
cbn Central Bank of Nigeria Nigeria NGN Central bank
cbk Central Bank of Kuwait Kuwait KWD Central bank
cbb Central Bank of Bahrain Bahrain BHD Central bank
cbar Central Bank of Azerbaijan Azerbaijan AZN Central bank
cbbh Central Bank of Bosnia and Herzegovina Bosnia and Herzegovina BAM Central bank
bnb Bulgarian National Bank Bulgaria EUR Central bank
bcrp Central Reserve Bank of Peru Peru PEN Central bank
boj Bank of Japan Japan JPY Central bank
hkma Hong Kong Monetary Authority Hong Kong HKD Central bank
boi Bank of Israel Israel ILS Central bank
bcra Central Bank of Argentina Argentina ARS Central bank
sarb South African Reserve Bank South Africa ZAR Central bank
snb Swiss National Bank Switzerland CHF Central bank
rbnz Reserve Bank of New Zealand New Zealand NZD Central bank
bok Bank of Korea South Korea KRW Central bank
bnr National Bank of Romania Romania RON Central bank
nbu National Bank of Ukraine Ukraine UAH Central bank
banxico Banco de México Mexico MXN Central bank
bsp Bangko Sentral ng Pilipinas Philippines PHP Central bank
bcrd Banco Central de la República Dominicana Dominican Republic DOP Central bank
bcp Banco Central del Paraguay Paraguay PYG Central bank
nbc National Bank of Cambodia Cambodia KHR Central bank
bog Bank of Ghana Ghana GHS Central bank
cbe Central Bank of Egypt Egypt EGP Central bank
boa Bank of Albania Albania ALL Central bank
banguat Banco de Guatemala Guatemala GTQ Central bank
bom Bank of Mongolia Mongolia MNT Central bank
mas Monetary Authority of Singapore Singapore SGD Central bank
bdi Banca d'Italia Italy EUR Central bank
dnb Danmarks Nationalbank Denmark DKK Central bank
sfc Superintendencia Financiera de Colombia (TRM) Colombia COP Central bank
nbk National Bank of Kazakhstan Kazakhstan KZT Central bank
nbg National Bank of Georgia Georgia GEL Central bank
cbu Central Bank of Uzbekistan Uzbekistan UZS Central bank
mnb Magyar Nemzeti Bank Hungary HUF Central bank
cbi Central Bank of Iceland Iceland ISK Central bank
cbuae Central Bank of the UAE United Arab Emirates AED Central bank
sbp State Bank of Pakistan Pakistan PKR Central bank
nrb Nepal Rastra Bank Nepal NPR Central bank
cbj Central Bank of Jordan Jordan JOD Central bank
bb Bangladesh Bank Bangladesh BDT Central bank
cbo Central Bank of Oman Oman OMR Central bank
pma Palestine Monetary Authority Palestine ILS Central bank
cbm Central Bank of Myanmar Myanmar MMK Central bank
cbc Central Bank of the Republic of China (Taiwan) Taiwan TWD Central bank
bot Bank of Thailand Thailand THB Central bank
amcm Monetary Authority of Macao Macao MOP Central bank
sbv State Bank of Vietnam Vietnam VND Central bank
bol Bank of the Lao PDR Laos LAK Central bank
bcv Central Bank of Venezuela Venezuela VES Central bank
bcch Central Bank of Chile Chile CLP Central bank
bcu Central Bank of Uruguay Uruguay UYU Central bank
bcbol Banco Central de Bolivia Bolivia BOB Central bank
cbvs Central Bank of Suriname Suriname SRD Central bank
bogy Bank of Guyana Guyana GYD Central bank
sama Saudi Central Bank (SAMA) Saudi Arabia SAR Central bank
bam Bank Al-Maghrib Morocco MAD Central bank
nbs National Bank of Serbia Serbia RSD Central bank
nbrb National Bank of the Republic of Belarus Belarus BYN Central bank
qcb Qatar Central Bank Qatar QAR Central bank
cbiq Central Bank of Iraq Iraq IQD Central bank
bda Bank of Algeria Algeria DZD Central bank
bccr Banco Central de Costa Rica Costa Rica CRC Central bank
bceao Central Bank of West African States (BCEAO) West Africa (WAEMU) XOF Central bank
nbe National Bank of Ethiopia Ethiopia ETB Central bank
cbke Central Bank of Kenya Kenya KES Central bank
nbm National Bank of Moldova Moldova MDL Central bank
nbrm National Bank of North Macedonia North Macedonia MKD Central bank
cba Central Bank of Armenia Armenia AMD Central bank
beac Bank of Central African States (BEAC) Central Africa (CEMAC) XAF Central bank
bct Central Bank of Tunisia Tunisia TND Central bank
bnrw National Bank of Rwanda Rwanda RWF Central bank
bna National Bank of Angola Angola AOA Central bank
botz Bank of Tanzania Tanzania TZS Central bank
bou Bank of Uganda Uganda UGX Central bank
bojm Bank of Jamaica Jamaica JMD Central bank
bcn Banco Central de Nicaragua Nicaragua NIO Central bank
bch Banco Central de Honduras Honduras HNL Central bank
cbtt Central Bank of Trinidad and Tobago Trinidad and Tobago TTD Central bank
bmu Bank of Mauritius Mauritius MUR Central bank
bdm Banco de Moçambique Mozambique MZN Central bank
bob Bank of Botswana Botswana BWP Central bank
boz Bank of Zambia Zambia ZMW Central bank
rbm Reserve Bank of Malawi Malawi MWK Central bank
nbkr National Bank of the Kyrgyz Republic Kyrgyzstan KGS Central bank
lb Bank of Lithuania Lithuania EUR Central bank
bcc Banque Centrale du Congo DR Congo CDF Central bank
cbbd Central Bank of Barbados Barbados BBD Central bank
cbl Central Bank of Libya Libya LYD Central bank
cbg Central Bank of The Gambia Gambia GMD Central bank
brh Banque de la République d'Haïti Haiti HTG Central bank
rma Royal Monetary Authority of Bhutan Bhutan BTN Central bank
nbt National Bank of Tajikistan Tajikistan TJS Central bank
cbbz Central Bank of Belize Belize BZD Central bank
rbf Reserve Bank of Fiji Fiji FJD Central bank
mma Maldives Monetary Authority Maldives MVR Central bank
bcm Banque Centrale de Mauritanie Mauritania MRU Central bank
rbz Reserve Bank of Zimbabwe Zimbabwe ZWG Central bank
bon Bank of Namibia Namibia NAD Central bank
hmrc HM Revenue & Customs United Kingdom GBP Tax authority
bazg Swiss Federal Office for Customs and Border Security Switzerland CHF Tax authority
ustreasury U.S. Department of the Treasury United States USD Tax authority
composite Composite Official Rate Global USD Composite

See the central bank coverage map or the tax authority coverage for per-source pages, or get the live list from /api/v1/central-banks. Both kinds of source are served by the endpoints below — only the coverage pages are split. More sources are being added. All central-bank requests count toward your plan's monthly request quota, like every other endpoint.

These are not the mid-market rates served by /api/v1/rates and the conversion endpoints. A mid-market rate is the live interbank midpoint and moves every minute; an official rate is the number the named institution published for that date and never changes afterwards. Use official rates wherever a regulation, tax authority, or auditor names the source; use mid-market rates for pricing and display. The two can diverge by several percent — see the comparison in Overview.

Rates use the convention value = quote currency per 1 base currency and always carry the bank's own publication date (rate_date). On weekends and holidays the most recent published date is returned — which is the rate compliance rules require you to apply.

Every covered bank also has a dedicated zero-dependency npm package (e.g. ecb-exchange-rate, cbsl-exchange-rate) wrapping these endpoints with TypeScript types — linked from its per-bank page.

GET /api/v1/central-banks Auth Required

List covered banks with metadata and the latest available date.

curl "https://allratestoday.com/api/v1/central-banks" \
  -H "Authorization: Bearer YOUR_API_KEY"
GET /api/v1/central-banks/rates Auth Required

Every bank's latest official rate for one pair, in a single call — useful for comparing what different institutions published for the same day, or picking the one a given regulator names. Pairs a bank does not publish directly are cross-computed from that bank's own table only; banks are never mixed to derive a rate, and any bank that cannot produce the pair is skipped.

Sources that have not published for 30 days are still returned — the U.S. Treasury publishes quarterly and its rate stays legally in force for months — but are marked stale and excluded from the spread statistics, so a quarter-old table cannot distort the min/max/median against daily publishers.

curl "https://allratestoday.com/api/v1/central-banks/rates?source=USD&target=EUR" \
  -H "Authorization: Bearer YOUR_API_KEY"

See the rate methodology for how the composite is computed from these.

GET /api/v1/central-bank/{bank}/latest Auth Required

The bank's most recent published rate table. Available on all plans, including free — every request counts as one API call toward your monthly quota. Add source and target (same parameters as the live rates API) to get a single pair instead of the full table:

# Full table
curl "https://allratestoday.com/api/v1/central-bank/cbsl/latest" \
  -H "Authorization: Bearer YOUR_API_KEY"

# Single pair — USD to LKR at the CBSL rate
curl "https://allratestoday.com/api/v1/central-bank/cbsl/latest?source=USD&target=LKR" \
  -H "Authorization: Bearer YOUR_API_KEY"
{
  "bank": "cbsl",
  "name": "Central Bank of Sri Lanka",
  "rate_date": "2026-07-28",
  "source": "USD",
  "target": "LKR",
  "rate": 336.2512,
  "rate_type": "indicative",
  "derived": false,
  "method": "published",
  "disclaimer": "Official rates as published by the named central bank. On weekends/holidays the most recent published rate_date is returned."
}

If the bank does not publish the pair directly, it is computed from the published table — the inverse pair, or a cross rate via the bank's home currency (e.g. USD→JPY from the ECB's EUR→USD and EUR→JPY). Computed rates return "derived": true with the method, so you always know what the bank actually printed versus what was calculated.

{
  "bank": "cbsl",
  "name": "Central Bank of Sri Lanka",
  "rate_date": "2026-07-28",
  "rates": [
    { "base": "USD", "quote": "LKR", "type": "indicative", "value": 336.2512 },
    { "base": "EUR", "quote": "LKR", "type": "indicative", "value": 382.3849 }
  ]
}
GET /api/v1/central-bank/{bank}/{YYYY-MM-DD} Paid Plans

The published table for a specific date. If the bank did not publish that day, the response returns the most recent prior rate_date and sets published_on_requested_date: false. Also accepts source/target for a single pair.

curl "https://allratestoday.com/api/v1/central-bank/ecb/2026-06-30?source=USD&target=EUR" \
  -H "Authorization: Bearer YOUR_API_KEY"
GET /api/v1/central-bank/{bank}/history Paid Plans

Daily time series. Defaults to the last year; max 5000 rows per request. Use symbol for all pairs involving one currency, or source + target for a single pair series (e.g. USD→LKR day by day).

Billing: history is metered by volume — one API call per month of data covered (each response reports the charge in billed_requests). A one-month series costs 1 call; a full year costs 12. Whole-table history downloads on the bank pages are likewise billed per currency per month.

ParameterTypeDescription
symboloptional string 3-letter currency code, matched against either side of the pair. Required unless source+target given.
source / targetoptional string Pair mode: one resolved rate per date, cross-computed via the bank's home currency when not directly published (derived: true)
fromoptional date Range start, YYYY-MM-DD (default: one year before to)
tooptional date Range end, YYYY-MM-DD (default: today)
curl "https://allratestoday.com/api/v1/central-bank/boc/history?symbol=USD&from=2026-01-01" \
  -H "Authorization: Bearer YOUR_API_KEY"
GET /api/v1/central-bank/{bank}/availability All Plans

The bank's publication calendar: the dates it actually published a table, for a ?year=2026 or a ?from/?to range (default: the last year). Weekends, holidays, and weekly-cadence gaps show up as missing dates — useful for reconciliation jobs that need to know which dates have an official rate before requesting them.

curl "https://allratestoday.com/api/v1/central-bank/cbsl/availability?year=2026" \
  -H "Authorization: Bearer YOUR_API_KEY"

Response formats

All three central-bank table endpoints accept ?format=json|csv|xml|xlsx, like the rest of the API — see Response Formats for the full description. An xlsx export of a bank's history is the fastest way to hand a finance team an auditable range:

curl "https://allratestoday.com/api/v1/central-bank/ecb/history?source=USD&target=EUR&from=2026-01-01&format=xlsx" \
  -H "Authorization: Bearer YOUR_API_KEY" -o ecb-usd-eur.xlsx

Plan requirements

/latest, /availability and both /api/v1/central-banks… list endpoints work on every plan, free included. /history and the dated /{YYYY-MM-DD} lookup require a paid plan and return 403 on free:

{
  "error": "Historical central bank rates require a paid plan. The /latest endpoint is available on all plans.",
  "upgrade_url": "https://allratestoday.com/pricing"
}

Terminology

  • rate_date — the bank's own publication date for the table, never ours. Requests for dates the bank didn't publish resolve to the most recent published date and carry published_on_requested_date: false.
  • Value conventionvalue is always quote currency per 1 unit of base currency. Per-100/per-10,000 unit multipliers used by some banks (JPY, IDR) are already normalized away.
  • rate_type — the bank's own price type, preserved as published: reference (single official rate), middle/mid (midpoint), indicative, or buy/sell where the bank publishes both sides (TCMB, BCB, BI, CBN, BCRP, CBBH). Banks publishing buy/sell return one row per side.
  • derived + method — pairs the bank doesn't print directly are computed from its table (inverse or cross via the bank's home currency) and flagged derived: true; what the bank printed is never mixed with what was computed.
  • Publication cadence — most covered banks publish one table per business day. The exceptions: the US Federal Reserve H.10 release is weekly (one rate per business day, released each Monday), the Swiss National Bank publishes monthly averages, UK HMRC publishes one table per calendar month, and the US Treasury one per quarter. The /availability endpoint shows any source's real calendar.

MCP Server

The @allratestoday/mcp-server package lets AI coding tools — Claude Code, Cursor, Claude Desktop, and ChatGPT Desktop — call the AllRatesToday API directly using the Model Context Protocol. Once configured, your assistant gets four new tools without any extra prompt engineering.

Install

Claude Code

claude mcp add allratestoday -- npx -y @allratestoday/mcp-server
claude mcp env allratestoday ALLRATES_API_KEY=art_live_xxxxx

Cursor, Claude Desktop, or ChatGPT Desktop — add the block below to your MCP config (~/.cursor/mcp.json or the desktop app's claude_desktop_config.json). Restart the client after editing.

{
  "mcpServers": {
    "allratestoday": {
      "command": "npx",
      "args": ["-y", "@allratestoday/mcp-server"],
      "env": { "ALLRATES_API_KEY": "art_live_xxxxx" }
    }
  }
}

Tools exposed

ToolAPI key?What it does
get_exchange_ratenoCurrent mid-market rate between two currencies.
get_historical_ratesyesTime series over 1d, 7d, 30d, or 1y.
get_rates_authenticatedyesMulti-target rates and higher limits via /api/v1/rates.
list_currenciesnoAll supported currencies with codes, names, and symbols.

Environment variables

VariableRequired?Purpose
ALLRATES_API_KEYOnly for get_rates_authenticatedBearer token like art_live_xxxxx from your dashboard.
ALLRATES_BASE_URLNoOverride to point at a staging or self-hosted deployment.

Example prompts

  • "What's the USD to EUR rate right now?"
  • "Show me GBP/JPY over the last 30 days."
  • "Convert 2,500 USD to Indian rupees."
  • "List every supported currency."
  • "What's happening in FX markets today?"

Troubleshooting

  • Client doesn't see the tools: restart the MCP client after editing config. Claude Desktop caches the server list.
  • command not found: npx: install Node.js 18+ — npx ships with it.
  • Auth-required tool failing: double-check your ALLRATES_API_KEY. Public tools work without one — test those first to confirm connectivity.

Full setup docs: /docs/mcp-server/. Source & issues: github.com/cahthuranag/mcp-server. Feature overview: /mcp/.

DeepSeek Integration

The Python package allratestoday-deepseek plugs AllRatesToday tools into any deepseek-chat or deepseek-reasoner conversation via OpenAI-compatible function calling.

pip install allratestoday-deepseek
export DEEPSEEK_API_KEY=sk-xxxxx
allratestoday-deepseek --ask "Convert 2500 USD to EUR."

Library usage

from allratestoday_deepseek import DeepSeekCurrencyAgent

with DeepSeekCurrencyAgent() as agent:
    print(agent.ask("How many Japanese Yen is 500 Swiss Francs?"))

Same four tools as the MCP server, plus a dedicated convert_currency tool that fetches the pair rate and multiplies the amount. See the /deepseek/ landing page for details.

LLM Discovery

For browsing-enabled LLMs that don't use MCP or a Custom GPT, AllRatesToday publishes an llms.txt that tells agents exactly which endpoint to call for a live rate:

GET https://allratestoday.com/api/rate?source=USD&target=EUR
# Response: {"rate": 0.92145, "source": "interbank"}

This endpoint is public — no API key, no headers. It's safe to mention in user-facing prompts because it won't leak credentials.

Landing pages under /currency-converter/{from}-to-{to}-rate/ additionally expose a schema.org/ExchangeRateSpecification microdata block with the current rate, so LLM browsers can extract a numeric value without calling the API at all.

React Currency Localizer

Automatically display prices in your user's local currency using IP geolocation. Zero runtime dependencies, intelligent caching, and graceful fallbacks.

npm install react-currency-localizer-realtime

How It Works

StepServiceCacheDescription
1. Detect currency ipapi.co (free, no key) 24h (localStorage) Detects user's local currency from their IP address
2. Fetch rate AllRatesToday API 1h (memory) Gets real-time mid-market exchange rate
3. Convert & display Browser (Intl API) Formats the converted price with currency symbol
Performance First load: 2 API calls. Subsequent loads: 0–1 calls (geo cached). Batch conversion: 1000+ prices in <1ms. Bundle: ~10KB minified (~4KB gzipped). Zero runtime dependencies.

useCurrencyConverter()

HOOK useCurrencyConverter(options)

Convert a single price to the user's local currency. Handles geolocation, rate fetching, caching, and error states automatically.

ParameterTypeDescription
basePricerequired number The price in your base currency
baseCurrencyrequired string ISO 4217 currency code (case-insensitive, e.g. USD or usd)
apiKeyrequired string Your AllRatesToday API key
manualCurrencyoptional string Override auto-detected currency
geoEndpointoptional string Custom geolocation endpoint URL
onSuccessoptional function Callback on successful conversion
onErroroptional function Callback on error

Returns:

PropertyTypeDescription
convertedPricenumber | nullPrice in the user's local currency
localCurrencystring | nullDetected or manual currency code
baseCurrencystringOriginal base currency
exchangeRatenumber | nullExchange rate used
isLoadingbooleanTrue while fetching
errorError | nullError object if failed

Example:

import { useCurrencyConverter } from 'react-currency-localizer-realtime';

function ProductPrice({ price }) {
  const { convertedPrice, localCurrency, isLoading, error } = useCurrencyConverter({
    basePrice: price,
    baseCurrency: 'USD',
    apiKey: 'YOUR_API_KEY',
  });

  if (isLoading) return <span>Loading...</span>;
  if (error) return <span>${price}</span>; // Fallback

  return (
    <span>
      {new Intl.NumberFormat(undefined, {
        style: 'currency',
        currency: localCurrency || 'USD',
      }).format(convertedPrice || price)}
    </span>
  );
}

useCurrencyLocalizer() — Batch Conversion

HOOK useCurrencyLocalizer(options)

Convert multiple prices efficiently with a single exchange rate lookup. Returns convert(), format(), and convertAndFormat() functions.

ParameterTypeDescription
baseCurrencyrequired string ISO 4217 currency code
apiKeyrequired string Your AllRatesToday API key
manualCurrencyoptional string Override detected currency
onReadyoptional function Callback when converter is ready
onErroroptional function Callback on error

Returns:

PropertyTypeDescription
convert(price)number | nullConvert a single price
format(price)stringFormat with currency symbol
convertAndFormat(price)stringConvert + format in one call
isReadybooleanTrue when ready to convert
isLoadingbooleanTrue while fetching
localCurrencystring | nullDetected currency
exchangeRatenumber | nullRate used
errorError | nullError if any

Example — Product list:

import { useCurrencyLocalizer } from 'react-currency-localizer-realtime';

function ProductList({ products }) {
  const { convertAndFormat, isReady } = useCurrencyLocalizer({
    baseCurrency: 'USD',
    apiKey: 'YOUR_API_KEY',
  });

  return (
    <ul>
      {products.map(p => (
        <li key={p.id}>
          {p.name}: {isReady ? convertAndFormat(p.price) : '...'}
        </li>
      ))}
    </ul>
  );
}

Example — Pricing table:

function PricingTable() {
  const plans = [
    { name: 'Basic', price: 9.99 },
    { name: 'Pro', price: 19.99 },
    { name: 'Enterprise', price: 49.99 },
  ];

  const { convertAndFormat, isReady } = useCurrencyLocalizer({
    baseCurrency: 'USD',
    apiKey: 'YOUR_API_KEY',
  });

  return (
    <div>
      {plans.map(plan => (
        <div key={plan.name}>
          <h3>{plan.name}</h3>
          <p>{isReady ? convertAndFormat(plan.price) : '...'}/month</p>
        </div>
      ))}
    </div>
  );
}

<LocalizedPrice /> Component

COMPONENT <LocalizedPrice />

Drop-in React component that displays a price converted to the user's local currency. Handles loading, errors, and formatting automatically.

PropTypeDescription
basePricerequired number Price in base currency
baseCurrencyrequired string ISO 4217 code (case-insensitive)
apiKeyrequired string Your AllRatesToday API key
manualCurrencyoptional string Override detected currency
loadingComponentoptional ReactNode Custom loading UI
errorComponentoptional function Custom error UI (receives error, basePrice, baseCurrency). If not provided, shows original price as fallback.
formatPriceoptional function Custom formatter: (price, currency) => string

Basic usage:

import { LocalizedPrice } from 'react-currency-localizer-realtime';

// Keyless — auto-detects currency, free daily ECB rates, shows fallback on error
<LocalizedPrice basePrice={99.99} baseCurrency="USD" />

// With a key — real-time rates, 160+ currencies
<LocalizedPrice basePrice={99.99} baseCurrency="USD" apiKey="YOUR_API_KEY" />

Custom format:

// Custom formatting for subscription pricing
<LocalizedPrice
  basePrice={19.99}
  baseCurrency="USD"
  apiKey="YOUR_API_KEY"
  formatPrice={(price, currency) => `${currency} ${price.toFixed(2)}/month`}
/>

Custom loading and error:

<LocalizedPrice
  basePrice={99.99}
  baseCurrency="USD"
  apiKey="YOUR_API_KEY"
  loadingComponent={<span>Converting...</span>}
  errorComponent={(error, basePrice) => (
    <span>${basePrice} <small>(conversion unavailable)</small></span>
  )}
/>

Manual currency with selector:

function CurrencySelector() {
  const [currency, setCurrency] = useState('');

  return (
    <div>
      <select value={currency} onChange={e => setCurrency(e.target.value)}>
        <option value="">Auto-detect</option>
        <option value="USD">USD</option>
        <option value="EUR">EUR</option>
        <option value="GBP">GBP</option>
        <option value="JPY">JPY</option>
      </select>

      <LocalizedPrice
        basePrice={99.99}
        baseCurrency="USD"
        apiKey="YOUR_API_KEY"
        manualCurrency={currency || undefined}
      />
    </div>
  );
}
SSR Note When using with Next.js or other SSR frameworks, IP geolocation runs on the server and detects the server's location. Use manualCurrency for server rendering and auto-detect on the client:
const [isClient, setIsClient] = useState(false);
useEffect(() => setIsClient(true), []);

<LocalizedPrice
  basePrice={99.99}
  baseCurrency="USD"
  apiKey="YOUR_API_KEY"
  manualCurrency={!isClient ? 'USD' : undefined}
/>
Environment Variables Store your API key in environment variables: VITE_ALLRATESTODAY_KEY (Vite) • REACT_APP_ALLRATESTODAY_KEY (CRA) • NEXT_PUBLIC_ALLRATESTODAY_KEY (Next.js)

Errors

Every error is a JSON object with an error string, and sometimes a hint or extra context. The shape never changes with the status code, so one handler covers all of them.

{ "error": "Authentication required. Provide an API key via Authorization header or log in." }
Branch on the status code, not on the message text. Messages are written for humans and get reworded; the status codes below are the contract.
StatusWhenWhat to do
400 An unsupported ?format=, a negative or non-numeric amount, amount combined with several targets, a malformed date, or from later than to. Fix the request. Retrying identically will always fail. Format errors are returned before authentication, so a 400 here never means your key is wrong.
401 No Authorization header, a key that does not exist, or a key that has been disabled or revoked. Also returned by the retired /api/public/rates. Check the header format is exactly Bearer <key>. If the key was working yesterday, confirm it has not been rotated from the profile page.
403 The endpoint needs a paid plan — central-bank /history and /{date} — or a browser-restricted key was used from an unapproved origin. Not a retry case. Upgrade, or switch to /latest, which is available on every plan.
404 An unknown central bank code ({ "error": "Unknown central bank: xyz" }), or a path that is not an endpoint at all — a non-existent path returns the HTML 404 page, not JSON. List valid codes from /api/v1/central-banks. If you got HTML back, the URL is wrong — check for /api/convert and friends, which do not exist.
429 Your request allowance is spent. See Rate Limits & Quotas. Do not retry or back off — this is a quota, not a throttle, and it will keep failing until resets_at. Serve a cached rate and alert. There is no Retry-After header; use resets_at from the body.
500 An unexpected failure on our side, or a missing service configuration. Retry once after a short delay. If it persists, check status.allratestoday.com and email support with the timestamp.
502 The upstream market-data provider failed or has no quote for that pair ({ "error": "Rate unavailable for that pair" }). Safe to retry with backoff — these are usually transient. If one specific pair fails consistently, it is likely not quoted; try routing via USD.
503 Temporarily unavailable, typically during an incident. Retry with exponential backoff and fall back to your last cached rate.

A handler that covers all of them

async function getRate(from, to) {
  const res = await fetch(
    `https://allratestoday.com/api/v1/rates?source=${from}&target=${to}`,
    { headers: { Authorization: `Bearer ${process.env.ART_API_KEY}` } }
  );

  if (res.ok) return (await res.json())[0].rate;

  const { error } = await res.json().catch(() => ({ error: res.statusText }));

  switch (res.status) {
    case 400:
    case 404:
      throw new Error(`Bad FX request: ${error}`);      // a bug — fix the call
    case 401:
    case 403:
      throw new Error(`FX credentials: ${error}`);       // page someone
    case 429:
      return cache.get(`${from}${to}`);                  // quota gone; serve stale
    default:
      return retryWithBackoff(() => getRate(from, to)); // 5xx — transient
  }
}

Whatever you do with an error, keep a last-known-good rate. FX is a dependency in a payment path; failing a checkout because a rate lookup returned 502 is almost never the right trade.

Response Formats

Every table endpoint returns JSON by default and accepts ?format= with one of json, csv, xml or xlsx. The rows are identical in every format — only the encoding changes.

ValueContent typeUse it for
jsonapplication/jsonThe default, and what every SDK uses.
csvtext/csvDownloadable CSV with a UTF-8 BOM, so currency symbols and non-ASCII names open correctly in Excel rather than as mojibake.
xlsxapplication/vnd.openxmlformats-…A real Excel workbook, not a renamed CSV: dates arrive as dates and rates keep full precision, so sorting and filtering behave.
xmlapplication/xmlThe same fields as the JSON payload, for ERP and legacy pipelines that cannot consume JSON.

Supported on: /api/v1/rates, /api/v1/symbols, /api/historical-rates, /api/v1/central-banks, and the central-bank /latest, /history and /availability endpoints.

curl "https://allratestoday.com/api/v1/central-bank/ecb/history?source=USD&target=EUR&from=2026-01-01&format=xlsx" \
  -H "Authorization: Bearer YOUR_API_KEY" -o ecb-usd-eur.xlsx
  • An unsupported value returns 400 before authentication is checked, so a typo in format never looks like an auth failure — and never costs a request.
  • format is ignored when amount is used on /api/v1/rates: a conversion is a single object, not a table, and always comes back as JSON.
  • A non-JSON response is still charged against your quota exactly once, and an xlsx of a year of history is billed by range like any other history call.
  • Each coverage page also offers its published table as a one-click Excel or CSV download with no API key at all — see any central bank or tax authority page.

Caching

Rates are quoted per request, so the cheapest integration is one that does not call us for every page view. Caching is the single biggest lever on your quota.

DataWe sendSensible client cache
Live rates (/api/v1/rates, /api/rate)public, max-age=6060 seconds. The underlying market data refreshes on roughly that cadence, so a shorter cache buys precision you cannot observe.
Currency list (/api/v1/symbols)public, max-age=86400A day, or bake it into your build. It is keyless, so this costs you nothing either way.
Mid-market historyUntil the next daily close. Yesterday's closes never change.
Official central-bank ratesIndefinitely. A published rate_date is immutable by definition — once you have the ECB's rate for 2026-06-30, it will never differ. Cache it forever and only ever fetch dates you do not hold.
The pattern that saves the most quota Refresh rates on a schedule, not on demand. One cron job every minute writing to a shared cache costs ~44,000 requests a month no matter how much traffic you have; calling the API from each request scales your bill with your traffic. If you display prices in many currencies, fetch them as one comma-separated target call per refresh.

Only cache a rate as far as your use allows: for display, a minute is invisible; for a booked transaction, store the exact time and rate you used, and never re-derive a historical figure from a cached live rate.

CORS & Browser Use

These endpoints send Access-Control-Allow-Origin: * and are callable cross-origin from a browser:

EndpointKey needed?
/api/v1/symbolsNo — fully keyless
/api/rateYes, via header or ?key=
/api/open/central-bank/{bank}, /api/open/geoNo — the open endpoints behind the widget and React localizer
/api/widget/rateNo — widget-only
/api/openapi.jsonNo

/api/v1/rates, /api/historical-rates and every /api/v1/central-bank/… path do not send permissive CORS headers; a cross-origin fetch to them from a third-party site is blocked by the browser.

But CORS is not the real objection, and /api/rate being callable from a browser is not an invitation to do it: a key in browser JavaScript is a public key. Anyone can read it from the network tab and spend your quota. Call the API from your server and expose your own endpoint to your frontend:

// server.js — your backend holds the key
app.get('/fx/:from/:to', async (req, res) => {
  const r = await fetch(
    `https://allratestoday.com/api/v1/rates?source=${req.params.from}&target=${req.params.to}`,
    { headers: { Authorization: `Bearer ${process.env.ART_API_KEY}` } }
  );
  res.set('Cache-Control', 'public, max-age=60').json(await r.json());
});

If you genuinely need rates in a page with no backend, the supported options are the embeddable widget and the keyless React Currency Localizer, both of which are built for it. For a marketing page or a dashboard, those are usually the right answer.

Versioning & Changes

The API is versioned in the path. /api/v1/… is the current and only version; v1 paths will not change shape underneath you.

  • Additive changes ship without notice. New fields, new endpoints, new central banks and new format values can appear at any time. Parse defensively: ignore fields you do not recognise rather than validating against a closed schema, and do not assume a fixed number of keys in a response object.
  • Breaking changes get a new version path and an email to every account using the affected endpoint before the old one is retired.
  • Legacy unversioned paths/api/rate and /api/historical-rates — remain supported. New integrations should prefer the /api/v1/ equivalents where one exists.
  • Retired: the keyless /api/public/rates now returns 401 with a pointer to registration. If you are still calling it, move to /api/v1/rates with a free key.

The machine-readable contract is the OpenAPI specification — generate a client from it rather than hand-writing one. Coverage and behaviour are also published as a versioned PDF on the API specifications page, which is the document to hand an auditor or a procurement team.

Service Availability

Current system health, historical uptime, and incident reports are published on our status page:

status.allratestoday.com →

  • Live status for the website, authenticated rates API, API documentation, and pricing & billing, updated automatically by independent monitoring.
  • Historical daily uptime records per component — the 99.9% figure on our homepage is measured, not promised.

Planned maintenance is announced in advance on the status page. During an incident, check there first — it is hosted separately from the API, so it stays up even if the API does not.

Data Freshness

AllRatesToday provides real-time exchange rates sourced from institutional-grade forex data providers including institutional interbank market data. Unlike other providers that update once every 60 minutes, our rates are fetched live on every request, ensuring you always get the most current mid-market rates available.

This section describes the mid-market endpoints. Official central-bank and tax-authority rates follow the publisher's calendar instead — one table per day, week, month, or quarter, fixed once published. See Central Bank Rates and the comparison in Overview.

Real-Time Updates Rates sourced from institutional interbank market data — no delayed or batched updates.

Supported Currencies

160 currencies, including:

Major Currencies USD, EUR, GBP, JPY, CHF, CAD, AUD, NZD
Popular Currencies INR, CNY, BRL, MXN, RUB, TRY, ZAR, SGD, HKD, KRW, THB, PHP, PKR, BDT, LKR, NGN, GHS, KES, AED, SAR, EGP, and more

See the full list of all supported currencies with codes, names, and symbols. Also available via the OpenAPI specification. Prefer clicking around? Try every endpoint live in the API Playground.

Official SDKs

Install our official SDK for your language. All SDKs support free and authenticated endpoints, currency conversion, and historical rates.

Need official central-bank rates instead of mid-market? There is one zero-dependency npm package per covered central bank and tax authority (ecb-exchange-rate, boe-exchange-rate, fed-exchange-rate, …), all sharing the same four functions. See the bank SDK index for every package with installation and API reference.

JavaScript / TypeScript (npm)

npm install @allratestoday/sdk
import AllRatesToday from '@allratestoday/sdk';

const client = new AllRatesToday({ apiKey: 'art_live_...' });

// Get latest rates (multiple currencies in one call)
const { rates } = await client.latest({ base: 'USD', symbols: ['EUR', 'GBP', 'JPY'] });
console.log(rates); // { EUR: 0.9234, GBP: 0.7891, JPY: 151.42 }

// Convert an amount
const result = await client.convert('USD', 'EUR', 1000);
console.log(`$1,000 = €${result.result}`);

// Historical conversion at a specific date
const past = await client.convert('USD', 'EUR', 1000, { date: '2026-01-15' });

// Rates for a specific date
const data = await client.forDate('2026-01-15', { base: 'EUR', symbols: ['USD', 'GBP'] });

// Time series (custom date range)
const series = await client.timeSeries('2026-01-01', '2026-03-31', {
  base: 'USD', symbols: ['EUR']
});

// List all supported currencies
const { symbols } = await client.symbols();
console.log(symbols); // { USD: 'United States Dollar', EUR: 'Euro', ... }

// Historical rates by period
const history = await client.getHistoricalRates('USD', 'EUR', '30d');

Python (pip)

pip install allratestoday
from allratestoday import AllRatesToday

client = AllRatesToday(api_key="art_live_...")

# Get exchange rate
rate = client.get_rate("USD", "EUR")
print(f"1 USD = {rate['rate']} EUR")

# Convert amount
result = client.convert("USD", "EUR", 1000)
print(f"$1,000 = €{result['result']}")

# Historical rates
history = client.get_historical_rates("USD", "EUR", "30d")

PHP (Composer)

composer require allratestoday/sdk
use AllRatesToday\AllRatesToday;

$client = new AllRatesToday('art_live_...');

// Get exchange rate
$rate = $client->getRate('USD', 'EUR');
echo "1 USD = {$rate['rate']} EUR";

// Convert amount
$result = $client->convert('USD', 'EUR', 1000);
echo "$1,000 = €{$result['result']}";

// Historical rates
$history = $client->getHistoricalRates('USD', 'EUR', '30d');

React (npm)

npm install react-currency-localizer-realtime
import { LocalizedPrice } from 'react-currency-localizer-realtime';

// Automatically detects the visitor's currency. No API key needed:
// keyless mode uses free daily ECB rates (~30 currencies) and renders
// a "Rates by AllRatesToday" link. Pass apiKey for real-time + 160 currencies.
function PricingCard() {
  return (
    <div>
      <h3>Pro Plan</h3>
      <LocalizedPrice basePrice={19.99} baseCurrency="USD" />
    </div>
  );
}
import { useCurrencyConverter } from 'react-currency-localizer-realtime';

// Hook-based API for full control
function ProductPrice({ price }) {
  const { convertedPrice, localCurrency, isLoading } = useCurrencyConverter({
    basePrice: price,
    baseCurrency: 'USD',
    apiKey: 'art_live_...',
  });

  if (isLoading) return <span>Loading...</span>;

  return (
    <span>
      {new Intl.NumberFormat(undefined, {
        style: 'currency',
        currency: localCurrency || 'USD',
      }).format(convertedPrice || price)}
    </span>
  );
}
import { useCurrencyLocalizer } from 'react-currency-localizer-realtime';

// Batch conversion for product lists
function ProductList({ products }) {
  const { convertAndFormat, isReady } = useCurrencyLocalizer({
    baseCurrency: 'USD',
    apiKey: 'art_live_...',
  });

  return (
    <ul>
      {products.map(p => (
        <li key={p.id}>{p.name}: {isReady ? convertAndFormat(p.price) : '...'}</li>
      ))}
    </ul>
  );
}

React SDK features: Automatic currency detection via IP geolocation, intelligent caching (24h for geo, 1h for rates), manual currency override, custom formatters, graceful fallbacks, and zero runtime dependencies beyond React.

Code Examples (without SDK)

JavaScript / Node.js

const response = await fetch(
  'https://allratestoday.com/api/v1/rates?source=USD&target=EUR',
  { headers: { 'Authorization': 'Bearer YOUR_API_KEY' } }
);
const data = await response.json();
console.log(`1 USD = ${data.rate} EUR`);

Python

import requests

response = requests.get(
    'https://allratestoday.com/api/v1/rates',
    params={'source': 'USD', 'target': 'EUR'},
    headers={'Authorization': 'Bearer YOUR_API_KEY'}
)
data = response.json()
print(f"1 USD = {data['rate']} EUR")

PHP

$opts = {'http' => {'header' => 'Authorization: Bearer YOUR_API_KEY'}};
$context = stream_context_create($opts);
$response = file_get_contents(
    'https://allratestoday.com/api/v1/rates?source=USD&target=EUR',
    false, $context
);
$data = json_decode($response, true);
echo "1 USD = " . $data['rate'] . " EUR";

cURL

curl "https://allratestoday.com/api/v1/rates?source=USD&target=EUR" \
  -H "Authorization: Bearer YOUR_API_KEY"

API Playground

Try the API directly from your browser. Enter your API key to test.

GET /api/v1/rates?source=USD&target=EUR&amount=100
Click "Send Request" to see the live response...
OpenAPI Specification Full machine-readable spec available at /openapi.json — use it to auto-generate client libraries, or explore it interactively in the API Playground.

Run in Postman

Fork our Postman collection to quickly test all API endpoints.

Ready to integrate?

Get your free API key and start making requests in seconds.

Get Free API Key