Exchanger

May 4, 2026 ยท View on GitHub

Tests Psalm Total Downloads Version

Exchange rate provider layer for PHP. Direct access to 30 provider implementations through a single ExchangeRateService interface, with chain fallback and PSR-16 caching. Maintained since 2016.

Exchanger is the exchange rate provider layer for PHP. It exposes 30 services (the European Central Bank, several national banks, exchangerate.host, and commercial exchange rate APIs that require an API key) behind a single ExchangeRateService interface, with chainable fallback, PSR-16 caching, and historical rates. Used in real-world PHP applications since 2016.

For most use cases, the higher-level Swap library is what you want. Reach for Exchanger directly when you need finer control.

๐Ÿ’ก What is Exchanger?

  • Exchanger is a PHP library for currency conversion and exchange rate retrieval at the provider layer.
  • It contains 30 service implementations behind a common ExchangeRateService interface.
  • It caches results via PSR-16 SimpleCache.
  • It supports historical rates.
  • It supports a chain service for fallback. When a service errors, the next one in the chain is tried.

๐ŸŽฏ 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.

๐Ÿง  Why Exchanger over Swap?

Swap is the easy-to-use, high-level API. Exchanger is the layer Swap is built on.

Reach for Exchanger directly when:

  • Custom facade: you want to build your own currency conversion API on top of the provider layer.
  • Framework binding: you are integrating into a framework that does not yet have a Swap binding.
  • Fine-grained chain composition: you need to wrap services with custom logic (rate limiting, observability, conditional fallback) before chaining them.
  • Direct cache control: you want to manage the PSR-16 cache key strategy yourself.
  • Custom HTTP layer: you need an HTTP middleware stack the Swap builder does not expose.

If none of these apply, use Swap.

๐Ÿ“ฆ 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

use Exchanger\Exchanger;
use Exchanger\ExchangeRateQueryBuilder;
use Exchanger\Service\EuropeanCentralBank;

// The European Central Bank is free, no API key required.
$service   = new EuropeanCentralBank();
$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();          // 'european_central_bank'

// 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.

๐Ÿ” 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;

$service = new Chain([
    new YourPrimaryService(null, null, ['api_key' => 'YOUR_KEY']),
    new YourFallbackService(null, null, ['api_key' => 'YOUR_KEY']),
    new EuropeanCentralBank(), // free fallback for EUR-base pairs
]);

$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 an exception, the exception is collected and the next service is tried. If every service was skipped or threw, the chain raises an Exchanger\Exception\ChainException containing all collected exceptions.

๐Ÿ›  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, more granular 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 application of Swap.
  • Symfony Swap. Symfony integration of Swap.

All four packages are MIT-licensed and require PHP 8.2 or newer.

๐Ÿ“Š Providers

Exchanger ships 30 exchange rate provider implementations. Each is registered in Exchanger\Service\Registry under the identifier shown in the table.

Public providers (no API key required)

ServiceIdentifierBaseQuoteHistorical
Bulgarian National Bankbulgarian_national_bank*BGNYes
Central Bank of the Czech Republiccentral_bank_of_czech_republic*CZKYes
Central Bank of the Republic of Turkeycentral_bank_of_republic_turkey*TRYYes
Central Bank of the Republic of Uzbekistancentral_bank_of_republic_uzbekistan*UZSYes
Cryptonatorcryptonator* (crypto)* (crypto)No
European Central Bankeuropean_central_bankEUR*Yes
exchangerate.hostexchangeratehost**Yes
National Bank of Georgianational_bank_of_georgia*GELYes
National Bank of Romanianational_bank_of_romania(limited list)(limited list)Yes
National Bank of the Republic of Belarusnational_bank_of_republic_belarus*BYNYes
National Bank of Ukrainenational_bank_of_ukraine*UAHYes
Russian Central Bankrussian_central_bank*RUBYes
WebserviceXwebservicex**No

Commercial providers (require an API key)

ServiceIdentifierBaseQuoteHistorical
AbstractAPIabstract_api**Yes
coinlayercoin_layer* (crypto)*Yes
Currency Converter APIcurrency_converter**Yes
Currency Data (APILayer)apilayer_currency_dataUSD (free), * (paid)*Yes
CurrencyDataFeedcurrency_data_feed**No
currencylayer (direct)currency_layerUSD (free), * (paid)*Yes
Exchange Rates Data (APILayer)apilayer_exchange_rates_dataUSD (free), * (paid)*Yes
exchangeratesapi (direct)exchange_rates_apiUSD (free), * (paid)*Yes
fastFOREX.iofastforex**Yes
Fixer (APILayer)apilayer_fixerEUR (free), * (paid)*Yes
Fixer (direct)fixerEUR (free), * (paid)*Yes
1Forgeforge**No
Open Exchange Ratesopen_exchange_ratesUSD (free), * (paid)*Yes
xChangeApi.comxchangeapi**Yes
Xignitexignite**Yes

You can also add your own provider by implementing the Exchanger\Contract\ExchangeRateService interface (see the documentation).

โš™ Caching, HTTP client, and error handling

  • Caching: PSR-16 SimpleCache is passed as the second constructor argument: new Exchanger($service, $cache). Per-query disable: ->addOption('cache', false). Per-query TTL: ->addOption('cache_ttl', 3600).
  • HTTP client: any PSR-18 client (symfony/http-client, php-http/guzzle7-adapter, etc.). Pass it explicitly to each service constructor, or rely on php-http/discovery to auto-discover.
  • Errors: when every service in a Chain has either skipped (unsupported pair) or thrown, the chain raises an Exchanger\Exception\ChainException containing all collected exceptions.

๐Ÿ“š Documentation

The full documentation, with the per-provider configuration reference, caching options, and how to write your own service, is in doc/readme.md.

The Swap ecosystem:

  • Swap: easy-to-use PHP currency conversion library.
  • Exchanger: exchange rate provider layer (this package).
  • Laravel Swap: Laravel application of Swap.
  • Symfony Swap: Symfony integration of Swap.

๐Ÿค Sponsorship

The Swap ecosystem is open to selected sponsorships from exchange rate API providers and financial infrastructure companies.

Sponsorship can include:

  • Documentation visibility
  • Integration examples
  • Ecosystem-level visibility across Swap, Exchanger, Laravel Swap, and Symfony Swap

For inquiries, contact the maintainer via GitHub.

๐Ÿ™Œ 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.

๐Ÿ‘ Credits