CurrencyExchange RatesJavaScriptPythonTutorial
Currency Conversion API: JavaScript and Python Examples with Live Rates
ApogeoAPI6 min read
Getting exchange rates from the API
ApogeoAPI's exchange rates endpoint returns current rates for all supported currencies relative to USD:
GET https://api.apogeoapi.com/v1/rates/USD?apikey=YOUR_KEY
# Response
{
"base": "USD",
"date": "2026-05-14",
"rates": {
"EUR": 0.923,
"GBP": 0.789,
"JPY": 154.2,
"BRL": 4.95,
"ARS": 892.5,
"AUD": 1.54,
...160 more currencies...
}
}
Free tier: 1,000 requests/month. Rates refresh every 4 hours.
JavaScript — simple converter
const APOGEO_KEY = process.env.APOGEO_KEY;
let ratesCache = null;
let ratesCachedAt = 0;
async function getRates(base = 'USD') {
// Cache rates for 4 hours
if (ratesCache && Date.now() - ratesCachedAt < 4 * 60 * 60 * 1000) {
return ratesCache;
}
const res = await fetch(
`https://api.apogeoapi.com/v1/rates/${base}?apikey=${APOGEO_KEY}`
);
const data = await res.json();
ratesCache = data.rates;
ratesCachedAt = Date.now();
return ratesCache;
}
async function convert(amount, from, to) {
const rates = await getRates('USD');
// Convert to USD first, then to target
const inUSD = from === 'USD' ? amount : amount / rates[from];
const result = to === 'USD' ? inUSD : inUSD * rates[to];
return Math.round(result * 100) / 100; // round to 2 decimal places
}
// Usage
const inEUR = await convert(29.99, 'USD', 'EUR'); // → 27.67
const inJPY = await convert(29.99, 'USD', 'JPY'); // → 4623
console.log(`${inEUR} EUR`);
console.log(`¥${inJPY}`);
JavaScript — format currency amounts
Use the browser's Intl.NumberFormat to format amounts with the correct symbol, thousands separator, and decimal places for any locale:
function formatCurrency(amount, currencyCode, locale = 'en-US') {
return new Intl.NumberFormat(locale, {
style: 'currency',
currency: currencyCode,
maximumFractionDigits: ['JPY', 'KRW', 'IDR', 'CLP'].includes(currencyCode) ? 0 : 2,
}).format(amount);
}
// Examples
formatCurrency(29.99, 'USD'); // "$29.99"
formatCurrency(27.67, 'EUR'); // "€27.67"
formatCurrency(4623, 'JPY'); // "¥4,623"
formatCurrency(149.50, 'BRL', 'pt-BR'); // "R$ 149,50"
JavaScript — React hook for currency conversion
// hooks/useExchangeRate.ts
import { useState, useEffect } from 'react';
const cache = new Map<string, { rates: Record<string, number>; expires: number }>();
export function useExchangeRate(baseCurrency = 'USD') {
const [rates, setRates] = useState<Record<string, number> | null>(null);
const [loading, setLoading] = useState(true);
useEffect(() => {
const cached = cache.get(baseCurrency);
if (cached && cached.expires > Date.now()) {
setRates(cached.rates);
setLoading(false);
return;
}
fetch(`/api/rates?base=${baseCurrency}`) // proxy through your API
.then(r => r.json())
.then(data => {
cache.set(baseCurrency, { rates: data.rates, expires: Date.now() + 4 * 3600000 });
setRates(data.rates);
setLoading(false);
});
}, [baseCurrency]);
const convert = (amount: number, from: string, to: string): number => {
if (!rates) return amount;
const inBase = from === baseCurrency ? amount : amount / rates[from];
return to === baseCurrency ? inBase : inBase * rates[to];
};
return { rates, loading, convert };
}
// Component
function PriceDisplay({ usdAmount }: { usdAmount: number }) {
const { convert, loading } = useExchangeRate('USD');
const [targetCurrency, setTargetCurrency] = useState('EUR');
if (loading) return <span>Loading...</span>;
const converted = convert(usdAmount, 'USD', targetCurrency);
return (
<div>
<span>{formatCurrency(converted, targetCurrency)}</span>
<select value={targetCurrency} onChange={e => setTargetCurrency(e.target.value)}>
{['EUR', 'GBP', 'JPY', 'BRL', 'CAD', 'AUD'].map(c => (
<option key={c} value={c}>{c}</option>
))}
</select>
</div>
);
}
Python — synchronous (requests)
import requests
import time
from functools import lru_cache
from typing import Optional
APOGEO_KEY = "your_api_key"
BASE_URL = "https://api.apogeoapi.com/v1"
# Simple TTL cache using a dict
_rates_cache: dict = {}
_rates_cached_at: float = 0
def get_rates(base: str = "USD") -> dict[str, float]:
global _rates_cache, _rates_cached_at
if _rates_cache and time.time() - _rates_cached_at < 4 * 3600:
return _rates_cache
response = requests.get(
f"{BASE_URL}/rates/{base}",
params={"apikey": APOGEO_KEY},
timeout=3,
)
response.raise_for_status()
data = response.json()
_rates_cache = data["rates"]
_rates_cached_at = time.time()
return _rates_cache
def convert(amount: float, from_currency: str, to_currency: str, base: str = "USD") -> float:
rates = get_rates(base)
# Normalize to base currency first
in_base = amount if from_currency == base else amount / rates[from_currency]
# Convert to target
result = in_base if to_currency == base else in_base * rates[to_currency]
return round(result, 2)
# Usage
print(convert(29.99, "USD", "EUR")) # 27.67
print(convert(29.99, "USD", "BRL")) # 148.45
print(convert(100, "EUR", "JPY")) # 16694
Python — async (httpx)
import asyncio
import httpx
import time
APOGEO_KEY = "your_api_key"
_rates_cache: dict = {}
_rates_cached_at: float = 0
async def get_rates_async(base: str = "USD", client: httpx.AsyncClient = None) -> dict:
global _rates_cache, _rates_cached_at
if _rates_cache and time.time() - _rates_cached_at < 4 * 3600:
return _rates_cache
should_close = client is None
if client is None:
client = httpx.AsyncClient()
try:
r = await client.get(
f"https://api.apogeoapi.com/v1/rates/{base}",
params={"apikey": APOGEO_KEY},
timeout=3,
)
r.raise_for_status()
data = r.json()
_rates_cache = data["rates"]
_rates_cached_at = time.time()
return _rates_cache
finally:
if should_close:
await client.aclose()
async def main():
async with httpx.AsyncClient() as client:
# Fetch rates and geolocate in parallel
rates_task = get_rates_async(client=client)
geo_task = client.get(
"https://api.apogeoapi.com/v1/geo/8.8.8.8",
params={"apikey": APOGEO_KEY},
)
rates, geo_response = await asyncio.gather(rates_task, geo_task)
geo = geo_response.json()
currency = geo["currencyCode"]
usd_price = 29.99
rate = rates.get(currency, 1)
local_price = round(usd_price * rate, 2)
print(f"Country: {geo['countryCode']}")
print(f"Currency: {currency}")
print(f"Price: {local_price} {currency}")
asyncio.run(main())
Combining with IP geolocation
ApogeoAPI returns the visitor's currency code in the IP geolocation response — saving you a separate rates call in many cases:
// One call gets country + currency code
const geoRes = await fetch(
`https://api.apogeoapi.com/v1/geo/${ip}?apikey=${APOGEO_KEY}`
);
const geo = await geoRes.json();
// geo.currencyCode = "BRL"
// geo.currencyRate = 4.95 (relative to USD — same as the exchange rates endpoint!)
// Convert directly from geo response — no second API call needed
const localPrice = Math.round(29.99 * geo.currencyRate);
console.log(`${geo.currencySymbol}${localPrice} ${geo.currencyCode}`);
// → "R$148 BRL"
API docs: api.apogeoapi.com/api/docs. Free tier: app.apogeoapi.com/register.
Try ApogeoAPI free
1,000 requests/month forever. 14-day full-access trial. No credit card.
Get your free API key