DEV Community

Alex Spinov
Alex Spinov

Posted on

ExchangeRate-API Has a Free Endpoint — Get Live Currency Rates Without an API Key

Most currency APIs want your email, your credit card, and a monthly commitment before you can test a single rate. ExchangeRate-API has a free open endpoint that requires none of that.

One URL. No key. 166 currencies. Updated daily.

https://open.er-api.com/v6/latest/USD
Enter fullscreen mode Exit fullscreen mode

That's it. Call it right now from your terminal:

curl https://open.er-api.com/v6/latest/USD
Enter fullscreen mode Exit fullscreen mode

You'll get back:

{
  "result": "success",
  "base_code": "USD",
  "time_last_update_utc": "Thu, 26 Mar 2026 00:02:31 +0000",
  "time_next_update_utc": "Fri, 27 Mar 2026 00:02:31 +0000",
  "rates": {
    "EUR": 0.863827,
    "GBP": 0.747511,
    "JPY": 159.204596,
    "CAD": 1.380053,
    "AUD": 1.438717,
    "CHF": 0.791328,
    "CNY": 7.257342,
    "INR": 84.123456
  }
}
Enter fullscreen mode Exit fullscreen mode

166 currencies in one request. No auth headers. No rate limit errors to handle.

Change the base currency

Swap USD for any supported currency code:

curl https://open.er-api.com/v6/latest/EUR
curl https://open.er-api.com/v6/latest/GBP
curl https://open.er-api.com/v6/latest/JPY
Enter fullscreen mode Exit fullscreen mode

The response always gives you rates relative to your chosen base.

Python: currency converter in 15 lines

import requests

def convert(amount: float, from_currency: str, to_currency: str) -> float:
    url = f"https://open.er-api.com/v6/latest/{from_currency.upper()}"
    response = requests.get(url)
    response.raise_for_status()

    data = response.json()

    if data["result"] != "success":
        raise ValueError(f"API error: {data}")

    rate = data["rates"].get(to_currency.upper())
    if not rate:
        raise ValueError(f"Currency not found: {to_currency}")

    return amount * rate

# Examples
print(f"$100 USD = €{convert(100, 'USD', 'EUR'):.2f} EUR")
print(f"£50 GBP = ${convert(50, 'GBP', 'USD'):.2f} USD")
print(f"¥10000 JPY = ${convert(10000, 'JPY', 'USD'):.2f} USD")
Enter fullscreen mode Exit fullscreen mode

Output:

$100 USD = €86.38 EUR
£50 GBP = $66.93 USD
¥10000 JPY = $62.81 USD
Enter fullscreen mode Exit fullscreen mode

JavaScript version

async function convertCurrency(amount, from, to) {
  const response = await fetch(
    `https://open.er-api.com/v6/latest/${from.toUpperCase()}`
  );
  const data = await response.json();

  if (data.result !== 'success') {
    throw new Error('API request failed');
  }

  const rate = data.rates[to.toUpperCase()];
  if (!rate) throw new Error(`Unknown currency: ${to}`);

  return (amount * rate).toFixed(2);
}

// Usage
convertCurrency(100, 'USD', 'EUR').then(result => {
  console.log(`$100 USD = €${result} EUR`);
});
Enter fullscreen mode Exit fullscreen mode

What the time_next_update_utc field tells you

The API updates rates once per day. The time_next_update_utc field shows exactly when the next update happens. Use it to avoid unnecessary calls:

import requests
from datetime import datetime, timezone

def get_rates_with_cache(base: str = "USD") -> dict:
    url = f"https://open.er-api.com/v6/latest/{base}"
    data = requests.get(url).json()

    next_update = data["time_next_update_unix"]
    now = datetime.now(timezone.utc).timestamp()

    # Data is fresh — show when it updates next
    minutes_until_refresh = int((next_update - now) / 60)
    print(f"Rates current. Next update in ~{minutes_until_refresh} minutes")

    return data["rates"]

rates = get_rates_with_cache("USD")
Enter fullscreen mode Exit fullscreen mode

Cache the response and only re-fetch after time_next_update_unix. You'll cut your API calls to 1/day.

Build a multi-currency price display

import requests

def price_in_currencies(usd_price: float, currencies: list) -> dict:
    data = requests.get("https://open.er-api.com/v6/latest/USD").json()
    rates = data["rates"]

    return {
        currency: round(usd_price * rates[currency], 2)
        for currency in currencies
        if currency in rates
    }

price = price_in_currencies(29.99, ["EUR", "GBP", "JPY", "CAD", "AUD", "INR"])
for currency, amount in price.items():
    print(f"  {currency}: {amount}")
Enter fullscreen mode Exit fullscreen mode

Output:

  EUR: 25.90
  GBP: 22.43
  JPY: 4773.84
  CAD: 41.38
  AUD: 43.13
  INR: 2522.90
Enter fullscreen mode Exit fullscreen mode

Free vs. paid

The open endpoint (open.er-api.com) is completely free with no registration. Limitations:

  • Updates: Once per day (sufficient for most apps)
  • Historical data: Not available (paid only)
  • Rate limits: No documented limit, but cache your responses anyway
  • HTTPS: Yes
  • CORS: Yes (usable from browser)

The paid API (v6.exchangerate-api.com) adds historical data, minute-level updates, and higher reliability SLAs. Starting at $9.99/month.

For a portfolio tracker, e-commerce price display, or internal tool — the free endpoint handles it fine.

What it doesn't do

No historical exchange rates on the free tier. If you need "what was EUR/USD on January 15, 2023?" — that's a paid feature. Free alternatives for historical data: Frankfurter API (ECB rates, historical, completely free).


Need live currency data on autopilot? My Exchange Rate Scraper on Apify tracks 170+ currencies — runs on a schedule, no code needed. Email spinov001@gmail.com for custom pipelines.


More free API articles:

Top comments (0)