The Frankfurter API: Pull ECB Exchange Rates as JSON (No Key, No Rate Limits)

Written by

in

I needed to backfill three years of EUR/USD daily closes for a P&L report last month. My first instinct was the usual: sign up for some FX data vendor, wait for the API key email, paste it into a .env file, then discover the free tier caps me at 100 requests a month and doesn’t include historical data anyway. I’ve done this dance a dozen times. This time I didn’t.

The Frankfurter API gives you European Central Bank reference rates as clean JSON. No key, no signup, no rate limit that I’ve ever hit. It pulls from the ECB’s daily reference rates, which are the same numbers your bank and half the finance industry quote against. Here’s how it works and where it bites.

The one request that does 90% of the job

Latest rates, base USD, a couple of currencies:

curl "https://api.frankfurter.dev/v1/latest?base=USD&symbols=EUR,GBP,JPY"

You get back exactly what you’d hope for:

{
  "amount": 1.0,
  "base": "USD",
  "date": "2026-07-22",
  "rates": { "EUR": 0.87658, "GBP": 0.74807, "JPY": 163.07 }
}

Drop the symbols param and you get every currency the ECB tracks (about 30). Drop base and it defaults to EUR, since that’s the ECB’s native quote currency. The amount field lets you convert a specific sum in one shot — ?amount=250&base=USD&symbols=EUR tells you what 250 dollars is in euros without you doing the multiply.

Historical rates on a single date

Swap latest for an ISO date and you get that day’s fixing:

curl "https://api.frankfurter.dev/v1/2020-01-01?base=USD&symbols=EUR"
# {"amount":1.0,"base":"USD","date":"2019-12-31","rates":{"EUR":0.89015}}

Notice the returned date is 2019-12-31, not the Jan 1 I asked for. That’s the first real gotcha: the ECB doesn’t publish on weekends or TARGET holidays, so Frankfurter rolls back to the last available business day. New Year’s Day has no fixing, so you get December 31st. This is correct behavior, but if you’re joining this against your own date series, align on the returned date, not the one you requested, or you’ll double-count or drop rows.

Time series — the part I actually came for

This is where the paid vendors usually put up a paywall. Frankfurter just hands it over with a date range using ..:

curl "https://api.frankfurter.dev/v1/2024-01-01..2024-01-05?base=USD&symbols=EUR"
{
  "amount": 1.0,
  "base": "USD",
  "start_date": "2023-12-29",
  "end_date": "2024-01-05",
  "rates": {
    "2023-12-29": { "EUR": 0.90498 },
    "2024-01-02": { "EUR": 0.91274 },
    "2024-01-03": { "EUR": 0.91583 },
    "2024-01-04": { "EUR": 0.91299 },
    "2024-01-05": { "EUR": 0.91567 }
  }
}

Weekends are simply absent — there’s no Dec 30/31 or Jan 1 in that response because there was no ECB fixing. You can leave the end date open (2024-01-01..) to pull everything up to today. For a full multi-year backfill that’s one HTTP call, and the payload is small because it’s just floats keyed by date.

Here’s the Python I used to turn that into a pandas frame:

import requests, pandas as pd

url = "https://api.frankfurter.dev/v1/2021-01-01..?base=USD&symbols=EUR,GBP,JPY"
data = requests.get(url).json()["rates"]

df = pd.DataFrame(data).T                # dates become the index
df.index = pd.to_datetime(df.index)
df = df.sort_index()
print(df.tail())

The .T transpose matters because the JSON is keyed date → currency → rate, and DataFrame reads the outer keys as columns by default. Three lines and I had a clean daily series I could reindex to a business-day calendar and forward-fill for the missing holidays.

Where it doesn’t fit

Frankfurter is ECB reference data, so know what that means before you wire it into anything:

  • One price per day, not intraday. The ECB publishes a single reference rate around 16:00 CET. If you need tick data or an FX rate at 09:31:04, this is the wrong tool. It’s for reporting, accounting, and backtests on daily bars — not for trading execution.
  • It’s a reference, not a tradeable quote. There’s no bid/ask spread here. Don’t use it to mark a live position you’d actually close at market.
  • Currency coverage is ECB’s list. Majors and most liquid crosses are there. Exotic or pegged currencies the ECB doesn’t track won’t appear. No crypto either.
  • Rates update once a day, on business days. If your cron hits it at 08:00 CET you’re getting yesterday’s fixing until the new one posts.

For the report I was building — convert historical foreign revenue to USD at each day’s official rate — those constraints are exactly what I wanted. Auditors like ECB reference rates precisely because there’s one unambiguous number per day.

Why I trust a keyless API here

I’m usually suspicious of “no key required” services because the business model is often “we’ll add a paywall once you depend on us.” Frankfurter is open source and the data underneath is the ECB’s public feed, which isn’t going anywhere. If the hosted instance ever disappears, you can self-host it against the same ECB XML and change one hostname. That’s the kind of dependency I’m comfortable building on — the same reason I lean on other keyless government endpoints like SEC EDGAR and the Treasury FiscalData API instead of commercial data brokers.

If you’re doing this kind of number-crunching regularly, a second monitor pays for itself the first time you’re diffing a rate series against a spreadsheet. I run a cheap Dell 27-inch IPS monitor as a dedicated data pane (full disclosure: affiliate link). Overkill for one API, worth it once you’ve got three terminals of JSON open.

The whole thing in one script

import requests

def convert(amount, frm, to, date="latest"):
    url = f"https://api.frankfurter.dev/v1/{date}?base={frm}&symbols={to}"
    r = requests.get(url).json()
    rate = r["rates"][to]
    return round(amount * rate, 2), r["date"]

usd, on = convert(1000, "USD", "EUR", "2023-06-15")
print(f"$1000 = €{usd} at the ECB fix on {on}")

No key to rotate, no dashboard to log into, no free-tier counter ticking down. For daily FX in reports and backtests, this is the first thing I reach for now.


Join https://t.me/alphasignal822 for free market intelligence.

📧 Get weekly insights on security, trading, and tech. No spam, unsubscribe anytime.

Comments

Leave a Reply

Your email address will not be published. Required fields are marked *

Also by us: StartCaaS — AI Company OS · Hype2You — AI Tech Trends