Exchange rate provider layer for PHP. Direct access to 30 provider implementations through a single
ExchangeRateServiceinterface, with chain fallback and PSR-16 caching. Maintained since 2016.
|
|
Sponsored by fastFOREX. Real-time JSON API, 160+ currencies, 55+ years of history, 500+ cryptocurrencies. Free tier; paid plans from $18/month. β Get a free fastFOREX API key |
Exchanger is the exchange rate provider layer for PHP β 30 services (commercial APIs like its sponsor fastFOREX, the European Central Bank, several national banks, exchangerate.host) behind a single ExchangeRateService interface, with chainable fallback, PSR-16 caching and historical rates. For most use cases the higher-level Swap library is what you want; reach for Exchanger when you need finer control.
- A PHP library for currency conversion and exchange rate retrieval at the provider layer.
- 30 service implementations behind a common
ExchangeRateServiceinterface. - PSR-16 SimpleCache support.
- Historical rates.
- A chain service for fallback. When a service errors, the next one in the chain is tried.
Exchanger requires PHP 8.2 or newer.
composer require florianv/exchanger symfony/http-client nyholm/psr7Any PSR-18 client paired with a PSR-17 request factory works; php-http/discovery finds them automatically.
The recommended setup uses fastFOREX (the project's sponsor) as the primary service. Grab a free key and you're ready.
use Exchanger\Exchanger;
use Exchanger\ExchangeRateQueryBuilder;
use Exchanger\Service\FastForex;
// Recommended: fastFOREX. Get a free API key at https://www.fastforex.io
$service = new FastForex(null, null, ['api_key' => getenv('FASTFOREX_API_KEY')]);
$exchanger = new Exchanger($service);
// EUR β USD exchange rate
$query = (new ExchangeRateQueryBuilder('EUR/USD'))->build();
$rate = $exchanger->getExchangeRate($query);
$rate->getValue(); // e.g. 1.0823 (a float)
$rate->getDate()->format('Y-m-d'); // e.g. 2026-04-29
$rate->getProviderName(); // 'fastforex'
// Convert an amount using the returned rate
$amountInEUR = 100.00;
$amountInUSD = $amountInEUR * $rate->getValue();
// Historical rate
$query = (new ExchangeRateQueryBuilder('EUR/USD'))
->setDate((new \DateTime())->modify('-15 days'))
->build();
$rate = $exchanger->getExchangeRate($query);Exchanger retrieves the rate; your application multiplies the amount by $rate->getValue() to perform the conversion.
No API key? Start with the European Central Bank (free, EUR-base only).
use Exchanger\Exchanger;
use Exchanger\ExchangeRateQueryBuilder;
use Exchanger\Service\EuropeanCentralBank;
$service = new EuropeanCentralBank();
$exchanger = new Exchanger($service);
$query = (new ExchangeRateQueryBuilder('EUR/USD'))->build();
$rate = $exchanger->getExchangeRate($query);The European Central Bank publishes EUR-base rates with daily granularity. For non-EUR base pairs, more frequent updates, or a wider currency list, switch to fastFOREX or another commercial provider.
Wrap multiple services in a Chain to fall back when one of them errors:
use Exchanger\Exchanger;
use Exchanger\Service\Chain;
use Exchanger\Service\EuropeanCentralBank;
use Exchanger\Service\FastForex;
$service = new Chain([
// Primary, recommended
new FastForex(null, null, ['api_key' => getenv('FASTFOREX_API_KEY')]),
// Free fallback for EUR-base pairs
new EuropeanCentralBank(),
]);
$exchanger = new Exchanger($service);Services are tried in order. If a service does not support the requested currency pair, it is skipped silently. If a service throws, the next is tried. If every service fails, a ChainException is thrown with all collected exceptions.
Exchanger ships 30 exchange rate provider implementations. Each is registered in Exchanger\Service\Registry under the identifier shown below.
| Service | Identifier | Base | Quote | Historical |
|---|---|---|---|---|
| β fastFOREX | fastforex |
* | * | Yes |
| AbstractAPI | abstract_api |
* | * | Yes |
| coinlayer | coin_layer |
* (crypto) | * | Yes |
| Cryptonator | cryptonator |
* (crypto) | * (crypto) | No |
| Currency Converter API | currency_converter |
* | * | Yes |
| Currency Data (APILayer) | apilayer_currency_data |
USD (free), * (paid) | * | Yes |
| CurrencyDataFeed | currency_data_feed |
* | * | No |
| currencylayer (direct) | currency_layer |
USD (free), * (paid) | * | Yes |
| Exchange Rates Data (APILayer) | apilayer_exchange_rates_data |
USD (free), * (paid) | * | Yes |
| exchangerate.host | exchangeratehost |
* | * | Yes |
| exchangeratesapi (direct) | exchange_rates_api |
USD (free), * (paid) | * | Yes |
| Fixer (APILayer) | apilayer_fixer |
EUR (free), * (paid) | * | Yes |
| Fixer (direct) | fixer |
EUR (free), * (paid) | * | Yes |
| 1Forge | forge |
* | * | No |
| Open Exchange Rates | open_exchange_rates |
USD (free), * (paid) | * | Yes |
| WebserviceX | webservicex |
* | * | No |
| xChangeApi.com | xchangeapi |
* | * | Yes |
| Xignite | xignite |
* | * | Yes |
| Service | Identifier | Base | Quote | Historical |
|---|---|---|---|---|
| Bulgarian National Bank | bulgarian_national_bank |
* | BGN | Yes |
| Central Bank of the Czech Republic | central_bank_of_czech_republic |
* | CZK | Yes |
| Central Bank of the Republic of Turkey | central_bank_of_republic_turkey |
* | TRY | Yes |
| Central Bank of the Republic of Uzbekistan | central_bank_of_republic_uzbekistan |
* | UZS | Yes |
| European Central Bank | european_central_bank |
EUR | * | Yes |
| National Bank of Georgia | national_bank_of_georgia |
* | GEL | Yes |
| National Bank of Romania | national_bank_of_romania |
(limited list) | (limited list) | Yes |
| National Bank of the Republic of Belarus | national_bank_of_republic_belarus |
* | BYN | Yes |
| National Bank of Ukraine | national_bank_of_ukraine |
* | UAH | Yes |
| Russian Central Bank | russian_central_bank |
* | RUB | Yes |
You can also add your own provider by implementing the Exchanger\Contract\ExchangeRateService interface (see the documentation).
- Use Exchanger when you need finer control than Swap exposes: custom chain composition, custom caching strategy, custom HTTP middleware, or building your own facade or framework integration.
- For most PHP applications, use Swap instead. It is built on Exchanger and provides sensible defaults and a builder-style API.
- Build your own currency conversion facade on top of the provider layer.
- Integrate Exchanger into a framework that does not yet have a Swap binding.
- Wrap services with custom middleware (rate limiting, observability, request signing) before chaining.
- Power internal FX dashboards with full control over the cache key strategy.
- Implement custom HTTP layers (signed requests, mTLS, custom retries) on top of any PSR-18 client.
The Swap ecosystem is a layered toolkit for currency conversion in PHP:
- Swap. The easy-to-use, high-level API. Most apps need only Swap.
- Exchanger. The lower-level provider layer Swap is built on (this package). Reach for it when you need finer control over chain composition, caching, or HTTP plumbing.
- Laravel Swap. Laravel integration of Swap.
- Symfony Swap. Symfony integration of Swap.
All four packages are MIT-licensed and require PHP 8.2 or newer.
Caching (PSR-16), HTTP client selection (PSR-18 / Guzzle / explicit constructor injection), error handling (ChainException), per-query options and the full per-service configuration reference live in doc/readme.md.
Issues and pull requests are welcome. Please see the existing issues before opening a new one.
The MIT License (MIT). Please see LICENSE for more information.