Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Swap Laravel Package

florianv/swap

Swap is an easy-to-use PHP currency conversion library that retrieves exchange rates from 30+ providers behind a single API, with PSR-16 caching, historical rates, and automatic provider fallback. PHP 8.2+, maintained since 2014.

View on GitHub
Deep Wiki
Context7

Product Decisions This Supports

  • Build vs. buy for FX rate plumbing. Swap answers a recurring build-vs-buy question: do we own provider integrations, retry logic, fallback chains, caching, and historical rate retrieval, or do we consume it? With 30 providers behind one interface (18 commercial, 10 public/no-key), the marginal engineering cost of "add another rate source" drops from days to hours. That reframes FX from a bespoke subsystem into a commodity dependency.
  • Multi-currency pricing as a scoped, deferrable roadmap item. If the roadmap contains "show localized prices for EU/UK/CA visitors," Swap makes this a small, near-term shippable slice rather than an epic. Display-only conversion is low risk: retrieve a rate, multiply, cache. It is not a substitute for settlement-grade FX, but it unblocks the pricing experiment cheaply.
  • Choosing a latency/freshness/cost posture per use case. The provider table is effectively a pricing-tiers artifact. Free public sources (ECB, national banks) are EUR-base or single-quote-currency with daily granularity — fine for a storefront price display, wrong for a checkout total refreshed hourly across pairs. Commercial providers (~$18/mo entry) buy breadth and update frequency. The PM decision is which surfaces get which tier, and Swap lets us mix them in one fallback chain rather than committing globally.
  • Reliability posture for money-adjacent surfaces. The documented fallback chain (skip unsupported pairs silently, try next on error, raise ChainException with all errors when exhausted) means uptime of any single vendor is not a product-level dependency. That directly supports a "we can launch FX display without a new vendor SLA negotiation" decision, and it de-risks single-vendor outages.
  • Invoice and reconciliation correctness for historical rates. Historical rate support is what turns "convert now" into "convert as of the transaction date." For invoicing, ledger reconciliation, and audit trails, this is the difference between a feature we can ship and one we must build ourselves. It also shapes a durable product decision: store the rate and the rate date and the provider name at transaction time rather than recomputing later.
  • Scope control on the "which abstraction" question. The ecosystem is layered (Swap → Exchanger → Laravel/Symfony adapters). Choosing the high-level Swap for typical app work and reserving Exchanger for cases needing finer chain/caching/HTTP control prevents premature abstraction. Notably, the Laravel adapter exists as a separate package — relevant if the codebase is Laravel and we want config-file and service-container integration rather than manual Builder wiring.
  • Sizing a self-hosted vs. hosted FX service decision. Because caching is PSR-16 and the HTTP client is PSR-18 (anything works, auto-discovered), the package slots into existing infrastructure — no new cache, no new HTTP stack. That materially lowers the switching cost both in and out, which makes it a reversible decision.

When to Consider This Package

Adopt it when:

  • The need is rate retrieval and conversion convenience, not a treasury function. Display pricing, invoice totals, ledger reconciliation, internal FX dashboards, and multi-currency catalog views are the documented sweet spot.
  • You are on PHP 8.2+ already, or can be. This is a hard floor, not a soft one.
  • Your stack is PSR-compliant: a PSR-18 HTTP client and PSR-17 factories are prerequisites, and a PSR-16 cache is how you avoid hammering providers. If you already run Symfony HttpClient or Guzzle and a PSR-16 cache, marginal integration cost is near zero.
  • You want provider optionality as a hedge: free public sources to prototype and validate demand, commercial sources when volume or pair breadth demands it, without a rewrite.
  • You need historical rates — this is the requirement that most cleanly separates Swap from rolling your own single-vendor client.
  • You can accept floats and a "retrieve rate, multiply yourself" contract. Swap returns the rate; amount conversion is the application's job (with a moneyphp/money bridge available via SwapExchange). If you need decimal-exact arithmetic as a first-class guarantee, that logic lives on your side.

