Invoicing

Underpaid crypto invoice: what happens when a customer sends too little or too much?

Short answer: If a customer sends too little, the invoice stays open as partially paid: you hold the order until a top-up covers the balance or the invoice expires. If they send too much, the order counts as paid and you return the excess. Payzum, a non-custodial processor, shows the exact amount and detects overpayment.

Key takeaways

  • The usual cause of a short payment is an exchange that takes its withdrawal fee out of the amount the customer typed.
  • A short invoice sits in partially_paid and waits for a top-up until its timer ends. Payzum sends no webhook for that state today, so check the dashboard or poll the API.
  • An overpaid invoice reports finished. Compare actually_paid with pay_amount to find the excess, then send it back as a new transfer.
  • Two sentences on the checkout prevent the common mismatches: the exact amount with its network, and how to handle the exchange fee.

An underpaid crypto invoice usually starts with an email. The customer says they paid 180 USDC, and your dashboard shows 179.70. Both figures are correct: the missing 0.30 is the withdrawal fee the customer's exchange deducted before the money left.

Payments also arrive long, from a double send or a rounded-up top-up. Each case has a correct response, and the common ones can be headed off with a line of text on the checkout. The statuses below come from Payzum's public API, but the same logic holds for any processor that issues one invoice per payment.

Payzum is a non-custodial, stablecoin-first crypto payment processor: payments settle directly to wallets the merchant controls.

Why stablecoin payments arrive short or long

A card payment is pulled. The merchant asks for 180, and the issuer approves exactly 180 or declines. A crypto payment is pushed. The customer, or the customer's exchange, decides how much leaves the account, and the chain records whatever arrives. Almost every mismatch traces back to that difference, through one of four causes.

The exchange keeps its fee from the amount sent

Binance's guide to withdrawing crypto, updated on Sep 18, 2026, offers two ways to enter the amount. In "Receive amount" mode, the network fee is added on top, so the recipient gets the figure typed. In "Withdrawal amount" mode, the fee is deducted and the recipient gets what is left. A customer who types 180 in the second mode sends you 180 minus the fee.

The fees are small but never zero. Binance's withdrawal fee schedule, read on Nov 11, 2026, lists 0.3 USDC for USDC on Solana, 0.2 USDC on Base and 1 USDC on Ethereum. USDT on Ethereum costs 0.6 USDT. Coinbase's help center says it charges a fee based on its own estimate of network costs when a customer sends to an outside address. Any of those fees leaves your invoice open.

The customer types the wrong figure

A missing zero turns 1,200 into 120. A customer copying the amount from an email may round 180.004 down to 180. Wallets that scan the checkout QR fill the amount in for the customer, so this cause shrinks. Exchange withdrawal screens usually ask for the figure by hand.

The token travels on a different network

The same stablecoin lives on many chains. Circle says USDC is natively supported across 38 blockchain networks, a figure read on Nov 11, 2026. Tether's transparency data for the same day shows about 92 billion USDT issued on Tron and about 80 billion on Ethereum. A customer picks a network from a dropdown on the exchange, and it may not be the one on your invoice. Binance's own guide warns that funds sent on the wrong network might be lost.

The customer pays twice

A double tap in a wallet, or a full payment sent after a partial one, leaves the invoice long. It is easier to sort out than a short payment, because the customer often notices first.

What a mismatch costs when nobody catches it

The amounts are usually small. What costs money is handling the order wrongly, in one of these ways.

  • Shipping on a partial payment. A store that marks an order paid on any incoming transfer will one day release goods worth 1,200 against 120.
  • Letting a near-complete order expire. A 0.30 gap on 180 is 0.17%. If the invoice runs out of time with 179.70 inside, you have no sale and you owe a refund of 179.70.
  • Keeping an excess quietly. The customer sees the extra amount in their exchange history. An unanswered email about it turns into a public complaint, and the difference also breaks your month-end reconciliation.
  • Support time. Each case becomes a thread with the customer, often across time zones, while the order waits.

Why no processor can pull the missing amount

On a card network the merchant sets the figure at authorization. The customer never types it. A bank transfer is pushed, like crypto, and it arrives short for similar reasons: a typo, or a bank fee taken along the way. A stablecoin transfer follows the same push model. Payzum cannot pull the missing 0.30 from the customer's wallet, and neither can any other processor, because only the key holder can sign a transfer.

What a processor can do is make the right amount easy to send. EIP-681, an Ethereum standard with Final status created on Aug 1, 2017, defines a payment-request URL that carries the token, the recipient and the amount. Put it in a QR code and a wallet that scans it fills in all three. Solana Pay and Bitcoin's BIP-21 do the same on their chains. The weak spot is the exchange account, where the customer pastes the address and types the figure.

How Payzum tracks an underpaid crypto invoice

Every Payzum payment runs on its own invoice, with a fixed amount, a deposit address and an expiry. According to the hosted checkout docs, the payment page shows the chain, the exact amount to send, a countdown and a live status that updates as confirmations arrive. After a partial payment, the page and its QR code ask only for what is still due.

