On this page9 sections
- Money doesn't come with a label
- The idea: give every payment somewhere specific to go
- What a virtual account is not
- Following one payment
- Two kinds: one that stays and one that's lent out
- What happens when someone pays late?
- Why an account number is a promise
- For engineers: a few design choices
- If you're choosing a payment setup
Picture a small business with one bank account. On a busy Saturday, eleven customers pay by transfer. Three of them send ₦15,000. One of them calls on Monday to say their order never arrived.
The owner opens the bank statement and finds three rows of ₦15,000. One shows a sender name that doesn't match the customer. Another came from a business account. The third came from someone the owner has never heard of, who may have been paying for a sibling. Which one is this customer? If none of them can be tied to the customer, the owner can't even say whether they paid at all.
The money is there. What's missing is the answer to a simpler question: who was this payment for?
A virtual account exists to answer that question before anyone has to ask it. If you've ever been shown an account number on a checkout page, or been given an account number when you signed up for an app, you've used one. This post explains what they are, in plain terms, and how we use them at Cloove.
The businesses, names and amounts in this post are illustrative.
Money doesn't come with a label
A bank transfer carries surprisingly little. There's an amount, the sender's name as their bank has it, a time, and sometimes a short note, which most people leave blank or fill with "payment".
None of that reliably says what the money is for. Names don't match because people pay from a spouse's, a friend's, or a business account. Amounts don't help when two orders cost the same. Notes are optional and easy to get wrong.
So when many people pay into one account number, somebody has to match each payment to a person or an order by hand. That works at five payments a day. At fifty, it's someone's whole morning. At five hundred, things start falling through the cracks, and the customer who calls on Monday is the one who notices.
The idea: give every payment somewhere specific to go
A virtual account is a real bank account number that's issued for one person or one purpose. You can send money to it from any bank app, like any other number. Your app shows an account name when you type it in, usually the business's or the service's rather than the individual's, so you know you're paying the right place.
The difference is what happens behind it. Think of a large apartment building with one street address and hundreds of mail slots. Mail for slot 4012 can only be for whoever lives in 4012. Nobody has to open the envelope to work out where it goes.
The building is the one bank account the money actually lands in. Each virtual account number is a slot that says whose mail it is. When money arrives at a number, the number itself tells you who it belongs to. No guessing from names, no matching on amounts.
What a virtual account is not
The word "virtual" makes it sound less real than it is, so it's worth being clear.
- It's not pretend money. Transfers to a virtual account are ordinary bank transfers. The money is real and arrives the same way.
- It's not a separate bank. The number is issued by a licensed bank or payment company, which we'll call our partner. The money lands with them, pooled in one account, not in a separate account for each number.
- It's not where the record of ownership lives. That's the job of the business's own records, its ledger. The virtual account says which slot a payment came through. The ledger says whose money it is and what it was for.
That last point matters more than it might seem. The account number is the label, and the ledger is the book that label gets written into. A virtual account makes the label reliable. Keeping the book right is still the business's job.
Following one payment
Here's what happens when a friend sends ₦20,000 to someone's virtual account number.
- The friend sends the transfer from their own bank app, to the number they were given.
- The money arrives at the partner that issued the number. They can see which number it was paid to.
- The partner sends us a message saying, in effect, "₦20,000 arrived at this number." This is automatic and usually takes seconds.
- We check it. We don't take the message at face value. We confirm it really came from the partner, and that we haven't already credited this payment.
- We credit the right wallet. The number tells us whose wallet. Any fee is applied, and the owner gets an alert.
Step 4 is where most of the care goes. Messages can arrive twice, so every payment is recorded against the partner's own reference for it, and a second message for the same payment changes nothing.
Messages can also fail to arrive at all, so we don't rely on them alone. If a customer says they sent money that never showed up, our team can ask the partner directly what has landed in that customer's account and compare it with what we've credited. A payment whose message went missing still gets found and credited once.
Two kinds: one that stays and one that's lent out
We use virtual accounts in two different ways, and the difference explains a lot of what you see on payment screens.
A permanent account, for a person. Once someone has verified their identity, they get their own number. It stays theirs. They can share it with family, put it on an invoice, or save it in their banking app. Anything sent to it is theirs.
A temporary account, for one sale. When a customer pays a verified business through our checkout, we show them an account number for that one order. The customer sees a countdown of about half an hour, but the number stays reserved for that order for up to two hours, and longer for things like hotel bookings. When the payment arrives, the order is marked paid. When the reservation ends, the number can go back into a pool and be lent to a different order later.
Lending numbers out like this is why a checkout page might show you a different account number every time you shop with the same business. It's not a mistake. Each number is being used to say "this payment is for this order."
What happens when someone pays late?
The obvious worry with a temporary number: what if the customer pays after the reservation has ended, and the number has been handed to someone else?
We designed for that case, because it happens. People get distracted, save the number, and pay the next day. When money arrives at a pooled number, we look at which orders that number has served:
- If it's still reserved for an order, the payment goes to that order.
- If the reservation ended but an earlier order on that number is still waiting to be paid, it's a late payment for that order, and we match it.
- If there's no order it can sensibly belong to, the money goes to the business's wallet, where they can see it and sort it out with their customer.
What we never do is let a payment disappear because it arrived at the wrong moment. Late money still lands somewhere a person can see.
Why an account number is a promise
Once people have your account number, it's out in the world. It's saved in banking apps, printed on invoices, and pinned in family group chats. You can't quietly change it.
We learned this firsthand when we moved our customers' accounts from one partner to another. Opening an account with the new partner needs the customer's own identity check, so we couldn't simply do it for them in the background. Each customer had to take a step themselves.
So during the move, a customer can have two active numbers at once: the old one and the new one. Money sent to the old number still arrives and is still credited, and when it does, we remind the customer to share the new one. The old number is only retired after people have had time to move over.
It took longer than flipping a switch would have. But the alternative was money being sent to a number that no longer worked, and that's the kind of problem that's much harder to undo than to avoid.
For engineers: a few design choices
If you're building with virtual accounts, here are the decisions that saved us the most trouble.
- Give accounts their own table, with history. We started with the account number stored as a few columns on the wallet. Moving providers meant overwriting them, which threw away the record of the old number, the one people were still paying into. Accounts now live in their own table, so a wallet can have an old and a new account, each with its own status.
- Route by account number, and keep your own reference too. Some partners echo back a reference you gave them when opening the account. Some don't, and only tell you which number was paid. Store whatever you set when the account was opened, because later on it's often the only thing the partner will let you look a payment up by.
- Pick the right key for "have we seen this before?" Use the identifier the payment network itself assigns to the transfer. Some references are chosen by the sender and can repeat, which would make a genuine second payment look like a duplicate.
- Treat the notification as a hint. Verify that it really came from the partner before crediting. Where you can, take the amount and the receiving account from the partner's own record of the payment, not from the message. And have a way to ask the partner directly about payments you never heard about.
- Never let an expired number swallow money. Decide in advance where a late payment goes, and make sure the answer is always somewhere a person will see it.
If you're choosing a payment setup
You don't need to understand the plumbing to benefit from virtual accounts, but a few questions are worth asking any bank or payment company you're considering:
- Does each customer or order get its own number, or does everyone pay into one account?
- What happens to a payment that arrives late, or to a number that's no longer in use?
- How quickly will you hear that a payment arrived, and what happens if that notification is missed?
- Can you get a list of everything paid to your numbers to check against your own records?
Good answers to those four will save you a lot of Monday mornings spent staring at bank statements.
If you'd like to talk about how this works, reach us at chat@clooveai.com.
Keep reading

Engineering
What reconciliation actually is
Some of our withdrawals got stuck, and we were fixing them by hand. Here's what that taught us about reconciliation, why a timeout mismatch costs the most, and how we handle it now.
Abraham Udele
Engineering
Your agent remembers the wrong balance
How a banking agent repeated a stale payment status as fact, and the memory design we built so it can't happen again.
Josiah Yahaya
Follow along
New posts on how we build Cloove: agents that move money, the systems behind them, and what we learn in production.

