Library / SDK
florianv/swap avatar
florianv/swap

florianv/swap: PHP Exchange Rates With Fallback Providers

PHP currency conversion library for retrieving exchange rates from 30 providers, with caching and fallback. Maintained since 2014.

1,341 stars145 forksPHPMIT

At a glance

What is it?
florianv/swap gives PHP applications one interface for exchange rates from 30+ providers, with PSR-16 caching, historical rates, and ordered fallback. It suits applications that need provider portability, although non-EUR pairs and high-frequency data may require a commercial source.
Who is it for?
PHP applications should consider florianv/swap when they need a provider-neutral API, historical rate access, caching, or fallback across multiple data sources. Projects requiring frequent non-EUR updates should first check whether the selected provider meets their pair coverage and update cadence.
Can I use it commercially?
Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository received new commits within the last day.
What is it written in?
Mainly PHP, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 23, 2026, and from our analysis. They are not legal advice.

Editorial analysis

Why florianv/swap sits above PHP Exchange Rate APIs

florianv/swap addresses a specific problem in PHP applications: exchange rate providers do not expose identical methods, authentication requirements, supported pairs, or error behavior. The library places 30+ providers behind one interface, so application code asks Swap for a rate instead of implementing a separate integration for every service.

The intended audience includes PHP developers building payment interfaces, reporting systems, accounting workflows, Laravel applications, and Symfony applications that need currency values. The README also documents integration with moneyphp/money through `SwapExchange`. Swap retrieves a rate, but the application remains responsible for multiplying an amount by that value.

This separation has a practical consequence. Swap does not present itself as a complete money-handling system. The quickstart retrieves `EUR/USD`, then applies `$rate->getValue()` to an amount. Applications also need to decide how rounding, precision, and currency-specific conversion rules should work.

The provider boundary is important. Free public sources can cover routine use, while commercial APIs are available for broader currency lists, additional base currencies, or more frequent updates. That makes Swap suitable for applications that may change providers or require a fallback, but provider selection still depends on the currency pair and operational requirements.

Swap Builder, Rate Objects, and Provider Selection

Construction begins with `Swap\Builder`. Each provider is registered with `Builder::add()`, and the identifier determines which service implementation is used. Identifiers include `fastforex` and `european_central_bank`, among the documented provider entries.

After `build()`, the application can request a pair through `latest()`. The returned rate exposes its numeric value, date, and provider name through `getValue()`, `getDate()`, and `getProviderName()`. The provider name is operationally useful because it identifies which source supplied the successful result in a fallback chain.

For an API key, provider configuration is passed as an options array. In the documented fastFOREX setup, the key is read from the `FASTFOREX_API_KEY` environment variable rather than embedded in source. The provider identifier is separate from the provider option array.

Swap reports support for historical rates, but the README excerpt does not show a historical lookup method or its full configuration. The provider table marks historical availability as varying by service, and Cryptonator, CurrencyDataFeed, and 1Forge are shown without historical support. Historical behavior should therefore be verified against the documentation and selected provider before an application depends on it.

Ordered Fallback and Error Reporting in Swap

Swap accepts more than one provider and tries them in registration order. This is useful when a primary commercial service is supplemented by a free public source. The README's example places `fastforex` first and `european_central_bank` second.

Fallback has two documented paths. A provider that does not support the requested pair is skipped silently, so pair incompatibility does not become the visible result of the operation. If a provider throws an error, Swap advances to the next provider. When all providers fail, it throws `ChainException` with the collected errors.

That behavior needs careful interpretation. A successful response proves only that one configured provider could supply the requested pair. It does not tell the caller whether earlier providers failed, were skipped, or returned different values. Since the rate object includes `getProviderName()`, logging that name is the documented way to identify the selected source.

Fallback also does not merge providers or reconcile competing rates. It selects the first usable result in the configured chain. Applications that require provider consensus should not assume that Swap performs that comparison.

Installing Swap and Retrieving the First EUR Rate

Swap requires PHP 8.2 or newer. The README installs the library with the Symfony HTTP client, which supplies the PSR-18 client, and Nyholm's PSR-7 factories. The documentation says other PSR-18 or PSR-17 implementations can be used instead.

Install the package and its documented HTTP dependencies with Composer:

bash
composer require florianv/swap symfony/http-client nyholm/psr7

A no-key first use can start with the European Central Bank provider. This example requests a latest `EUR/USD` rate:

php
use Swap\Builder;

$swap = (new Builder())
    ->add('european_central_bank')
    ->build();

$rate = $swap->latest('EUR/USD');

The reader should see a rate object when the provider can supply the requested pair. Its numeric value and date can be accessed with the methods shown in the README. This setup is specifically limited: the ECB provider publishes EUR-based rates with daily granularity. It is not the documented choice for non-EUR base pairs, more frequent updates, or a wider currency list.

