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.
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.
Bearer prefix or a key with a stray newline from copy-paste.X-RateLimit-Remaining before the limit. On a 429, read X-RateLimit-Scope and Retry-After.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_.
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
Successful metered responses carry X-RateLimit-Remaining. A 429 supplies Retry-After; respect that value instead of assuming every limit resets after 60 seconds. Read X-RateLimit-Scope to see whether you hit the minute limit, anonymous hourly cap, or monthly quota. The free tier is 12 requests a minute, Basic is 120, and Pro is 500.
CORS error — calling the API from the browser
CORS permits anonymous reads and the Authorization and X-API-Key headers. That does not make a keyed browser request private: anyone who opens devtools can copy exr_live_.... Anonymous calls are fine for evaluation. For an account-attributed production call, proxy through your backend and keep the key server-side.
How should I cache exchange rates safely?
Cache a complete successful observation: rate, source, market_session, and data_updated_at. For actively traded pairs, start with 60 seconds on the server. That cuts duplicate calls. It does not make a daily reference rate fresher, so keep the observation fields beside the number.
- Batch currencies into one
symbolsrequest instead of caching one HTTP call per pair. - Cache successful 2xx responses. Do not store a 401, 429, or upstream error as though it were a rate.
- On 429, use
Retry-AfterandX-RateLimit-Scope; do not invent a fixed retry delay. - Keep account keys in server-side configuration, never in a public browser cache or bundle.
The rate looks stale or will not change on weekends
This is expected, and the response tells you why. Actively traded currencies reprice live (~60s on trading days); current coverage comes from the API rather than a fixed marketing count, and the rest use daily reference rates from the ECB and FRED. Over a weekend the interbank market is closed, so the live feed pauses and reference fixes carry their last published value. Two fields make this explicit:
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:
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 another FX API and hitting errors?
Request parameters follow common FX API conventions (base currency plus a symbols filter), 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 — check any response-parsing code for a fixed key-set assumption.
The shortest call that works
No key, no dependencies:
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.