Tutorial/Python quickstart
Tutorial

How to get exchange rates in Python

Read live and historical FX rates in Python with a few lines of code. No key to start, 50,000 calls a month once you sign up, and every response tells you how fresh the rate is.

MMexchangerate.dev·Jun 19, 2026·5 min read

The shortest path to exchange rates in Python is a GET request to /v1/latest/USD. You get back JSON with rates for 31 currencies plus two freshness fields, source and market_session. No API key is required to make your first call.

Key points
One GET to /v1/latest/{base} returns rates for 31 currencies as JSON.
Every response carries source and market_session, so you know how fresh each rate is.
The free tier is 50,000 calls a month at 30 requests a minute, no card required.
Rates are indicative, published for reference and analytics, not as a dealing quote.

Your first call, no dependencies

You need nothing beyond the standard library. urllib.request handles a single call:

python · standard librarycopy
import json
import urllib.request

url = "https://api.exchangerate.dev/v1/latest/USD"
with urllib.request.urlopen(url) as resp:
    data = json.load(resp)

print(data["rates"]["EUR"])     # 0.87531
print(data["source"])            # ecb_daily
print(data["market_session"])    # open

That runs without a key. Anonymous calls are capped per IP address, so for anything past a quick test you want a free key.

With requests and an API key

Most projects already use requests. Pass your key as a bearer token:

python · requestscopy
import requests

API = "https://api.exchangerate.dev/v1"
KEY = "exr_live_..."   # free key at https://exchangerate.dev/signup

resp = requests.get(
    f"{API}/latest/USD",
    headers={"Authorization": f"Bearer {KEY}"},
    timeout=10,
)
resp.raise_for_status()
data = resp.json()

print(data["rates"]["GBP"], data["market_session"])

A free key raises your limit to 50,000 calls a month at 30 requests a minute. The X-API-Key header works too, for platforms that cannot set Authorization.

Convert an amount

To convert rather than list rates, call /v1/convert. It returns the rate and the converted amount together:

python · convert 100 USD to EURcopy
r = requests.get(
    f"{API}/convert/USD/EUR/100",
    headers={"Authorization": f"Bearer {KEY}"},
).json()

print(r["rate"])         # 0.87572
print(r["converted"])    # 87.57

Know how fresh a rate is

Two fields on every response tell you what you are looking at. source is the data class: live for aggregated spot, ecb_daily for the European Central Bank reference fix, fred_daily for the Federal Reserve daily series. market_session says whether the FX day is open, weekend, or between sessions.

Field valueWhat it meansWhen it moves
source: liveAggregated spot consensusThrough the week and on weekends
source: ecb_dailyOfficial reference fixOnce per business day
market_session: weekendSaturday or SundayLive moves; the reference fix is frozen
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. Every response carries this in its notice field.

Read a single past day

Ask for any date back to 1999 by putting it in the path. The response adds is_forward_filled, which is true when no rate was published that day, such as a weekend or holiday:

python · rate on a past datecopy
r = requests.get(
    f"{API}/2026-03-14/USD",
    headers={"Authorization": f"Bearer {KEY}"},
).json()

print(r["rates"]["JPY"], r["is_forward_filled"])

For a full series across a date range in one call, use /v1/range with start_date and end_date. A separate guide covers that.

MM
exchangerate.dev
Integration guides for developers.

Keep reading

TutorialCurrency conversion in JavaScript and Node.jsRead GuideHistorical FX rates and time series in one callRead ReferenceReading source and market_sessionRead