The merchant API reports five statuses: waiting, partially_paid, finished, expired and failed. The invoice lifecycle reference adds the details that matter for mismatches.

  • A short payment moves the invoice to partially_paid. It stays open until a top-up completes it or the deadline passes.
  • No webhook fires for a partial payment today. The buyer's screen updates, but your backend has to poll GET /v1/payment/:id or you check the dashboard. A partial-payment webhook is on the roadmap.
  • An excess above the merchant's tolerance, 5% by default, is stored as overpaid on the buyer page. The merchant API and the signed webhook still say finished.
  • Three informational notifications carry the invoice's current state without changing it: wrong_token_received, suspicious_token_received and late_deposit_received.

So the overpayment check lives in your own handler. A minimal version, after the signature check, looks like this:

if (p.payment_status === 'finished') {
  fulfil(p.order_id);
  const excess = Number(p.actually_paid) - Number(p.pay_amount);
  if (excess > 0) queueExcessReturn(p.order_id, excess);
}

The money itself never waits in a Payzum balance. Funds settle to your wallet, and Payzum keeps 0.5% of each processed sale from the amount received. On a 180 USDC sale, that is 0.90 USDC, and you keep 179.10. Network gas is extra and costs cents on Solana, Base or Polygon. The pricing page has the details.

On EVM chains and Solana, the hosted page also offers a "Pay with wallet" button. It asks the customer's wallet to sign exactly the transfer the invoice expects, so the amount, the token and the network cannot drift.

A 180 USDC grinder paid 0.30 short, minute by minute

A small online shop sells coffee grinders and prices them in USDC. A customer buys one for 180 USDC on Solana and pays from Binance.

TimeWhat happensAPI status
10:02The shop creates a 180.00 USDC invoice on Solana. The customer opens the hosted page.waiting
10:05The customer withdraws from Binance in "Withdrawal amount" mode and types 180. Binance deducts its 0.3 USDC withdrawal fee.waiting
10:06179.70 USDC arrives. The page now asks for 0.30, and the QR carries that figure.partially_paid
10:08No webhook fires. The shop's polling job flags the order, and support emails the customer.partially_paid
10:15The customer tries to send 0.30, but Binance's smallest USDC withdrawal on Solana is 3 USDC. They send 3.00 in "Receive amount" mode.partially_paid
10:16182.70 has arrived. The 2.70 excess is 1.5%, inside the 5% tolerance, so the page says paid. The webhook reports finished.finished
10:20The shop ships the grinder and returns 2.70 USDC to an address the customer confirms by email.finished

The exchange minimum at 10:15 is easy to overlook. Binance's fee schedule, read on Nov 11, 2026, sets the smallest USDC withdrawal on Solana at 3 USDC, so a customer who is 0.30 short and pays from that exchange cannot send 0.30. They overpay or they top up from a self-custody wallet. Your handling has to expect both.

The 2.70 belongs to the customer, and the shop returns it in full as a new transfer. The guide on how to refund a crypto payment covers the address check and the record to keep. One sentence about the exchange fee on the checkout would have spared the shop those emails.

Handling a short payment, step by step

  1. Find it. Poll GET /v1/payment/{order_id} every few minutes for orders that are still open, or filter the dashboard. Don't wait for a webhook.
  2. Tell the customer the exact remainder, the token and the network, with the invoice link. The page already shows only what is due.
  3. Hold the order. Nothing ships on partially_paid, whatever the size of the gap.
  4. When the status turns finished, compare actually_paid with pay_amount. Return or credit any excess under your written policy.
  5. If the invoice expires with funds inside, nothing ships. Send back what arrived as a new payment to an address the customer confirms.

Short, long, late or wrong token: the decision table

The buyer page and your API use different words for the same state, so the table gives both, with the response that fits each case.

CaseBuyer pageMerchant API and webhookYour move
Short by an exchange feepartialpartially_paid, no webhookAsk for the remainder before the timer ends
Short by a typopartialpartially_paid, no webhookSame, with a quick call if the gap is large
Long, within 5%paidfinishedShip, then return or credit the excess
Long, beyond 5%overpaidfinished; compare actually_paid with pay_amountShip, then return the excess
Paid after expiryexpiredexpired, plus late_deposit_receivedNo automatic shipping; new invoice at today's price, or return the funds
Other token sentunchangedwrong_token_received, status unchangedContact Payzum support with the transaction hash
Wrong networkunchangedno changeContact Payzum support before promising recovery

The last two rows are the only ones where the outcome is not in your hands. Collect the transaction hash, the network and the amount before you write to support, and tell the customer you are checking rather than giving a date.

Checkout wording that prevents most short payments

The cheapest fix happens before the customer pays. Payzum's create-invoice call accepts an order_description of up to 2,000 characters, shown on the checkout. Here is a version to adapt:

Send exactly 180.00 USDC on Solana. Paying from an exchange? Choose the option that sets the amount received, or add the withdrawal fee, so that 180.00 arrives. Use Solana only: a transfer on another network will not reach this order. If you send slightly less, this page shows what is still due, so pay it before the timer ends. We return any excess to an address you confirm by email.

