PHP powers over 75% of websites with a known server-side language, making it the most common backend for applications that need currency conversion. Whether you are building a Laravel application, a WordPress plugin, or a custom PHP project, integrating a currency API correctly matters for performance and reliability. This guide covers everything from basic cURL requests to production-ready implementations with Guzzle, caching, and error handling.
Why Use a Currency API in PHP?
PHP applications frequently need exchange rate data for e-commerce pricing, invoice generation, financial reporting, and multi-currency checkout flows. Hardcoding rates is impractical since currencies fluctuate constantly. A dedicated currency API like Finexly provides real-time and historical rates for 170+ currencies with sub-50ms response times.
Getting Started
First, sign up for a free API key at Finexly. The free tier includes 1,000 requests per month with no credit card required.
Method 1: PHP cURL (No Dependencies)
The simplest approach uses PHP's built-in cURL extension:
<?php
function getExchangeRates(string $base = 'USD', array $symbols = []): array
{
$apiKey = 'YOUR_API_KEY';
$url = 'https://api.finexly.com/v1/latest?base=' . $base;
if (!empty($symbols)) {
$url .= '&symbols=' . implode(',', $symbols);
}
$ch = curl_init();
curl_setopt_array($ch, [
CURLOPT_URL => $url,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_TIMEOUT => 10,
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . $apiKey,
'Accept: application/json',
],
]);
$response = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
if ($httpCode !== 200) {
throw new RuntimeException("API request failed with status $httpCode");
}
return json_decode($response, true);
}
// Usage
$rates = getExchangeRates('USD', ['EUR', 'GBP', 'JPY']);
echo "1 USD = {$rates['rates']['EUR']} EUR\n";Method 2: Guzzle HTTP Client
For production applications, Guzzle provides a cleaner interface with automatic retries and connection pooling:
<?php
use GuzzleHttp\Client;
use GuzzleHttp\Exception\RequestException;
class CurrencyApiClient
{
private Client $client;
public function __construct(string $apiKey)
{
$this->client = new Client([
'base_uri' => 'https://api.finexly.com/v1/',
'timeout' => 10,
'headers' => [
'Authorization' => 'Bearer ' . $apiKey,
'Accept' => 'application/json',
],
]);
}
public function getLatestRates(string $base = 'USD', array $symbols = []): array
{
$query = ['base' => $base];
if (!empty($symbols)) {
$query['symbols'] = implode(',', $symbols);
}
try {
$response = $this->client->get('latest', ['query' => $query]);
return json_decode($response->getBody()->getContents(), true);
} catch (RequestException $e) {
throw new RuntimeException(
'Currency API error: ' . $e->getMessage(),
$e->getCode()
);
}
}
public function convert(string $from, string $to, float $amount): float
{
$response = $this->client->get('convert', [
'query' => compact('from', 'to', 'amount'),
]);
$data = json_decode($response->getBody()->getContents(), true);
return $data['result'];
}
public function getHistoricalRates(string $date, string $base = 'USD'): array
{
$response = $this->client->get('historical', [
'query' => compact('date', 'base'),
]);
return json_decode($response->getBody()->getContents(), true);
}
}Install Guzzle via Composer:
composer require guzzlehttp/guzzleLaravel Integration
If you are using Laravel, you can create a service class that integrates with the framework's caching and configuration:
<?php
namespace App\Services;
use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Facades\Http;
class CurrencyService
{
private string $apiKey;
private string $baseUrl = 'https://api.finexly.com/v1';
public function __construct()
{
$this->apiKey = config('services.finexly.api_key');
}
public function getRate(string $from, string $to): float
{
$cacheKey = "exchange_rate:{$from}:{$to}";
return Cache::remember($cacheKey, now()->addMinutes(5), function () use ($from, $to) {
$response = Http::withToken($this->apiKey)
->get("{$this->baseUrl}/latest", [
'base' => $from,
'symbols' => $to,
]);
$response->throw();
return $response->json("rates.{$to}");
});
}
public function convert(string $from, string $to, float $amount): float
{
$rate = $this->getRate($from, $to);
return round($amount * $rate, 2);
}
}Register it in your config/services.php:
'finexly' => [
'api_key' => env('FINEXLY_API_KEY'),
],Then add your key to .env:
FINEXLY_API_KEY=your_api_key_hereCaching Strategies
Exchange rates do not change every millisecond. Caching responses reduces API calls and improves performance:
// File-based cache (no dependencies)
function getCachedRates(string $base, int $ttl = 300): array
{
$cacheFile = sys_get_temp_dir() . "/rates_{$base}.json";
if (file_exists($cacheFile) && (time() - filemtime($cacheFile)) < $ttl) {
return json_decode(file_get_contents($cacheFile), true);
}
$rates = getExchangeRates($base);
file_put_contents($cacheFile, json_encode($rates));
return $rates;
}For Laravel, the Cache::remember() approach shown above handles this automatically with your configured cache driver (Redis, Memcached, or file).
Error Handling and Rate Limits
Production applications must handle API errors gracefully:
function safeGetRates(string $base): ?array
{
try {
$rates = getExchangeRates($base);
if (!isset($rates['rates'])) {
error_log('Unexpected API response format');
return null;
}
return $rates;
} catch (RuntimeException $e) {
error_log('Currency API error: ' . $e->getMessage());
// Fall back to cached data if available
$cacheFile = sys_get_temp_dir() . "/rates_{$base}.json";
if (file_exists($cacheFile)) {
return json_decode(file_get_contents($cacheFile), true);
}
return null;
}
}The Finexly API returns standard HTTP status codes and rate limit headers (X-RateLimit-Remaining, X-RateLimit-Reset) so your application can handle limits proactively. Check the API documentation for the full error code reference.
Building a Simple Currency Converter
Here is a complete working example that ties everything together:
<?php
require 'vendor/autoload.php';
$client = new CurrencyApiClient('YOUR_API_KEY');
// Convert 500 EUR to USD
$result = $client->convert('EUR', 'USD', 500);
echo "500 EUR = $result USD\n";
// Get all rates for GBP
$rates = $client->getLatestRates('GBP');
foreach ($rates['rates'] as $currency => $rate) {
echo "GBP/$currency: $rate\n";
}
// Historical rate from last month
$historical = $client->getHistoricalRates('2026-03-01', 'USD');
echo "USD/EUR on March 1: {$historical['rates']['EUR']}\n";Next Steps
Now that you have currency conversion working in PHP, explore these related guides:
- JavaScript integration guide for frontend implementations
- Python API tutorial for data analysis workflows
- Node.js integration guide for backend JavaScript
- Historical rates guide for time-series analysis
- REST vs WebSocket comparison for high-frequency use cases
Ready to start? Get your free API key and integrate exchange rates into your PHP application in minutes.
Explore More
Vlado Grigirov
Senior Currency Markets Analyst & Financial Strategist
Vlado Grigirov is a senior currency markets analyst and financial strategist with over 14 years of experience in foreign exchange markets, cross-border finance, and currency risk management. He has wo...
View full profile →