I had 60 M-Pesa till statements and three different order logs—nothing matched
I run a small online shop selling phone accessories, power banks, and charging cables. I take orders on Shopify, through WhatsApp, and occasionally through Instagram DMs. Payment is almost always M-Pesa—customers send money to my till number, I confirm, then I hand the package to a boda rider who delivers it the same day if they're in Nairobi, next day if they're in Kiambu or Machakos.
The problem is reconciliation. Every month I need to match M-Pesa till statements against three different logs: Shopify orders (which have customer names and order numbers but not always phone numbers), WhatsApp orders (which I track in a Google Sheet with phone numbers, product names, and amounts), and boda delivery logs (which have phone numbers, delivery fees, and timestamps). M-Pesa statements have phone numbers, transaction codes, amounts, and timestamps, but no customer names unless the customer added one when sending the money. Nothing lines up cleanly.
In March I had 60 till transactions to reconcile. I tried doing it in Excel. I spent four hours sorting, filtering, and using VLOOKUP to match phone numbers between sheets. I still had eight transactions I couldn't match—either the phone number was missing from one log, or the amount was off by KSh 50 because I'd forgotten to add delivery fees, or the timestamp was three hours different because the boda guy confirmed pickup late. I was exhausted, and I still didn't trust the numbers.
Last week I tried again, this time using Claude Sonnet 4.5 and Gemini Flash on Kryotta. I wanted to see if AI could handle the messiness—mismatched phone formats, missing names, delivery fees buried in notes fields. It worked. I reconciled all 60 transactions in one afternoon. But I broke it twice before I got it right, and I learned exactly which model handles Kenyan phone numbers better.
Step one: export everything into CSVs (and clean nothing yet)
I exported four files:
- M-Pesa till statement (CSV from the M-Pesa business portal)
- Shopify orders (CSV export, last 30 days)
- WhatsApp orders (my Google Sheet, exported as CSV)
- Boda delivery log (another Google Sheet, also CSV)
I didn't clean anything. Phone numbers were a mess—some had +254, some had 0, some had neither. Amounts in the boda log included delivery fees; amounts in Shopify didn't. Timestamps were in different formats. I wanted to see if AI could handle real data, not data I'd spent an hour preparing.
I uploaded all four files to Kryotta and started with Claude Sonnet 4.5.
Step two: the first prompt (which failed because I wasn't specific enough)
Here's what I wrote:
"Match these M-Pesa transactions to orders in the Shopify, WhatsApp, and boda logs. Show me which transactions match and which don't."
Claude gave me a table. It matched 14 out of 60 transactions. The rest it marked as "no match found." I checked a few manually—they should have matched. A WhatsApp order for KSh 1,200 had an M-Pesa transaction for KSh 1,350 (the extra KSh 150 was delivery), but Claude didn't connect them because the amounts were different.
The problem: I hadn't told it how to match. Should it match on phone number alone? Phone number and amount? What if the amount was off by a delivery fee? What if the phone number format was different?
I rewrote the prompt.
Step three: the second prompt (which worked, but only after I fixed the phone numbers)
Here's the revised version:
*"Match M-Pesa transactions to orders using these rules:
- Match on phone number first. Normalize all phone numbers to the format 2547XXXXXXXX (remove +, remove leading 0, add 254 if missing).
- If the M-Pesa amount is KSh 100–200 higher than the order amount, check the boda log—it's probably a delivery fee. Match it anyway and note 'delivery included.'
- If there's no phone number in the Shopify log, try matching on amount and timestamp (within 2 hours).
- Show me matched transactions, unmatched transactions, and any duplicates. Give me a table with columns: M-Pesa transaction code, phone number, amount, matched order source (Shopify/WhatsApp/none), order reference, notes."*
Claude ran it. This time it matched 52 out of 60. Much better. But I noticed something: five of the matches were wrong. It had matched an M-Pesa transaction for KSh 800 to a Shopify order for KSh 800, but the phone numbers were completely different—it had ignored the phone number rule and matched on amount alone because the Shopify order had no phone number in the export.
I realized the issue: Kenyan phone numbers are formatted inconsistently everywhere. Some M-Pesa transactions showed +254712345678. Some showed 0712345678. Some Shopify orders had the number in a notes field, not the phone field. Claude was trying, but it was getting tripped up by the formatting.
Step four: I switched to Gemini Flash for the phone number cleanup
I copied the M-Pesa statement and the three order logs into a new Kryotta chat with Gemini Flash and asked it to do one thing:
"Normalize all phone numbers in these four files to the format 2547XXXXXXXX. If a phone number is in a notes field or a name field (like 'Jane 0712345678'), extract it. If there's no phone number, leave that row blank in the phone column. Give me four cleaned CSVs."
Gemini handled this better than Claude. It found phone numbers buried in Shopify customer notes ("Delivered to 0723456789"), extracted them, and normalized everything. It took two minutes. I downloaded the four cleaned CSVs.
Then I went back to Claude Sonnet 4.5 with the cleaned files and the same matching prompt. This time: 58 out of 60 matched.
The two transactions that still didn't match (and why)
Two M-Pesa transactions had no match in any log. I checked manually. Both were legitimate—customers had paid, I'd sent the products—but I'd never recorded the orders. One was a WhatsApp order I took while I was at a chama meeting and forgot to add to the sheet. The other was an Instagram DM order I'd handled entirely in my head.
This is the value: AI didn't create a match where none existed. It showed me the gaps. I added those two orders to the WhatsApp log manually, re-ran the prompt, and everything reconciled.
What I learned: Gemini is better at messy phone numbers, Claude is better at conditional matching
Gemini Flash handled phone number extraction and normalization better. It found numbers in weird places (notes fields, customer names, delivery instructions) and formatted them consistently. Claude Sonnet 4.5 was better at applying conditional logic—"if the amount is higher, check the delivery log; if the timestamp is close but the amount is off, flag it as possible duplicate."
If I were doing this again, I'd use Gemini to clean the data first, then Claude to do the matching. That's exactly what I did the second time, and it worked in 40 minutes instead of four hours.
The checklist: how to reconcile M-Pesa payments with AI
Here's the process I'd follow every time now:
1. Export everything as CSV, don't clean it yet.
M-Pesa statement, Shopify orders, WhatsApp log, boda log—whatever you've got. Leave the mess intact.
2. Use Gemini Flash to normalize phone numbers.
Prompt: "Normalize all phone numbers to 2547XXXXXXXX. Extract numbers from notes fields if needed. Give me cleaned CSVs."
3. Use Claude Sonnet 4.5 to match transactions.
Prompt: "Match M-Pesa transactions to orders. Match on phone number first. If amount is KSh 100–200 higher, check delivery log. If no phone number in Shopify, match on amount and timestamp (within 2 hours). Show matched, unmatched, and duplicates."
4. Check the unmatched transactions manually.
AI won't invent matches. If something's unmatched, you probably forgot to log it.
5. Re-run the prompt with any missing orders added.
Takes 30 seconds.
I've done this twice now. March reconciliation: 60 transactions, 40 minutes. April reconciliation: 73 transactions, 35 minutes. I'm never going back to Excel.
Questions people ask
Can I do this if I don't use Shopify?
Yes. As long as you can export your orders as a CSV (Google Sheets, Excel, a notebook you've typed up), the process is the same. The key is having phone numbers and amounts in some consistent format.
What if my M-Pesa statement doesn't have phone numbers?
It should—till statements show the sender's phone number for every transaction. If you're using a paybill instead of a till, you might only see account numbers. In that case, you'll need to match on amount and timestamp, which is messier but still possible.
Does this work for Airtel Money or other mobile money platforms?
I haven't tested it, but the logic should be the same. Export the statement, normalize phone numbers, match on number and amount. The prompts would be identical.
How much does it cost to run this on Kryotta?
I used Claude Sonnet 4.5 and Gemini Flash for two reconciliations (133 transactions total). Cost was under KSh 150. Compare that to four hours of my time at even KSh 500/hour, and it's absurdly cheap.
I'm not going to pretend this solves every accounting problem. You still need to check the unmatched transactions yourself. You still need to keep your logs up to date. But if you're spending hours every month trying to match M-Pesa payments to orders, this will cut that time by 80%. Try it once with last month's data—start a free workspace on Kryotta and see if it works for your setup.