Each sentence removes one support thread:

  • The amount and the network come first, in the same sentence.
  • The exchange fee is named in the terms customers see on screen. Binance calls the option "Receive amount".
  • The shortfall rule tells the customer what to do without writing to you.
  • The excess rule stops a worried customer from opening a dispute with their exchange.

Two settings help as much as the wording. Limit your accepted tokens to the networks your customers actually use, because fewer choices mean fewer wrong-network transfers. And set prices well above the exchanges' minimum withdrawals, so a customer is never forced to overpay to close a small gap.

Four businesses and the mismatch each one meets

The same four statuses show up very differently depending on what you sell.

  • A wholesaler bills a retailer 4,800 USDC on Ethereum. The retailer's finance team withdraws from Binance in "Withdrawal amount" mode, and 4,799 arrives after the 1 USDC fee. The fix is a line in the payment terms: send in "Receive amount" mode. The wholesaler adds it to every invoice, so the next one can close on the first transfer. For the paperwork side, see how to send a crypto invoice.
  • A design studio invoices 1,200 USDC on Base, and the client sends 120. The invoice sits in partially_paid with 1,080 due. The studio holds the final files and sends the invoice link again. The client scans the QR from a self-custody wallet, the amount fills itself in, and the invoice completes.
  • An online course creator sells a program for 89 USDC on Polygon. A student taps "send" twice, and 178 arrives. The excess is 100%, so the buyer page shows overpaid while the webhook says finished. The handler flags 89 USDC, and the creator returns it the same day.
  • A shop counter runs Payzum's point of sale, with a new QR for each sale. A customer pays from an exchange app on Solana, and the payment lands 0.70 USDT short after the exchange's fee. The cashier sees that the sale has not completed, asks for the remainder on the same sale, and hands over the goods once it shows paid.
The Payzum inline widget rendering the crypto checkout inside a page, with amount, order reference, expiry countdown and the embed snippet
Inside Payzum: the inline checkout widget, with amount, order reference and expiry countdown.

Card, bank transfer and crypto invoice: who can get the amount wrong

QuestionCardBank transferCrypto invoice with Payzum
Who sets the amountThe merchant, at authorizationThe payer, by handThe payer; the page and QR propose the exact figure
Can it arrive short?NoYes, through typos or bank feesYes; the invoice waits in partially_paid for a top-up
How an excess is spottedNot applicableBy hand, on the statementactually_paid against pay_amount; overpaid status above 5%
Reversal laterChargebacks for about 120 daysRecall requests between banksNone; you return an excess as a new transfer
Where the money sitsWith the acquirer until payoutYour bank accountYour own wallet, minus 0.5% per sale

Compared with a card, a crypto invoice gives up the amount the merchant sets and gains final payments with no chargeback window. The checkout wording and the status checks cover what you give up.

Doubts merchants raise about short and extra payments

Can I accept small shortfalls automatically?

Not through the status flow. Payzum's docs describe a 5% tolerance for overpayment only. Any amount below the total keeps the invoice in partially_paid. Preventing the shortfall at checkout saves more work than handling it afterwards.

Do I have to return a small excess?

It is the customer's money, so return it or offer it as credit, and say which in your terms before the sale. A clear threshold, such as returning anything above 1 USDC, keeps the decision out of each individual email.

Will customers find all this confusing?

Most of the confusion starts on the exchange screen. A customer who scans the QR from a wallet gets the amount filled in. A customer who pays from an exchange needs one sentence about the fee, and the template above gives it to them.

Frequently asked questions

What happens when a customer sends too little crypto for an invoice?

The invoice moves to partially_paid and stays open. The checkout shows only what is still due, and the customer can top up before the timer ends. If it expires first, nothing ships, and you return what arrived as a new payment.

What happens when a customer sends too much crypto for an invoice?

The order counts as paid. Payzum's merchant API and webhook report finished, so compare actually_paid with pay_amount to find the excess. Above the default 5% tolerance, the buyer page shows overpaid. Return the excess to an address the customer confirms.

Why did my customer's crypto payment arrive short?

Usually the exchange took its withdrawal fee from the amount typed. Binance's "Withdrawal amount" mode deducts the network fee, while "Receive amount" adds it on top. A typo in the amount is the next most common cause.

Does Payzum send a webhook for a partial payment?

Not today. Payzum's invoice lifecycle reference says partially_paid emits no webhook, so poll GET /v1/payment/:id or check the dashboard. A partial-payment webhook is on the roadmap.

What if the customer pays after the invoice has expired?

The invoice stays expired, and Payzum sends a late_deposit_received notification. Don't treat it as a paid order. Issue a new invoice at the current price, or return the funds as a new transfer.

Can crypto sent on the wrong network be recovered?

It depends on the network and the address, so contact Payzum support with the transaction hash before you promise the customer anything. Binance's own withdrawal guide warns that funds sent on the wrong network might be lost.

Book 20 minutes and stress-test your checkout

Every checkout meets short and extra payments sooner or later. Bring your order flow, your networks and one recent mismatched payment, and we will set up the wording, the status checks and the excess rule with you. Payments settle to your own wallet, and Payzum keeps 0.5% per sale.

Calendar not loading? Book directly here · [email protected]