Look elsewhere when:

  • You need settlement, hedging, or accounting-grade FX with contractual rate guarantees, spread handling, and reconciliation against a bank. Swap is a rate fetcher, not an FX engine.
  • Compliance or data-residency constraints dictate a specific provider, or forbid the free public sources (several are national central banks with their own terms).
  • You need cryptocurrency pricing as a primary requirement — support exists but is thin and inconsistent (Cryptonator and 1Forge have no historical; coinlayer has both, at a price).
  • Long-term maintenance risk tolerance is low. A 1,341-star, single-primary-author library maintained since 2014 with documented releases and changelog is a reasonable bet, but it is not a vendor with an SLA. The sponsor relationship (fastFOREX is both the recommended default and the sponsor) is worth naming in any review: it is disclosed and benign, but it means the default path points at a commercial dependency.
  • You want Laravel-native configuration out of the box. The base package is framework-agnostic; you'd add florianv/laravel-swap for container and config integration rather than hand-wiring the Builder.
  • You need first-class rate alerting, streaming, or websocket updates — this is a request/response library with caching, not a market data feed.

How to Pitch It (Stakeholders)

For executives: We have a small, well-scoped multi-currency capability available at near-zero engineering cost. Swap is an MIT-licensed PHP library, maintained continuously since 2014, that pulls exchange rates from 30 providers behind one interface with caching and automatic fallback. Practically: we can turn on localized pricing and multi-currency invoices without building or contracting a new vendor relationship, starting free (European Central Bank and other public sources) and moving to a paid provider at roughly $18/month only when we need breadth or refresh frequency. Because it plugs into HTTP clients and caches we already run, adopting it is reversible — the exit cost is low. The main caveats to acknowledge: it is a rate fetcher, not a treasury system, so it's appropriate for display and reconciliation, not settlement; and it is a single-maintainer open-source project rather than a vendor with an SLA, which is a risk we mitigate with the fallback chain rather than a contract.

For engineering: Framework-agnostic PHP 8.2+ library. Install is composer require florianv/swap plus a PSR-18 client and PSR-17 factories (Symfony HttpClient + Nyholm PSR-7 is the documented happy path; Guzzle 7 works identically). You construct it with a Builder, register providers by identifier, and get an ordered fallback chain: unsupported pairs skip silently, errors cascade to the next provider, and exhaustion throws a ChainException carrying every collected error — so failures are debuggable, not swallowed. latest('EUR/USD') returns a value object with getValue(), getDate(), getProviderName(). Caching is PSR-16 with both minimal and per-query configuration, plus HTTP-request-level caching; you can inject a client explicitly via useHttpClient() instead of relying on discovery. Historical rates are supported by the providers that advertise them. Custom sources are an ExchangeRateService implementation passed to addExchangeRateService(). Two things to plan for: the library returns a float and does not do the multiplication for you (there's a moneyphp/money bridge via SwapExchange), and if we're on Laravel we should evaluate adding florianv/laravel-swap for container/config wiring instead of hand-rolling the Builder in a service provider. If we later need finer control over chain composition or HTTP plumbing, the lower-level florianv/exchanger exposes the same 30 providers directly.

For the product org: Two things to lock down before we build on this. First, persist the rate, the rate date, and the provider name at the moment of the transaction — historical rates exist, but recomputing a past conversion later is how reconciliation bugs happen. Second, decide per-surface which tier we use: free daily-granularity public sources for catalog display, a commercial provider with broader pair coverage for anything customer-facing at checkout. That's a small decision now and a painful retrofit later.

Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
jinas/dhivatar
store-doc/laravel-storage-driver
plus-it/laravel-translation-manager
diephp/perhaps
diephp/telegraph
osmaviation/spreadsheet
microsoft/fluentui-system-icons
mmccook/php-json-canonicalization-scheme
middlewares/firewall
qubiqx/montapacking
nyoncode/laravel-package-console
pnscripts/filament-broadquill-lite
pnscripts/laravel-sentfold-lite
vleap/mx-sdk-laravel-internal
twidpay/utils
htetmyathlaing/scout-elasticsearch-driver
artisan-toolbox/front-awesome
ls/client-assistant
users-au/laravel-client
cgv/localized-resource