Configuring fastFOREX as Swap's Primary Rate Source

The README recommends fastFOREX as the primary provider and requires an API key. The project sponsor supplies the API. Pass the key through the `FASTFOREX_API_KEY` environment variable in the provider configuration:

php
use Swap\Builder;

$swap = (new Builder())
    ->add('fastforex', ['api_key' => getenv('FASTFOREX_API_KEY')])
    ->build();

$rate = $swap->latest('EUR/USD');

The environment variable must resolve to the API key in the PHP process. A missing or invalid key would place reliance on the provider's own error behavior, and the README does not document a separate key-validation step in Swap.

The application can read the returned rate and use it for conversion. The documented arithmetic is direct multiplication:

php
$amountInEUR = 100.00;
$amountInUSD = $amountInEUR * $rate->getValue();

This example returns a float and does not define currency rounding. The README does not specify decimal precision, minor-unit rules, or a rounding policy for this calculation, so those concerns belong in application logic or a money-value library rather than an assumed Swap feature.

Caching, Historical Rates, and Upgrade Boundaries

Swap supports caching through PSR-16 `SimpleCache`. That interface allows the library to integrate with an application's configured PSR-16 cache implementation, but the README excerpt does not show cache construction, keys, expiration settings, or invalidation commands. Those details must come from the linked project documentation before an operator changes retention or freshness policy.

Historical rates are also supported, subject to provider availability. The provider table records historical support per service and shows that several providers do not offer it. This makes provider choice part of the data model rather than merely an implementation detail. A current rate may be available from a service that cannot answer a dated query.

The repository is not archived. Its last push was on 2026-06-17, and the listed releases include version 4.5.0 and 4.4.0, both dated 2026-03-09. Those facts indicate recent repository activity, but the README does not document a migration procedure or compatibility policy for upgrades. Projects moving between major versions should inspect `CHANGELOG.md`, `composer.json`, and the upgrade notes rather than assuming that provider identifiers or HTTP abstractions remain unchanged.

The MIT license permits use and modification under its terms, but applications still need to review provider licenses, API terms, and the obligations attached to their own distribution. Swap's MIT license does not by itself settle the commercial or data-use terms of fastFOREX or any other configured service.

Where Swap Falls Short and What Alternative Approach Fits

Swap is the wrong choice when a project needs a single guaranteed response from one provider, a fixed update schedule, or automatic reconciliation between conflicting rates. It selects a provider from a chain rather than combining their data. Its README also leaves rounding, cache configuration, and detailed historical API usage outside the quickstart.

The ECB example demonstrates the clearest boundary. It is appropriate when EUR-based, daily exchange rates are enough. It is unsuitable when the application needs a non-EUR base pair, more frequent updates, or a wider currency list. Switching providers is then an operational requirement, not a transparent caching improvement.

A direct commercial API integration is a real alternative for teams that already have one provider and do not need a common interface. The direct approach can give the application closer access to that provider's response model and error semantics, but it removes Swap's provider abstraction and fallback chain. Another alternative is building multiple provider adapters internally, which preserves a uniform application interface at the cost of maintaining that integration code directly.

Swap's value is therefore clearest for PHP code that expects to support several data sources or wants a fallback policy outside the business layer. It offers less value when provider portability is irrelevant and the application's requirements are tightly coupled to one API.

Editorial conclusion

PHP applications should consider florianv/swap when they need a provider-neutral API, historical rate access, caching, or fallback across multiple data sources. Projects requiring frequent non-EUR updates should first check whether the selected provider meets their pair coverage and update cadence. ECB-only deployments are more limited because the documented source is EUR-based with daily granularity.

Frequently asked questions

What PHP version does florianv/swap require?

The README states that Swap requires PHP 8.2 or newer. Its installation command also adds `symfony/http-client` and `nyholm/psr7`.

How do I configure a fallback provider in florianv/swap?

Add providers to `Builder` in the desired order and call `build()`. Swap skips unsupported pairs and tries the next provider after an error, then throws `ChainException` if every provider fails.

Can florianv/swap retrieve rates without an API key?

Yes, the README shows `european_central_bank` without a key. That provider is documented as EUR-based with daily granularity, so it has limited coverage and freshness.

Does florianv/swap cache exchange rates?

The README states that Swap caches results through PSR-16 `SimpleCache`. The excerpt does not document cache keys, expiration settings, or invalidation steps.

Does florianv/swap perform the currency amount conversion?

Swap retrieves the rate, and the quickstart applies `$amountInEUR * $rate->getValue()` to calculate the converted amount. The README also points to a moneyphp/money integration through `SwapExchange`.

Official sources

  1. florianv/swap on GitHub
  2. License: MIT
  3. Project website
  4. README
  5. Releases
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/florianv-swap.svg)](https://hysenlabs.com/projects/florianv-swap)

Was this useful?