DEV Community

Chathuranga Basnayaka
Chathuranga Basnayaka

Posted on

How to Get Live Exchange Rates in Python: A Developer's Guide

If you're building a Python application that deals with money across borders — whether it's an e-commerce platform, a fintech dashboard, or a data pipeline — you need reliable, real-time exchange rates. This guide walks you through two practical approaches to fetching live currency rates in Python, plus production-ready patterns for caching, error handling, and framework integration.

Why You Need Live Exchange Rates in Python

Hardcoding exchange rates is a non-starter. Rates fluctuate constantly, and even a small drift can compound into significant errors at scale. Common scenarios where you need live rates include:

  • E-commerce checkout: Converting product prices for international customers.
  • Financial reporting: Generating accurate multi-currency balance sheets.
  • Data analysis: Normalizing revenue data across regions for dashboards.
  • Payment processing: Calculating settlement amounts between currencies.
  • Travel apps: Showing users real-time conversion estimates.

The right approach is to pull rates from a reliable API, cache them sensibly, and handle failures gracefully. Let's look at how.

Option 1: Using the Requests Library (Raw HTTP)

The most straightforward way is to call an exchange rate REST API directly with the requests library. AllRatesToday provides a clean JSON API that supports 160+ currencies with rates updated every 60 seconds.

Installation

pip install requests
Enter fullscreen mode Exit fullscreen mode

Fetching the Latest Rates

import requests

API_KEY = "your_api_key_here"
BASE_URL = "https://api.allratestoday.com/v1"

def get_latest_rates(base_currency="USD"):
    """Fetch the latest exchange rates for a given base currency."""
    response = requests.get(
        f"{BASE_URL}/latest",
        params={"base": base_currency},
        headers={"Authorization": f"Bearer {API_KEY}"},
        timeout=10,
    )
    response.raise_for_status()
    data = response.json()
    return data["rates"]

rates = get_latest_rates("USD")
print(f"USD to EUR: {rates['EUR']}")
print(f"USD to GBP: {rates['GBP']}")
print(f"USD to JPY: {rates['JPY']}")
Enter fullscreen mode Exit fullscreen mode

Converting Between Currencies

def convert_currency(amount, from_currency, to_currency):
    """Convert an amount from one currency to another."""
    rates = get_latest_rates(from_currency)
    if to_currency not in rates:
        raise ValueError(f"Unsupported currency: {to_currency}")
    return round(amount * rates[to_currency], 2)

# Convert 100 USD to EUR
result = convert_currency(100, "USD", "EUR")
print(f"100 USD = {result} EUR")
Enter fullscreen mode Exit fullscreen mode

This approach gives you full control over the HTTP request, headers, and response parsing. It works well when you want to keep dependencies minimal or need to customize the request behavior.

Option 2: Using the AllRatesToday Python SDK

For a cleaner developer experience, the AllRatesToday Python SDK wraps the API with a Pythonic interface, built-in error handling, and automatic retries.

Installation

pip install allratestoday
Enter fullscreen mode Exit fullscreen mode

Basic Usage

from allratestoday import AllRatesToday

client = AllRatesToday("your_api_key_here")

# Get latest rates
rates = client.get_rates(base="USD")
print(f"USD to EUR: {rates['EUR']}")

# Convert directly
result = client.convert(amount=250, from_currency="GBP", to_currency="JPY")
print(f"250 GBP = {result} JPY")
Enter fullscreen mode Exit fullscreen mode

Fetching Historical Rates

# Get rates for a specific date
historical = client.get_rates(base="EUR", date="2026-01-15")
print(f"EUR to USD on Jan 15: {historical['USD']}")
Enter fullscreen mode Exit fullscreen mode

The SDK handles authentication, request formatting, and response parsing for you. It's the recommended approach for most projects.

Caching Rates to Minimize API Calls

Fetching rates on every request is wasteful and will burn through your API quota quickly. Exchange rates don't change every millisecond — a smart cache with a short TTL is the right pattern.

Simple In-Memory Cache

import time
from allratestoday import AllRatesToday

client = AllRatesToday("your_api_key_here")

_cache = {}
CACHE_TTL = 300  # 5 minutes

def get_cached_rates(base="USD"):
    """Return cached rates if fresh, otherwise fetch new ones."""
    now = time.time()
    cache_key = f"rates_{base}"

    if cache_key in _cache:
        cached_data, timestamp = _cache[cache_key]
        if now - timestamp < CACHE_TTL:
            return cached_data

    rates = client.get_rates(base=base)
    _cache[cache_key] = (rates, now)
    return rates
Enter fullscreen mode Exit fullscreen mode

Redis Cache for Multi-Instance Deployments

If you're running multiple server instances (e.g., behind a load balancer), an in-memory cache won't be shared between them. Use Redis instead:

import json
import redis
from allratestoday import AllRatesToday

r = redis.Redis(host="localhost", port=6379, db=0)
client = AllRatesToday("your_api_key_here")

