Bookkeeping
Matching on-chain payments to your invoices
By Robert H.
A bank transfer carries a description. An on-chain transaction does not. Reconciling crypto payments means you supply the link the payment itself does not carry.

A bank transfer carries a description: "invoice 2026-041". An on-chain transaction does not. You get a hash, an amount, a sending address and a timestamp, and nothing else. Reconciling crypto payments means you supply the link the payment does not carry, and record it well enough that it still holds up two years from now.
When exactly the right amount arrives from a client you recognise, that takes seconds. In practice too little arrives, someone pays two invoices at once, or an address turns up that you have never seen. Below: how to make the link predictable, the five cases everyone runs into, and what to record when you make the match.
Why a crypto payment carries no description
A bank transfer is a message between two banks with fields in it: amount, name, IBAN, description. An on-chain transaction is an instruction saying that a number of units of a coin or token moves from address A to address B. What you get back is a hash, the amount, the addresses involved and the block's timestamp, in UTC. There is no field where "invoice 2026-041" fits.
There are exceptions, but fewer than people think. XRP has a destination tag, Stellar has a memo, and a few other networks have something comparable, largely because exchanges serve thousands of customers behind one address. Bitcoin and Ethereum have no such standard field, and where one exists, your client's wallet or exchange still has to support it and fill it in. You can ask for it; you cannot build on it.
What you do have is the receiving address: the one piece of information in the transaction that you influence in advance. The rest of this article turns on that.
Set up the link before you need it
The most reliable method is one receiving address per invoice. A modern wallet derives an unlimited number of addresses from the same seed; you use a fresh one per invoice and put it in the payment instruction. Anything landing on that address belongs to that invoice, even if the amount differs, arrives in two parts, or comes from a sender you do not know. The address is the reference.
With one fixed address you fall back on amount, timing and confirmation from the client. At low volumes that works, but it becomes unreliable the moment two clients send a similar amount in the same week. Agree instead that the client emails you the transaction hash as soon as they pay; it costs them ten seconds and saves you most of the guesswork. It also helps to be precise up front about what belongs on an invoice paid in USDC or bitcoin.
Take invoice 2026-041: EUR 1,450 excluding VAT, EUR 304.50 VAT, EUR 1,754.50 in total. The client pays in USDC on Polygon, and at the moment of confirmation the rate is 1 EUR = 1.08 USDC, so 1,894.86 USDC. That invoice is what goes wrong below.
Partial payments
1,000.00 USDC arrives, and three weeks later another 894.86 USDC. Two transactions, two hashes, one invoice.
Keep the invoice as a single item and hang several receipts off it, each with its own hash, timestamp, rate and euro amount. The first 1,000 USDC at a rate of 1.08 is EUR 925.93. The second tranche arrives at 1.10 and is EUR 813.51. Together EUR 1,739.44, against an invoice of EUR 1,754.50.
Note what does not change: your revenue stays EUR 1,450 and your VAT stays EUR 304.50. Both follow from the invoice, not from whatever came in. The EUR 15.06 difference is an exchange difference you post separately. Never split an invoice in two to make it add up.
One payment, two invoices
The same client also has invoice 2026-047 open: EUR 605.00 including VAT, or 653.40 USDC. They send everything at once, 2,548.26 USDC, one hash.
You split that receipt in your records, not on the blockchain. Record the same hash against both invoices, with the amount allocated to each, and note that it is a split receipt, with a reference to the other invoice. Anyone looking up either one later sees at once that the hash appears elsewhere, and why.
An amount that falls just short
For invoice 2026-052 of EUR 2,420 including VAT you expect 2,637.80 USDT at a rate of 1 EUR = 1.09 USDT. What arrives is 2,632.80 USDT: five USDT short, or EUR 4.59.
Almost always this is a withdrawal fee: the client paid from an exchange, and the exchange deducts its fee from the amount sent. From a self-custody wallet that usually does not happen, because there the sender pays the network fee separately, on top. Which of the two you see depends on where your client pays from.
Do not leave an invoice open for EUR 4.59. Mark it paid, post the shortfall as a payment difference to a separate account, and move on; your VAT does not change, because it follows the invoice. If shortfalls are structural, that is not a bookkeeping problem but an agreement problem: state in your payment terms that the client bears the fees.
A payment on a different network
You asked for USDC on Polygon and nothing arrives, but the client says they paid and sends a hash.
On EVM networks, Ethereum, Polygon, Arbitrum, Base and Optimism, the same address is valid on every chain. A payment sent to "your address" on Arbitrum is sitting on your address, just on a chain you were not watching. Add the network in your wallet and the tokens appear. For your records it is an ordinary receipt, with the actual network recorded rather than the agreed one.
Outside the EVM family it works differently. A Solana or Tron address has a different format, so a client holding your Ethereum address cannot send there by accident: that transaction either fails or the money ends up somewhere you cannot reach. That is no longer a reconciliation problem. Always state the network explicitly in your payment instruction, alongside the coin.
A sender you do not recognise
There is 653.40 USDC on your address, from an address you have never seen, with no name attached.
Match on amount and timing, and confirm it with the client. One email, "I see 653.40 USDC arrive on 14 March at 11:02, is that your payment of invoice 2026-047?", and you keep the reply with the transaction. That reply is your link; the address on its own is not.
Build an address book alongside it: once a payment is confirmed, record the sending address against that client so you recognise it next time. That is an indication, not proof. If your client pays from an exchange, the address belongs to the exchange, can change per withdrawal, and may be shared with thousands of others. A familiar address makes reconciling faster, not certain.
What to record at the moment you match
Reconciling is only finished when the link itself is recorded. For each matched payment, capture seven things: the invoice number, the transaction hash, the network, the receiving and sending address, the coin with the exact number of units, the confirmation timestamp, and the euro amount with which exchange rate you book a crypto payment at.
On top of that, and this gets forgotten most often, record why you made the link: for a partial payment the amount allocated and what remains, for a split payment the other invoice, for a shortfall where you posted it, for an unknown sender the client's confirmation. A matched line without a reason is an assumption, and an assumption from two years ago cannot be reconstructed.
Convert timestamps consistently. Blockchains log in UTC and your books run in local time; in summer that is a two-hour gap, enough to drop a payment made on 1 January at 00:30 into the wrong quarter. And do it straight away: a payment from yesterday you match with the client's email still on screen, one from eight months ago you match on an amount that roughly fits.
This manual work, finding incoming transactions, converting them to euro, hanging them off the right invoice, sorting out partial payments and shortfalls, and documenting the link, is exactly what stbl admin was built for. It watches your wallets across several networks, values every receipt at the confirmation timestamp against a fixed rate source, proposes the match with the open invoice and records it including hash, rate and allocation, partial and split payments included. Your keys stay yours: stbl admin is non-custodial and never touches your money. The Pro plan is EUR 49 per month excluding VAT.
Match payments to invoices without the guesswork
stbl admin follows your wallets, values every receipt in euros and proposes the match with the right invoice, partial and split payments included.
Get started