TillsafeDocstillsafe.comRequest early access

Underpaid, overpaid, late

What happens when the payer sends too little, too much, too late, the wrong token or the wrong chain.

Payers get amounts wrong all the time: an exchange deducts its withdrawal fee from the amount, someone rounds, someone pays the next morning. Every case below is decided by what actually arrived at the invoice's address, and every one ends either credited or refundable. Nothing is ever lost in between.

Underpayment

Your tolerance. underpay_tolerance_bps in POST /v1/merchant/settings lets you accept a small shortfall as full payment: 50 means 0.5%. It starts at 0 (exact amounts only) and can be at most 1000 (10%). An invoice keeps the tolerance it was created with, so a change applies to new invoices only.

  • Short by no more than the tolerance: the invoice is paid, and the payer owes nothing more.
  • Short by more: the invoice is partially_paid, and amount_remaining says what is missing. The checkout asks the payer to send the rest to the same address (or in another asset the invoice accepts), and the payments add up. When the total reaches the threshold, the invoice is paid.
  • Still short when the invoice expires: it becomes expired, and what arrived is refundable (create the refund with an explicit amount). Accepting a short payment as full is not offered through the API today: raise your tolerance for future invoices instead.

Overpayment

An excess of at least 0.01 of the stablecoin the invoice is priced in makes the invoice overpaid. A smaller excess leaves the invoice simply paid: that budget is what lets connected-wallet payments carry a unique amount (see connected wallet). The 0.01 floor applies to every payment on an invoice that offers a stablecoin, BTC included; on an invoice that offers only BTC, any excess counts.

overpaid is a paid status: fulfil the order. If you want to give the excess back, create a refund without an amount: it defaults to exactly the excess (on a paid invoice too, where that is the small excess that was kept). See refunds.

Late payments

  • Within 10 minutes after expires_at (a stablecoin payment): still credited. If it completes the payment, the invoice is paid_late. Treat it like paid.
  • After the invoice expired or was cancelled: the status stays expired or cancelled. You get an invoice.late_payment webhook, the payer sees a notice, and the payment is refundable with reason late_payment (create the refund with an explicit amount). Today a late payment cannot be accepted through the API; fulfil it manually if you want to keep it.
  • An address stays tied to its invoice for its lease (24 hours) and a 72-hour cooldown after it. Payments to the address in that time are attributed to the invoice; nothing later can be.

Volatile assets (BTC)

A BTC amount is fixed for the 15-minute price lock (price_locked_until). A BTC payment after the lock is priced again at its arrival:

  • If the price moved against you by at most 1%, the original amount still stands, and the invoice is paid_late when it completes.
  • If it moved against you by more, the amount due is recalculated at the new price and the payer is asked to top up the difference.
  • A move in your favour never changes the amount.

Wrong token

A token the invoice did not ask for, sent to its address (USDC to a USDT-only invoice, for example), is never counted toward the invoice. You get an invoice.wrong_asset webhook, the payer sees a notice, the status does not change, and the transfer is refundable: create a refund with that asset and "reason": "wrong_asset" (the reason is not inferred), and the default amount is all of it. If you want to accept a token, list it among the invoice's assets. Tokens nobody recognises are ignored.

Wrong chain

An invoice uses the same deposit address on every EVM network your account has enabled. If a payer sends the right token on another of those networks (BSC instead of Ethereum, say), it is credited normally, at the same price. Those networks are not shown as options; they are there to catch the mistake. A mistake across chain families (a TRON address used on an EVM chain) cannot be rescued.