Multi-currency & FX
Paylera lets you bill customers in their preferred currency (presentment currency), settle into the currency your bank account holds (settlement currency), and reconcile the gap with explicit FX-gain/loss postings.
The two currencies
| Field | Meaning |
|---|---|
presentment_currency | What the customer sees on the invoice. |
settlement_currency | What lands in your bank when the payment provider settles. |
Often they’re the same. When they differ — a EUR invoice paid through a
USD-settling Stripe account — the invoice records both, plus the
fx_rate used and the source.
Where the rate comes from
fx_rate_source:
provider— the rate the payment provider quoted at capture (recommended; matches what they’ll deposit).ecb— yesterday’s European Central Bank reference rate.manual— you POST a rate per currency pair; we use the most recent.
The choice is per-tenant. Most teams pick provider for hosted-checkout
flows and ecb for invoice-only flows that settle later.
Locking the rate
The rate on an invoice is locked at finalisation. Once an invoice is
open, the rate cannot change — even if the spot rate moves before the
payment captures. This is what makes the books reconcile.
fx_rate_locked_at records the timestamp the rate was captured.
Multiple currencies on one customer
A customer can have any number of subscriptions in any number of currencies. They cannot share a wallet (one wallet per currency per customer), but they can share a payment method (the provider handles the conversion or rejects, depending on the method).
The ledger
When presentment and settlement currencies differ, every payment posts two legs plus an explicit FX-gain/loss leg:
Cash (settlement_currency) 100.00 USD debit AR (presentment_currency) 92.00 EUR credit FX gain/loss 0.40 USD credit (or debit if loss)The FX leg is computed from (amount_settled_in_settlement_currency) − (amount_invoiced_in_presentment × fx_rate_locked_at). It always nets to
zero when summed against the cash and AR legs in their original currencies.
Reporting
Reports group amounts by their functional currency — the currency you chose to keep your books in (set on the tenant configuration). Anything not already in that currency is converted at the rate locked on its originating invoice. There is no “spot rate at report time” smear — each line carries its own historical rate.
Stale FX
If fx_rate_source: ecb and the most recent ECB rate is older than 36
hours, finalisation of any cross-currency invoice fails with
fx.stale_rate. The default policy is fail-loud rather than silently
charge with a stale rate.
For fx_rate_source: manual, the same threshold applies. The
fx-stale runbook is your operations playbook.
Common pitfalls
- Customer changes currency mid-flight. Don’t try to “convert” an existing subscription. Cancel it, create a new subscription on a plan in the new currency, and refund the unused portion of the old one.
- Refund in the wrong currency. Refunds always return in the payment’s settlement currency. If you owe the customer EUR but they paid in USD, you’ll refund USD — and they’ll bear the spread.
- Tax in the presentment currency. Always. The tax engine computes tax in the invoice currency.
Webhook events
| Event | When |
|---|---|
invoice.fx_rate_locked | Rate stamped at finalisation. Useful for downstream books. |
payment.settled | Payment captured at the provider, including final settlement amount and rate. |
fx.rate_stale | A finalisation was rejected for stale FX. |