def get_rates_with_redis(base="USD", ttl=300):
    """Fetch rates with Redis caching."""
    cache_key = f"exchange_rates:{base}"
    cached = r.get(cache_key)

    if cached:
        return json.loads(cached)

    rates = client.get_rates(base=base)
    r.setex(cache_key, ttl, json.dumps(rates))
    return rates
Enter fullscreen mode Exit fullscreen mode

Choose your cache TTL based on your use case: 60 seconds for near-real-time applications, 5 minutes for e-commerce, or up to 24 hours for accounting and reporting.

Handling Errors and Edge Cases

Production code needs to handle network timeouts, invalid API keys, rate limits, and unexpected responses. Here's a robust pattern:

import requests
from requests.exceptions import HTTPError, Timeout, ConnectionError

API_KEY = "your_api_key_here"
BASE_URL = "https://api.allratestoday.com/v1"

def get_rates_safe(base="USD", retries=3):
    """Fetch rates with retry logic and proper error handling."""
    for attempt in range(retries):
        try:
            response = requests.get(
                f"{BASE_URL}/latest",
                params={"base": base},
                headers={"Authorization": f"Bearer {API_KEY}"},
                timeout=10,
            )

            if response.status_code == 429:
                wait = int(response.headers.get("Retry-After", 60))
                print(f"Rate limited. Retrying in {wait}s...")
                time.sleep(wait)
                continue

            response.raise_for_status()
            return response.json()["rates"]

        except Timeout:
            print(f"Timeout on attempt {attempt + 1}/{retries}")
        except ConnectionError:
            print(f"Connection error on attempt {attempt + 1}/{retries}")
        except HTTPError as e:
            if e.response.status_code == 401:
                raise ValueError("Invalid API key") from e
            raise

    raise RuntimeError("Failed to fetch rates after all retries")
Enter fullscreen mode Exit fullscreen mode

Key things to handle:

  • HTTP 429 (Too Many Requests): Respect the Retry-After header and back off.
  • Timeouts: Always set a timeout parameter. Never let requests hang indefinitely.
  • Invalid API keys (401): Fail fast and surface a clear error message.
  • Network failures: Retry with backoff, then fall back to cached data if available.

Real-World Use Cases

Flask Integration

from flask import Flask, jsonify, request
from allratestoday import AllRatesToday

app = Flask(__name__)
client = AllRatesToday("your_api_key_here")

@app.route("/api/convert")
def convert():
    amount = float(request.args.get("amount", 1))
    from_curr = request.args.get("from", "USD")
    to_curr = request.args.get("to", "EUR")

    result = client.convert(
        amount=amount,
        from_currency=from_curr,
        to_currency=to_curr,
    )
    return jsonify({"result": result, "from": from_curr, "to": to_curr})
Enter fullscreen mode Exit fullscreen mode

Django View

from django.http import JsonResponse
from allratestoday import AllRatesToday

client = AllRatesToday("your_api_key_here")

def convert_view(request):
    amount = float(request.GET.get("amount", 1))
    from_curr = request.GET.get("from", "USD")
    to_curr = request.GET.get("to", "EUR")

    result = client.convert(
        amount=amount,
        from_currency=from_curr,
        to_currency=to_curr,
    )
    return JsonResponse({"result": result, "from": from_curr, "to": to_curr})
Enter fullscreen mode Exit fullscreen mode

Data Analysis with Pandas

import pandas as pd
from allratestoday import AllRatesToday

client = AllRatesToday("your_api_key_here")
rates = client.get_rates(base="USD")

# Convert a DataFrame column from local currencies to USD
df = pd.DataFrame({
    "revenue": [1000, 2500, 800, 3200],
    "currency": ["EUR", "GBP", "JPY", "CAD"],
})

df["usd_amount"] = df.apply(
    lambda row: row["revenue"] / rates[row["currency"]], axis=1
)
print(df)
Enter fullscreen mode Exit fullscreen mode

Performance Tips

  1. Cache aggressively. A 5-minute cache eliminates 99% of redundant API calls without meaningful data staleness for most applications.

  2. Batch your requests. Fetch all rates for a base currency in one call rather than making separate calls for each currency pair.

  3. Use connection pooling. If you're using requests directly, use a Session object to reuse TCP connections:

    session = requests.Session()
    session.headers.update({"Authorization": f"Bearer {API_KEY}"})
    # Reuse `session` for all API calls
    
  4. Store your API key securely. Use environment variables or a secrets manager — never hardcode keys in source files.

    import os
    API_KEY = os.environ["ALLRATESTODAY_API_KEY"]
    
  5. Set timeouts on every request. A missing timeout can hang your entire application if the API is slow to respond.

  6. Log API response times. Monitor latency in production so you can spot degradation early.

Wrapping Up

Getting live exchange rates into your Python application takes just a few lines of code. Whether you use the requests library for maximum control or the AllRatesToday Python SDK for convenience, the fundamentals are the same: fetch from a reliable source, cache smartly, handle errors, and keep your API key secure.

AllRatesToday offers a free tier with no credit card required, covering 160+ currencies with updates every 60 seconds. Sign up at allratestoday.com and start building.

Top comments (0)