Plain PHP with cURL
function latestRates(string $base = 'USD'): array
{
$ch = curl_init('https://api.currencyapi.com/v3/latest?base_currency=' . urlencode($base));
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => ['apikey: ' . getenv('CURRENCYAPI_KEY')],
CURLOPT_TIMEOUT => 10,
]);
$json = json_decode(curl_exec($ch), true);
curl_close($ch);
return array_map(fn ($item) => $item['value'], $json['data']);
}
$rates = latestRates('USD');
echo $rates['EUR']; // e.g. 0.8828
Laravel with caching
use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Facades\Http;
function exchangeRates(string $base = 'USD'): array
{
return Cache::remember("fx:latest:$base", now()->addMinutes(10), function () use ($base) {
$data = Http::withHeaders(['apikey' => config('services.currencyapi.key')])
->get('https://api.currencyapi.com/v3/latest', ['base_currency' => $base])
->throw()
->json('data');
return collect($data)->map(fn ($item) => $item['value'])->all();
});
}
Converting without float errors
// 199.99 USD to EUR with 2 decimals
$rate = (string) exchangeRates('USD')['EUR'];
$eur = bcmul('199.99', $rate, 2);
For invoices, also store the rate and its date next to the converted amount, so the conversion can be reproduced later with the historical endpoint.