Integration guide

Add currency exchange rates and conversion to PHP

Use PHP cURL for server-side requests and cache the latest response until nextUpdateAt. Read the key from the server environment.

1. Get a free API key

Sign up at https://currencyexchangerate-api.com/auth/login, then create a key under API keys in the console. The free plan includes 3,000 requests per month with no credit card. Store the secret as CXR_API_KEY in server-side environment configuration; never expose it in browser code.

.env

shell
CXR_API_KEY=cxr_your_secret_key

2. Create a reusable client and cache rates

Use the standard HTTP client. Cache every /latest response until nextUpdateAt: rates change at most once by then, and reusing the response saves quota. The helper also exposes /convert.

rates.php

PHP
<?php const API_BASE_URL = 'https://api.currencyexchangerate-api.com/api/v1'; function getApi(string $path): array{    $retry = null;    $ch = curl_init(API_BASE_URL . $path);    curl_setopt_array($ch, [        CURLOPT_RETURNTRANSFER => true,        CURLOPT_HTTPHEADER => [            'Authorization: Bearer ' . getenv('CXR_API_KEY'),        ],        CURLOPT_HEADERFUNCTION => function ($curl, $header) use (&$retry) {            if (stripos($header, 'Retry-After:') === 0) {                $retry = (int) trim(substr($header, 12));            }             return strlen($header);        },    ]);    $body = curl_exec($ch);    $status = curl_getinfo($ch, CURLINFO_HTTP_CODE);    curl_close($ch);     if ($body === false) {        throw new RuntimeException('Rates API unreachable');    }     $data = json_decode($body, true, 512, JSON_THROW_ON_ERROR);    if ($status >= 400) {        $message = $data['detail'] ?? 'Rates API error';        if ($retry) {            $message .= " (retry after $retry seconds)";        }        throw new RuntimeException($message, $status);    }     return $data;} function latest(string $base = 'USD', string $symbols = 'EUR,GBP'): array{    // Per process; use APCu or a framework cache to share across requests.    static $saved = [];     $id = "$base:$symbols";    if (isset($saved[$id]) && time() < $saved[$id]['until']) {        return $saved[$id]['data'];    }     $query = http_build_query(compact('base', 'symbols'));    $data = getApi('/latest?' . $query);    $saved[$id] = ['until' => strtotime($data['nextUpdateAt']), 'data' => $data];     return $data;} function convert(string $from, string $to, float $amount): array{    $query = http_build_query(compact('from', 'to', 'amount'));     return getApi('/convert?' . $query);}

3. Use it in PHP

Call the helper from a server route, controller, view, command, or script. Format converted values for the user’s locale.

convert.php

PHP
<?php require 'rates.php'; $result = convert('EUR', 'GBP', 100);$formatter = new NumberFormatter('en_GB', NumberFormatter::CURRENCY);echo $formatter->formatCurrency($result['result'], $result['to']);

4. Handle API errors

A 401 means the key is invalid. A 429 can mean a rate limit or quota limit; read Retry-After in seconds before retrying. Other errors use application/problem+json.

errors.php

PHP
<?php require 'rates.php'; try {    $result = convert('EUR', 'GBP', 100);} catch (RuntimeException $e) {    // getCode() is the HTTP status: 401 bad key, 429 limited.    http_response_code($e->getCode() === 429 ? 429 : 502);    echo $e->getMessage();}

5. Format the amount for display

Use locale-aware currency formatting instead of adding a symbol manually.

format.php

PHP
<?php // Requires the intl extension.$formatter = new NumberFormatter('de_DE', NumberFormatter::CURRENCY);echo $formatter->formatCurrency(85.249105, 'EUR');