florianv / exchanger
PHP exchange rate provider layer for currency conversion: 30 services, chain fallback, and caching.
Requires
- php: ^8.2
- ext-json: *
- ext-libxml: *
- ext-simplexml: *
- php-http/client-implementation: ^1.0
- php-http/discovery: ^1.19
- php-http/httplug: ^1.0 || ^2.0
- psr/http-factory: ^1.0.2
- psr/simple-cache: ^1.0 || ^2.0 || ^3.0
Requires (Dev)
- nyholm/psr7: ^1.0
- php-http/message: ^1.7
- php-http/mock-client: ^1.0
- phpunit/phpunit: ^11.0 || ^12.0
- roave/backward-compatibility-check: ^8.9
- vimeo/psalm: ^6.0
- dev-master / 2.x-dev
- 2.9.1
- 2.9.0
- 2.8.3
- 2.8.2
- 2.8.1
- 2.8.0
- 2.7.2
- 2.7.1
- 2.7.0
- 2.6.3
- 2.6.2
- 2.6.1
- 2.6.0
- 2.5.3
- 2.5.2
- 2.5.1
- 2.5.0
- 2.4.1
- 2.4.0
- 2.3.1
- 2.3.0
- 2.2.2
- 2.2.1
- 2.2.0
- 2.1.1
- 2.1.0
- 2.0.0
- 1.x-dev
- 1.4.3
- 1.4.2
- 1.4.1
- 1.4.0
- 1.3.0
- 1.2.2
- 1.2.1
- 1.2.0
- 1.1.2
- 1.1.1
- 1.1.0
- 1.0.3
- 1.0.2
- 1.0.1
- 1.0.0
- 0.7.0
- 0.6.1
- 0.6.0
- 0.5.0
- 0.4.0
- 0.3.0
- 0.2.1
- 0.2.0
- 0.1.0
- 0.0.0
This package is auto-updated.
Last update: 2026-05-18 09:27:57 UTC
README
Exchange rate provider layer for PHP. Direct access to 31 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 — 31 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.
💡 What is Exchanger?
- A PHP library for currency conversion and exchange rate retrieval at the provider layer.
- 31 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.
📦 Installation
Exchanger requires PHP 8.2 or newer.
composer require florianv/exchanger symfony/http-client nyholm/psr7
Any PSR-18 client paired with a PSR-17 request factory works; php-http/discovery finds them automatically.
⚡ Quickstart
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.
🔁 Chaining services (fallback chain)
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.
📊 Providers
Exchanger ships 31 exchange rate provider implementations. Each is registered in Exchanger\Service\Registry under the identifier shown below.
Commercial providers (require an API key)
| 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 |
| UniRateAPI | unirate_api |
* | * | Yes (paid) |
| WebserviceX | webservicex |
* | * | No |
| xChangeApi.com | xchangeapi |
* | * | Yes |
| Xignite | xignite |
* | * | Yes |
Public providers (no API key required)
| 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).
🎯 When should you use Exchanger?
- 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.
🛠 Common use cases
- 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.
🧭 Which package should I use?
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.
📚 Documentation
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.
🙌 Contributing
Issues and pull requests are welcome. Please see the existing issues before opening a new one.
📄 License
The MIT License (MIT). Please see LICENSE for more information.