Accounting & reconciliation

How to reconcile stablecoin payments with invoices and your accounting records

Short answer: To reconcile stablecoin payments with invoices, give every payment its own invoice, send your order ID with it, and match on the invoice ID and transaction hash instead of the wallet balance. Payzum is non-custodial, and its ledger records what arrived, the fee and the value in your reporting currency.

Key takeaways

  • A wallet transfer has no invoice number. The match key lives in the invoice you issue, not on the chain.
  • Use one invoice per payment and carry your order ID, so partial and overpaid cases show up as named exceptions.
  • The ledger includes invoice IDs, order IDs and transaction hashes, and the statement balance for a period should equal the Net on the Reports page.

Why a stablecoin transfer arrives with no invoice number on it

Payzum is a non-custodial, stablecoin-first crypto payment processor: payments settle directly to wallets the merchant controls. That keeps the money out of anyone's hands but yours. It also means the books are your job, and the first thing you learn is that a wallet history makes a poor ledger.

To reconcile stablecoin payments with invoices, you need something on each payment that points back to the invoice. Chains do not give you that for free. On Ethereum-style networks, a standard token transfer carries a sender, a receiver and an amount. The ERC-20 documentation on ethereum.org lists exactly those three values in the Transfer event and defines no memo or reference field. Your invoice number has nowhere to ride along.

Solana is different on paper. Its Memo program lets a sender attach text to a payment, and Solana's payments guide says memos are indexed by explorers and RPC providers, so they can be searched for reconciliation. In practice, the memo only exists if the payer's wallet added it. A customer paying from a phone wallet or an exchange withdrawal screen rarely does.

The match key therefore has to live in the system that issued the invoice.

What a month-end close looks like when forty clients pay into one wallet

Picture a design studio that bills about forty invoices a month in USDC. At close, the wallet shows forty-odd incoming transfers, each with an amount, a timestamp and a sender address. Five things go wrong, and they go wrong every month.

  • A client pays 1,500 against a 2,000 invoice and promises the rest next week.
  • Another sends 312 against a 300 invoice because they typed the wrong figure.
  • A payment lands two hours after the invoice expired.
  • One transfer comes from an exchange hot wallet shared by thousands of customers, so the sender address says nothing about who paid.
  • A client settles two invoices with a single transfer.

Start from the wallet and each of these is detective work in a block explorer. Start from the invoice and each one is a labelled exception that you can clear in a minute.

Why bank-style matching does not carry over to a wallet

A bank transfer comes with a payer name and a free-text reference, and your accountant matches on those. A card processor sends one deposit that bundles many sales net of fees, with a settlement report to explain it. Neither habit carries over. A chain gives you an address and a hash, and an address is not a customer.

The fix is to move the key to the place where the customer's intent is recorded, which is the invoice.

The three-part match key: invoice ID, order ID and transaction hash

Payzum ties each payment to an invoice. The invoice has an expiry, and Payzum detects overpayment on it. You create the invoice from your own system with your own order reference, so the pairing is made when the customer is asked to pay, before any money moves.

Everything after that is recorded against the pair. The accounting export on the taxes and accounting page turns every sale, conversion, fee and payout into a ledger line. The full ledger has 36 columns, including the invoice ID, the order ID and the transaction hashes, and you can download it as CSV or JSON. Partially paid and overpaid invoices are valued on what actually arrived.

Payzum charges 0.5% per processed sale, deducted from the amount received, plus on-chain network gas. The fee is booked as its own line. The gap between what the customer paid and what reached your wallet is therefore a visible number.

Each line is valued in your reporting currency, one of 31, using the European Central Bank reference rate for the date of the event. The ECB publishes those rates around 16:00 CET on working days and states that they are for information purposes only. Treat the rate as the documented method, and ask your accountant whether it suits your jurisdiction. Payzum provides records, not tax advice.

A month-end close in six steps

  1. Create one invoice per payment from your own system, and send your order ID with it. Never reuse an invoice for a second order, even for the same client.
  2. Let the signed webhook move the invoice status in your system. Verify the signature first, then update the order once per event. The signed webhooks guide covers the idempotency details.
  3. Once a week, open the exceptions: partial, overpaid and expired. Close them while the customer still remembers the order.
  4. On the 1st, take last month's frozen report. Payzum freezes it that day and emails you when it is ready, so the numbers cannot drift while you work.
  5. Import the statement file. QuickBooks Online and Alegra take a CSV with Date, Description and Amount, and Xero, Zoho Books and Odoo take OFX. Intuit's import guide, updated in 2026, lists those same three columns as the required ones.
  6. Check that the imported balance equals the Net on the Reports page for the same period. Then clear the open items by hand.

