Products

Multi-currency invoices: one bill, every supported asset

One customer holds Tron USDT, the next only has BTC in cold storage, a third reaches for USDC on Base. If your invoice quotes a single token, you are forcing two of those three to go swap first — and some of them just abandon. A multi-currency invoice presents the assets and networks halfin supports, the customer settles in whichever one they already hold, and the fiat amount you billed never changes regardless of how they pay.

01

The problem: a single-asset invoice narrows your customer down

Crypto holdings are fragmented. The same $49 can sit in a customer's wallet as TRC-20 USDT, as ETH, as SOL, or as native BTC, and those balances rarely interchange without a swap and a fee. When your invoice insists on one specific token on one specific network, every customer who holds something else has to bridge or convert before they can pay you — and a checkout that adds a step before payment is a checkout that loses people.

A multi-currency invoice removes that step. Instead of one address and one demanded token, the invoice offers the supported assets and networks, and the customer picks the rail they already have value on. You are not asking them to acquire a particular coin to do business with you; you are accepting the one they brought.

This is the same invoice object described on the invoicing hub — same lifecycle, same rate lock, same underpaid and overpaid handling. Multi-currency is about what the customer is allowed to choose at pay time, not a different product.

02

The fiat anchor does not move when the asset does

The figure you actually care about is the fiat amount: the USD or EUR you priced in, booked in your ledger, and reconcile at month-end. On a multi-currency invoice that anchor is fixed up front. The customer choosing USDT instead of BTC does not change what you billed — it changes which token amount halfin computes against the same anchored fiat figure.

When the invoice activates, halfin locks the conversion rate and pins a payable amount for each presented asset. The customer sees a concrete number per option — pay this much USDT, or this much BTC, or this much SOL — and all of those options resolve back to the one fiat amount. Whichever they confirm, the value that settles to your balance is the figure you started from.

Because the anchor is constant, your reconciliation does not branch by asset. A paid multi-currency invoice maps to the billed fiat amount the same way a single-asset one does; the asset and network the payment arrived on are recorded for accounting, not as a separate amount you have to re-value.

  • One fiat amount, set at creation — the customer's asset choice never re-prices it.
  • Per-asset payable amounts are computed from the locked rate and pinned at activation.
  • Reconciliation stays mechanical — every paid invoice maps back to the same billed figure.
  • The asset and network that settled are recorded for your books, not as a moving total.
03

What the customer can choose from

An invoice draws its payable options from the assets and networks where halfin's gates actually run. The matrix below is the real surface — an invoice presents from this list, not from a longer aspirational one. You can scope an invoice to a subset (say, stablecoins only) when that fits your business; left open, it offers the full set of supported rails.

Each row is an asset and the networks it settles on. The same USDT a customer holds on Tron and the USDC another holds on Base are both first-class payment options on one bill.

AssetNetworksWhy a customer reaches for it
USDTTron (TRC-20), Ethereum (ERC-20), SolanaMost widely held stablecoin; Tron is the low-fee default
USDCEthereum (ERC-20), Base, SolanaStablecoin for US and EVM-native payers
BTCBitcoinCustomers paying from cold storage or BTC-only wallets
ETHEthereum + ERC-20 tokensEVM-native balances and token settlement
SOLSolana (SOL + SPL)Fast, low-fee settlement
XRPXRP LedgerFast finality on the XRP Ledger
Native chain assetsBase, Arbitrum, Polygon, BNB Smart ChainPay on the chain where value already sits
04

What happens once the customer commits to a rail

A multi-currency invoice presents options, but a payment lands on exactly one network. When the customer selects an asset and sends funds, halfin matches the deposit on that chain against the invoice and runs the same crediting path as any single-asset invoice: it waits for the per-chain confirmation threshold, and crediting is reorg-aware, so a transaction unwound by a chain reorganization is reflected rather than silently counted.

Underpayment and overpayment are handled per the rail the customer actually used. If they send slightly less than the pinned amount for their chosen asset — a stale quote, an exchange withdrawal fee — the invoice records the shortfall against that asset so you can request a top-up or settle partially under your own policy. An overpayment is recorded the same way. The gap is measured in the asset that arrived, but it still resolves against the one fiat anchor.

Your backend learns about all of this through the same signed webhook events as any invoice — invoice.confirming, invoice.paid, invoice.underpaid, invoice.overpaid, invoice.expired. Verify the HMAC signature before you act, then read which asset and network settled if you need it for accounting.

05

Create a multi-currency invoice with one call

There is no separate endpoint. You create the same invoice as always — a fiat amount and currency — and the supported assets become the customer's payable options when the invoice is presented. Authenticate with a scoped API key, send the amount as a string (monetary values are strings end to end, never floats), and pass an idempotency_key in the body so a retried request never creates a duplicate.

The call below books a $120 invoice in USD. The customer who opens it can settle in any supported asset and network; the $120 anchor is unchanged whichever they pick. The full response schema, including the per-asset payable amounts, lives in the docs and the @halfin/sdk-merchant types.

curl -X POST https://api.thehalfin.com/api/v1/invoices \
  -H "X-API-Key: $HALFIN_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "amount_fiat": "120.00",
    "fiat_currency": "USD",
    "deferred": true,
    "description": "Annual plan",
    "idempotency_key": "00000000-0000-4000-8000-000000000002"
  }'

# The customer settles in whichever supported asset they hold — USDT on
# Tron, USDC on Base, BTC, ETH, SOL, XRP — and the $120 fiat anchor is the
# same no matter which they pick. See docs.thehalfin.com for the response schema.
06

Where multi-currency fits with the rest of checkout

A multi-currency invoice is what a hosted checkout renders as an asset picker for the customer, so the choice of rail happens in a page you do not have to build. If you want that picker to match your brand, hosted checkout customization controls how those options are presented; if your payers tend to scan with a wallet app, the QR code each option exposes makes paying the selected asset a single tap.

On the payout side, accepting many assets means your balances accrue across several of them — automated payouts and balance conversion are how you sweep or rebalance what comes in without managing each rail by hand. The point of multi-currency invoicing is to widen who can pay you without widening how much you have to operate.