Claude vs Gemini for M-Pesa statement reconciliation: I tested 80 till reports

I tested Claude and Gemini on 80 M-Pesa till statements to see which AI model could cut my three-hour daily reconciliation down. Here's what actually worked.

KKryotta TeamProduct & research · · 8 min read
Shopkeeper at electronics counter reviewing M-Pesa transactions on phone and laptop, with accessories displayed behind
Shopkeeper at electronics counter reviewing M-Pesa transactions on phone and laptop, with accessories displayed behind

I ran the test because I was spending three hours a day on Excel

I run a small electronics shop in Nairobi—phone accessories, chargers, power banks, earbuds. We take orders through WhatsApp, sell on Jumia, and run a small Instagram shop. Every payment comes through M-Pesa: C2B for walk-ins, Buy Goods for online orders, sometimes Paybill when a customer gets the number wrong. By 6 p.m. I have 40 to 60 transactions in the till statement and a WhatsApp chat full of "I've paid" screenshots.

Reconciling used to take three hours. I'd download the CSV from the M-Pesa portal, open the WhatsApp chat on my laptop, cross-check each transaction code against the order, flag duplicates, hunt for the customer who paid KSh 1,500 when the invoice said KSh 1,800. Then I'd do the same for Jumia orders. By the time I was done, it was 9 p.m. and I'd missed two new WhatsApp orders.

Last month I decided to test whether Claude or Gemini could do this faster. I exported 80 till statements from January and February—2,400 transactions total—and ran them through both models with the same reconciliation prompts. I wanted to know which model caught mismatched amounts, which one handled duplicate transaction codes without hallucinating, and which one I could trust when a customer claimed they paid but the code wasn't in my statement.

Claude caught mismatched amounts, Gemini mixed up customer names

I started with a simple task: match 40 M-Pesa transactions against 40 WhatsApp orders. Each order had a customer name, a phone number, an amount, and a timestamp. The M-Pesa statement had a transaction code, a sender name (often different from the WhatsApp name), an amount, and a timestamp.