Five October payments, one partial and one overpaid

Here is a sample close for a small studio. The figures are invented for illustration. Payments are in USDC, the reporting currency is USD, and the fee column is 0.5% of the amount received. Network gas is separate and not shown.

InvoiceOrderInvoicedReceivedFee 0.5%NetStatus
INV-104188121,200.001,200.006.001,194.00Matched
INV-10428815450.00450.002.25447.75Matched
INV-104388202,000.001,500.007.501,492.50Partial: 500.00 open
INV-10448823300.00312.001.56310.44Overpaid by 12.00
INV-10458826800.00800.004.00796.00Matched
Total4,750.004,262.0021.314,240.69

Now the proof. Invoiced 4,750.00, minus the 500.00 still open on INV-1043, plus the 12.00 overpaid on INV-1044, equals the 4,262.00 that arrived. Take off 21.31 in fees and the net is 4,240.69. That is the figure the frozen statement should end on, and the one the Reports page should show.

Two rows need a person. INV-1043 stays open for 500.00, and you either chase it or write it off. INV-1044 holds 12.00 that belongs to the customer, so you refund it or credit it to their next invoice. Neither exception hides inside a wallet total, because the invoice ID names it.

Four billing patterns and where the match changes

The key stays the same, but the habit around it differs by how you bill.

  • A monthly retainer client, such as an agency or a bookkeeping practice, pays the same amount on the same day. One invoice per period stops March from being mistaken for April when the payment arrives late.
  • An online store uses the order ID as the key. The ledger carries both the order ID and the invoice ID, so a support question about a missing order resolves to one transaction hash in one lookup.
  • A freelancer paid from abroad issues one invoice per job. The freelancer guide shows how the client sees it, and the ledger shows you who paid what.
  • A shop with a POS gets a new QR per sale. In-person sales keep the terminal and the cashier in the ledger, so the end-of-day tally can be checked per cashier.
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.

Matching a bank deposit, a card payout and a stablecoin payment

At closeBank transferCard payoutStablecoin with Payzum
What identifies the paymentPayer name and a free-text referenceOne deposit bundling many sales, explained by a settlement reportInvoice ID, order ID and transaction hash
Where the fee showsA separate bank charge, or inside the exchange rateNetted out of the depositIts own ledger line, 0.5% of the amount received
Value in the reporting currencySet by the bank at conversionSet by the processorECB reference rate for the event date, per line
Can the number change after close?Returns and recalls can arrive laterDisputes can reverse sales weeks laterOn-chain payments are final, and the monthly report is frozen on the 1st

Objections from the person who keeps the books

Can't I just read the wallet and match amounts?

Only while every client pays the exact amount, once, on time, from a wallet you recognise. A single partial payment breaks that, and the sender address of an exchange withdrawal says nothing about the customer. Match on the invoice.

What if the customer pays from an exchange and no memo is attached?

The invoice is the key here, so the sender and the memo do not matter. You identify the payer from the invoice you issued, and the ledger keeps the sender address and the hash as evidence for the file.

Will the monthly numbers still move after I have imported them?

Not the frozen report. It is written once on the 1st and does not change afterwards. If a late payment arrives for an old invoice, it appears in the month it landed, with the invoice ID that tells you which month it belongs to.

Frequently asked questions

How do I reconcile stablecoin payments with invoices?

Issue one invoice per payment, send your own order ID with it, and match on the invoice ID and the transaction hash instead of the wallet balance. Then export the ledger, import the statement file into your accounting software and check that its balance equals the Net on the Reports page.

What happens when a customer underpays or overpays an invoice?

The ledger values the invoice on what actually arrived. An underpaid invoice stays open for the balance. An overpayment shows up as a difference that you refund or credit against the next invoice. Payzum detects overpayment on invoices.

Which accounting software can I import into?

QuickBooks Online and Alegra take a CSV statement with Date, Description and Amount. Xero, Zoho Books and Odoo take an OFX file. You can also download the full 36-column ledger as CSV or JSON, or pull it from the API at GET /v1/export/accounting.

Does Payzum give tax or accounting advice?

No. Payzum gives records: each line valued in your reporting currency with the European Central Bank rate for the date of the event. How to treat crypto and conversions is a question for your accountant and your tax authority.

Book 20 minutes and we'll trace one invoice end to end

Every business bills differently: per-job invoices, monthly retainers, a store with an order system or a counter with a POS. Book 20 minutes with our team and we'll walk one real invoice from creation to the month-end file, non-custodial, for your setup.

If the calendar doesn't load, book directly here · [email protected]

This guide is general information, not accounting or tax advice. Confirm how to record crypto payments with your accountant and your tax authority.