Skip to content

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

FieldMeaning
presentment_currencyWhat the customer sees on the invoice.
settlement_currencyWhat 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

EventWhen
invoice.fx_rate_lockedRate stamped at finalisation. Useful for downstream books.
payment.settledPayment captured at the provider, including final settlement amount and rate.
fx.rate_staleA finalisation was rejected for stale FX.