Claude Sonnet 4.5 got 38 out of 40 correct. It flagged two mismatches: one where the customer paid KSh 1,200 instead of KSh 1,500, another where the payment came from a different phone number (husband's line, same surname). It listed both in a clean table with the discrepancy highlighted.

Gemini Flash got 34 out of 40 correct. It matched the amounts fine, but it kept confusing customer names. A payment from "Jane Wanjiku" got matched to an order from "Jane Muthoni" because both first names matched and the amounts were close. It also missed one duplicate transaction code—two customers had sent payments within ten minutes, both using the same Safaricom agent, and the codes were identical except for the last digit. Claude caught that; Gemini didn't.

For basic amount matching, both models work. For catching name mismatches and near-duplicate codes, Claude is better. I now use Claude for the first pass.

Gemini was faster for bulk Jumia invoice matching

Jumia sends a daily sales report with order numbers, customer names, amounts, and expected M-Pesa codes. The problem is that Jumia's "expected" code doesn't always match what actually lands in the till statement—sometimes the customer pays late, sometimes Jumia batches payments, sometimes the code is just wrong.

I gave both models 30 Jumia invoices and the corresponding day's till statement (120 transactions). The prompt was: "Match each Jumia order to an M-Pesa transaction. If the code doesn't match but the amount and timestamp are within two hours, flag it as a probable match. If there's no match, list it as missing."

Gemini Flash finished in 12 seconds and got 28 out of 30 correct. It handled the fuzzy matching well—when the code was off by one character, it still paired the transaction based on amount and time. It missed two orders where the payment came a day late, but that's a data problem, not a model problem.

Claude Sonnet took 19 seconds and got 29 out of 30 correct. It was more cautious—it flagged three transactions as "possible match, verify manually" instead of committing. That's useful if you want to double-check, but it means more work.

For high-volume Jumia reconciliation where speed matters and you're okay with a 93 per cent hit rate, Gemini is faster. For anything involving money I can't afford to get wrong, I use Claude and accept the extra seven seconds.

Duplicate C2B codes: Claude won, no contest

This is where the test got interesting. M-Pesa C2B codes are supposed to be unique, but in practice, if two customers pay at the same agent within a few minutes, you sometimes get codes that differ by one digit. Or a customer sends KSh 1,500 twice because they thought the first payment failed, and you end up with two identical codes in the statement.

I fed both models 15 statements that I knew contained duplicates—22 duplicate pairs total. The prompt was: "Flag any transaction codes that appear more than once. For each duplicate, show both transactions with timestamp, amount, and sender name. If the amounts differ, highlight that."

Claude flagged all 22 pairs. It also caught three cases where the codes weren't identical but were suspiciously similar (e.g., RBK4G7H2QT and RBK4G7H2QY). It formatted the output as a table with a "Risk" column: "Confirmed duplicate" or "Possible typo—verify."

Gemini flagged 18 pairs. It missed four because it treated codes that differed by one character as distinct. When I added "also flag codes that are 90 per cent similar," it caught two more but started flagging random codes that just happened to share a prefix.

If you're dealing with high transaction volumes and you need to catch duplicates before you reconcile, use Claude. Gemini will get you most of the way there, but "most" isn't good enough when you're trying to figure out if a customer paid twice or if Safaricom glitched.

The prompts that worked (and the ones that didn't)

I tried eight different prompt structures. Three worked consistently; five produced nonsense or required so much manual cleanup that I might as well have done it in Excel.

What worked:

  • "Match each M-Pesa transaction to a WhatsApp order. Output a table with Order ID, M-Pesa Code, Amount Sent, Amount Expected, Status. If Status is 'Mismatch,' explain why."
  • "Find all duplicate transaction codes in this statement. For each duplicate, show both rows with timestamp and amount. Highlight any amount discrepancies."
  • "Compare this Jumia invoice list to this M-Pesa statement. Match by amount and timestamp if the code doesn't match exactly. Flag any invoice with no corresponding payment."

What didn't work:

  • Asking the model to "reconcile" without defining what that meant. Claude assumed I wanted a summary; Gemini assumed I wanted totals.
  • Asking for "discrepancies" without specifying which fields to compare. Both models flagged every transaction where the sender name didn't exactly match the customer name, even when it was obviously the same person.
  • Uploading a screenshot of the M-Pesa portal instead of a CSV. Both models tried to OCR it, but the formatting broke and I got garbage output.

The key is to be specific about the output format and the matching logic. If you say "match these two lists," the model will guess. If you say "match by transaction code first, then by amount and timestamp if the code is missing, then flag anything unmatched," you'll get usable results.

When to use which model (my current workflow)

I now use both models in sequence. It takes 15 minutes instead of three hours.

Step one: Claude for the first pass. I upload the day's till statement and the WhatsApp order list. Claude matches transactions, flags mismatches, catches duplicates. I export the table and review anything marked "Mismatch" or "Duplicate."

Step two: Gemini for Jumia bulk matching. I upload the Jumia invoice report and the same till statement. Gemini does the fuzzy matching faster, and I'm okay with a few false positives because I'm checking the output anyway.

Step three: Manual review for anything over KSh 5,000. Both models are good, but I don't trust them with high-value transactions. If a customer paid KSh 12,000 for a laptop, I'm checking the code myself.

I run this workflow on Kryotta because I can switch between Claude and Gemini without changing tabs or re-uploading files. The compare arena feature is also useful—I'll paste the same prompt into both models, run them side by side, and see which output is cleaner. For M-Pesa reconciliation, that side-by-side view has saved me from trusting a result that looked right but wasn't.

The mistakes I made (so you don't have to)

I assumed both models would handle phone numbers correctly. They don't. Kenyan phone numbers start with 07 or 01, and both models sometimes drop the leading zero or add a +254 prefix when it wasn't there in the original data. Now I tell the model: "Treat phone numbers as text. Do not reformat them."

I also assumed I could upload a PDF of the M-Pesa statement. You can't—or rather, you can, but the model will extract the text and the formatting will break. Always export as CSV from the M-Pesa portal, clean up any merged cells in Excel, then upload that.

And I learned not to ask the model to "suggest next steps" or "recommend actions." Both Claude and Gemini will happily tell you to "contact the customer" or "check with Safaricom," which is obvious and not helpful. Stick to concrete tasks: match, flag, compare.

Questions people ask

Can I use the free version of Claude or Gemini for this?
You can, but you'll hit rate limits fast if you're processing 60+ transactions a day. Kryotta gives you access to both models in one workspace with higher limits, and you can upload CSVs directly instead of pasting text.

What if the M-Pesa statement has Swahili column headers?
Both models handle it fine. I've tested statements with "Nambari ya Simu" instead of "Phone Number" and "Kiasi" instead of "Amount." Just make sure the CSV encoding is UTF-8.

Will this work for Paybill statements or just Buy Goods?
Yes, same workflow. Paybill statements have an account number field that Buy Goods doesn't, but the matching logic is identical. You'll just add "Account Number" to your prompt.

How do I handle payments that came from a different phone number than the one on the order?
Tell the model to match by amount and timestamp first, then flag any name or phone mismatch for manual review. Claude is better at this—it'll say "Possible match, different sender" instead of assuming it's wrong.

If you're still reconciling M-Pesa statements by hand, try this workflow once. Upload a day's transactions to Kryotta, paste the prompts above, and see if it saves you an hour. It won't catch everything, but it'll catch enough that you can spend the saved time answering WhatsApp orders instead of hunting for missing transaction codes.

K
Written by
Kryotta Team
Product & research

Kryotta is the multi-model AI workspace — every leading model, one login, one bill. Try it free →

Related reading