Resolve Duplicate-Charge Complaints Automatically (Without Refunding the Wrong Thing)
"I was charged twice!" is one of the highest-emotion tickets a support team ever receives. The customer is looking at their bank app, they can see two line items, and they want their money back now. It's also one of the most automatable tickets you have — the answer lives in your payment processor, the resolution is a single refund, and the customer wants speed above all else.
But it's a trap if you automate it naively. The uncomfortable truth, well documented by card networks and merchants alike, is that most reported "double charges" are not duplicates at all. They're an authorization hold sitting next to the real captured charge — two line items, one actual payment. Build an agent that refunds on sight and you'll cheerfully hand money back for charges the customer was never actually billed for. So this use case is really two jobs: resolve the genuine duplicates fast, and correctly talk down the false alarms without a refund.
This post walks through how a Macha agent does both. Macha is an AI agent layer that sits on top of the helpdesk you already run — Zendesk, Freshdesk, Gorgias, or Front — and connects to Stripe so the agent can read the actual payment record and take a real action on it, instead of guessing from the ticket text.
What the customer sees vs. what actually happened
Before any automation, get the distinction straight, because it's the entire ballgame.
| What the customer reports | What's usually true | Correct resolution |
|---|---|---|
| "Two charges for $65 yesterday" | An authorization hold + the settled capture | No refund. The hold drops off in 2–7 days |
| "Two identical $65 charges, both posted" | A genuine duplicate (retry, double-submit) | Refund the extra charge |
| "Charged $65 but I cancelled" | One real charge, refund owed | Refund — but that's a cancellation, not a duplicate |
That first row is the landmine. When you pay by card, the merchant first authorizes the card to confirm funds exist, then later captures the money when the order ships. Your bank may show the authorization hold and the capture as two separate lines, and to a customer that looks identical to being billed twice (Authorization hold, Wikipedia). Major retailers publish entire help-center articles explaining this exact confusion (Levi's, ExpertVoice). A true duplicate is different and rarer: the same amount posted (not pending) twice against the same order, usually from a payment retry or a double-clicked checkout.
An agent that can't tell these apart shouldn't be issuing refunds. An agent that reads Stripe directly can.
The flow, end to end
Here's the use case as Macha ships it. The trigger comes from your helpdesk; every action that touches money happens in Stripe; the reply and ticket update happen back in the helpdesk.
- Trigger — Ticket Created in Zendesk, where the agent's classifier recognizes a duplicate-charge complaint.
- Stripe → Get Customer — match the requester's email to the Stripe customer record.
- Stripe → List Payments — pull recent payments and inspect them: are there two posted charges of the same amount, or one charge plus a pending authorization?
- Decision — genuine duplicate, or auth hold the agent should explain rather than refund.
- Stripe → Create Refund — only for a confirmed duplicate, refunding the extra charge to the original payment method.
- Zendesk → Add Comment — reply to the customer with the specifics and a realistic timeline.
- Zendesk → Update Ticket — set status to Solved and tag it (
duplicate-charge-refunded) so it's auditable later.
The order matters: the agent reads before it writes. Get Customer and List Payments are read-only lookups; Create Refund is the only action that moves money, and it's gated behind the agent actually confirming a duplicate in the payment data.
Connecting the pieces
Two connections do the work. You connect Stripe with an API key, and you connect your helpdesk — for most teams that's Zendesk.
The Stripe connector exposes a focused set of actions: Get Customer, Search Customers, List Payments, Get Payment, Create Refund, and Create Charge. For this use case you only need the first three plus Create Refund — and a good practice is to give the agent exactly those tools and nothing more, so it physically cannot create a charge or touch a customer it has no business touching.
Note that Stripe is an action connector, not a trigger source — Macha doesn't watch Stripe for events here. The event that starts everything is the ticket landing in your helpdesk, which is exactly where you want the human-facing record of the whole interaction to live.
Writing the agent so it doesn't over-refund
The agent's instructions are where you encode the judgment. A reasonable shape:
- Verify identity first. Match the ticket email to a Stripe customer with Get Customer. If there's no match, don't guess — hand off to a human.
- Inspect, don't assume. Use List Payments and compare amounts, timestamps, and status. Two charges of the same amount, both succeeded/posted, against the same order is a duplicate. One posted charge plus a pending/uncaptured authorization is not — explain the auth hold and its 2–7 day drop-off instead.
- Refund the extra one only. Never refund the original. On a confirmed duplicate, issue a refund for the surplus charge to the original payment method.
- Set expectations honestly. Tell the customer the refund typically lands in 5–7 business days, because that's how card settlement actually works — don't promise "instant."
- Escalate the gray zones. Partial captures, multi-item orders, disputes already filed, currency mismatches, anything over a threshold amount — route to a human.
For higher-risk refunds you can keep a human in the loop with a confirmation step, so the agent does all the diagnostic work and drafts the action, but a person clicks approve before money moves. That hybrid is often the right starting posture — let the agent prove its judgment on the read-only diagnosis before you let it refund unattended.
What a clean resolution reads like
For a real duplicate, the customer experience is fast and specific — the agent quotes the actual amounts and dates it found in Stripe, not a canned apology:
You're right — I can see two charges of $65.00 from yesterday (March 4) on your account, and the second one is a duplicate. I've refunded the extra $65.00 to your original card. It should appear on your statement within 5–7 business days. Apologies for the scare, and thanks for flagging it.
And for the far more common false alarm, the agent resolves the worry without spending your money:
Good news — you weren't actually charged twice. What you're seeing is a temporary authorization hold that your bank places to confirm the funds, sitting next to the real charge for your order. The hold isn't a second payment and it'll drop off on its own within a few days. Your order total was $65.00, charged once.
That second reply is the one that separates an agent reading live payment data from a chatbot pattern-matching on the word "twice." One of them protects your margin.
Watch-outs — when not to let this run unattended
This use case is genuinely high-value, but it has sharp edges. Be honest about them:
- The auth-hold trap is the whole risk. If your agent can't reliably read payment status from Stripe and distinguish pending from posted, do not let it auto-refund. An over-eager agent refunding auth holds is worse than no automation.
- Subscriptions look like duplicates but aren't. Two charges a month apart on a recurring plan are two billing cycles, not a duplicate. Scope the agent to recent same-day, same-amount charges.
- Don't double-refund into a dispute. If the customer has already filed a chargeback with their bank, refunding in Stripe on top of it can pay them twice and cost you a dispute fee. When a dispute exists, escalate — let a human reconcile it.
- Partial captures and split shipments create legitimate multiple charges for one order. These are not duplicates; flag for review.
- High-value or fraud-adjacent cases belong with a person. Set an amount ceiling above which the agent diagnoses and drafts but does not act.
Every refund the agent issues is logged on the ticket with a tag, so finance and support both have an audit trail — which is exactly what you want the first time someone asks "wait, why did we refund this?"
What it costs to run
Macha bills in credits, charged per AI action — not per ticket and not per refund. The default model (GPT-5.4 Mini) is 1 credit per action, and models range from 0.5 to 9 credits depending on which you pick. A duplicate-charge resolution is a handful of actions — a couple of Stripe lookups, a refund, a reply, a ticket update — so the cost per resolved ticket is small and predictable, and you only pay when the agent actually does the work. There are no hard-coded prices to memorize here; see the pricing page for current plans, or start a 7-day free trial, no credit card required and watch what your real tickets consume.
FAQ
Can Macha tell a real duplicate charge from an authorization hold? That's the point of reading Stripe directly. The agent inspects payment status and amounts via List Payments — two posted charges of the same amount for one order is a duplicate; one posted charge plus a pending authorization is a hold it should explain, not refund.
Does the agent refund automatically, or does a human approve? Your choice. You can let it refund confirmed duplicates unattended, or gate the Create Refund action behind a human confirmation step for anything over a threshold you set.
Which helpdesks does this work with? Macha runs on top of Zendesk, Freshdesk, Gorgias, and Front. The trigger and the customer-facing reply live in your helpdesk; the payment actions happen in Stripe.
Will it issue partial refunds? Stripe's Create Refund supports full or partial amounts. For the duplicate-charge case the agent refunds the surplus charge; partial-capture situations are better escalated to a human.
How long until the customer sees the money? Refunds typically post to the customer's statement in 5–7 business days — the agent says so explicitly rather than promising "instant," because that's how card settlement works.
Is Stripe the only payment connector? Stripe and Razorpay are supported today. The same pattern — read the payment, confirm, refund, reply — applies to either.
Get started
Duplicate-charge complaints are the rare ticket where automation is genuinely safer and faster than a rushed human — provided the agent reads the payment record before it refunds. Connect Stripe and your helpdesk, give the agent exactly the tools it needs, and start it in confirm-first mode. Browse more billing and payments use cases, read the docs, or spin up a 7-day free trial, no credit card required and point it at your real queue.
Written by Abbas (Customer Support & AI, Macha) · Reviewed by Ankeet Guha (Co-founder & CTO) · Published 2026-06-24 · Last updated 2026-06-24.
Automate your support workflows
Macha's AI agents run entire workflows end to end across your stack.
Shopify
Stripe
Slack
Notion
Google Workspace
Confluence

