Exchanger

May 18, 2026 ยท View on GitHub

Tests Psalm Total Downloads Version

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

fastFOREX 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 ExchangeRateService interface.
  • 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)

ServiceIdentifierBaseQuoteHistorical
โญ fastFOREXfastforex**Yes
AbstractAPIabstract_api**Yes
coinlayercoin_layer* (crypto)*Yes
Cryptonatorcryptonator* (crypto)* (crypto)No
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
exchangerate.hostexchangeratehost**Yes
exchangeratesapi (direct)exchange_rates_apiUSD (free), * (paid)*Yes
Fixer (APILayer)apilayer_fixerEUR (free), * (paid)*Yes
Fixer (direct)fixerEUR (free), * (paid)*Yes
1Forgeforge**No
Open Exchange Ratesopen_exchange_ratesUSD (free), * (paid)*Yes
UniRateAPIunirate_api**Yes (paid)
WebserviceXwebservicex**No
xChangeApi.comxchangeapi**Yes
Xignitexignite**Yes

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
European Central Bankeuropean_central_bankEUR*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

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.

๐Ÿ‘ Credits