If you sell anything online, you’ve gotten this message: “I paid but I didn’t get anything.” Usually there’s a blurry receipt screenshot attached.
Someone has to open the dashboard, find the transaction, work out whether it went through, and write back. It’s slow, and it’s the same lookup every time.
The easy fix is to paste the message into an LLM and let it reply. That’s where it goes wrong.
a guess that sounds sure
Whether a payment went through isn’t a matter of opinion. Paystack knows. The model reading the customer’s message doesn’t, so it guesses, and it guesses in a confident tone. “Your payment was successful” when it failed is bad. Refunding something that’s already been refunded is worse.
So Resolve has one rule. The model doesn’t get to decide what happened.
how it works
A ticket comes in as text, a pasted receipt, or both. A vision model reads it and pulls out the payment details. If that fails, a regex fallback catches the obvious cases.
Then the real work happens, and no model does it. Resolve checks the transaction against Paystack’s verify API, against the business’s own orders ledger, and against the list of refunds already issued. The refund check is what stops a double refund.
Only after that does a model write anything. It gets the verdict and nothing else. It never sees the customer’s message or the receipt image, so it can’t repeat a claim as if it were true. The model is good at wording a reply. It just doesn’t get to choose the facts.
the security bits
Each business connects its own Paystack key on a setup page. The key goes in an httpOnly cookie, not local storage. Every lookup lands on an audit page, so you can see what was checked and why a reply says what it says.
what was still open
When I last worked on it I hadn’t got to page-level auth redirects, row-level security policies, or tighter tracking of where each draft’s facts come from. I wouldn’t have put it in front of a real business before those.
where it’s going
Resolve was a project, not a company, and I’m not pitching it as one. What I’m keeping is the rule behind it. If the answer lives in a system somewhere, go ask the system. Don’t ask the model to remember it.



