Guide/Exchange rate API on Stack Overflow
Guide

Exchange rate API on Stack Overflow: developer troubleshooting, answered

The FX-API errors developers hit on Stack Overflow, fixed: 401 auth, 429 rate limits, CORS from the browser, stale weekend rates, converting an amount, and pulling historical or time-series data.

MMexchangerate.dev·Jun 30, 2026·6 min read

When an integration breaks, developers paste the error into Stack Overflow. For an exchange rate API the questions are almost always the same: a rejected key, a rate-limit wall, a CORS error, or a rate that looks stale over the weekend. Here are direct fixes, using exchangerate.dev as the worked example. Every snippet is a real call against https://api.exchangerate.dev.

Key points
A 401 almost always means a missing Bearer prefix or a key with a stray newline from copy-paste.
Read X-RateLimit-Remaining and back off; the free tier is 12 requests a minute.
Never call the API from front-end JS with your key — proxy it through your backend.
source and market_session on every response tell you exactly why a rate is not moving.

The base URL is https://api.exchangerate.dev. The first call works anonymously (capped per IP), so you can reproduce any of these before signing up for a free key.

401 Unauthorized — the key is rejected

The key goes in the Authorization header as a bearer token, and the word Bearer with a trailing space has to be present. Keys are prefixed exr_live_.

curl · authenticatedcopy
curl https://api.exchangerate.dev/v1/latest/USD \
  -H "Authorization: Bearer exr_live_YOUR_KEY"

The usual causes of a 401: the Bearer prefix is missing, the key picked up a stray newline or quote from a copy-paste, or the env var holding it is not loaded. Platforms that cannot set Authorization can send the key as an X-API-Key header instead.

429 Too Many Requests — handling rate limits

Every response carries X-RateLimit-Remaining. Read it and back off before it reaches zero rather than polling blind. The free tier is 12 requests a minute, Basic is 120, Pro is 500. You can check your remaining quota and monthly reset at any time with GET /v1/account. A reference rate does not change every second, so a short client-side cache usually keeps you well inside the limit.

CORS error — calling the API from the browser

Do not call the API directly from front-end JavaScript with your key: it exposes exr_live_... to anyone who opens devtools, and the browser will block it on CORS. Proxy the call through your own backend, keep the key server-side, and have the browser hit your endpoint.

javascript · your backend routecopy
// the key never reaches the browser
const r = await fetch("https://api.exchangerate.dev/v1/latest/USD", {
  headers: { Authorization: `Bearer ${process.env.EXCHANGERATE_API_KEY}` },
});
const data = await r.json();

The rate looks stale or will not change on weekends

This is expected, and the response tells you why. Sixteen currencies reprice live (~60s on trading days); the rest are daily reference rates from the ECB and FRED. Over a weekend the interbank market is closed, so the live feed pauses and the reference fix carries Friday's value. Two fields make this explicit:

Field valueWhat it meansWhen it moves
source: liveAggregated spot consensusIntraday (~60s), trading week
source: ecb_dailyOfficial reference fixOnce per business day
market_session: weekendInterbank market closedLive feed paused; reference carries Friday

How do I convert an amount, not just read a rate?

Use /v1/convert/{from}/{to}/{amount}. It returns the rate and the converted amount together, so you do not multiply by hand:

curl · convert 100 USD to EURcopy
curl https://api.exchangerate.dev/v1/convert/USD/EUR/100 \
  -H "Authorization: Bearer exr_live_YOUR_KEY"

How do I get historical or time-series data?

For a single past day, put the date in the path: GET /v1/{YYYY-MM-DD}/{base}, back to 1999-01-04. For a full series across a range in one call, use GET /v1/range with start_date and end_date; it uses keyset pagination, so follow the cursor rather than requesting huge ranges in one shot.

Migrating from Frankfurter and hitting errors?

The request parameters are Frankfurter-compatible, so most migrations are a base-URL swap with no code rewrite. Where responses differ, this API adds fields (source, market_session, notice) rather than removing them. The migrating-from-Frankfurter guide has the exact mapping.

The shortest call that works

No key, no dependencies:

curl · no keycopy
curl https://api.exchangerate.dev/v1/latest/USD

You get back the rates plus source and market_session so you know how fresh each one is. A free key raises the limit to 10,000 calls a month and takes a minute.

Indicative, not for settlement
Rates are published for reference, analytics, and display. They are not a dealing quote and should not be used to settle a trade. Displaying them in a product you ship requires the Pro plan; Free and Basic are for internal use.
MM
exchangerate.dev
Integration guides for developers.

Keep reading

GuideExchange rate API on Reddit: the developer questionsRead ComparisonFree exchange rate APIs comparedRead GuideMigrating from Frankfurter without a rewriteRead