How to Fight a Stripe Chargeback (and Win)
Matt King
November 5, 2025
The average merchant wins about 30% of chargebacks they contest. Most lose because they submit the wrong evidence — or no evidence at all. With the right data attached to each transaction, you can push your win rate above 50%.
This guide covers the Stripe-specific workflow: what happens when a dispute is filed, which reason codes you can realistically win, and exactly what evidence to submit.
How Stripe Chargebacks Work
When a customer disputes a charge with their bank, Stripe:
- Debits the transaction amount plus a $15 dispute fee from your account
- Sends a
charge.dispute.createdwebhook event - Gives you 7-21 days to submit evidence
- Forwards your evidence to the card network for a decision
- Returns the funds if you win (the $15 fee is non-refundable either way)
The entire process takes 60-90 days from dispute filing to resolution.
Which Disputes Can You Win?
Not all chargeback reason codes are equally contestable. Focus your effort where evidence matters most:
| Reason Code | Dispute Type | Win Probability | Key Evidence |
|---|---|---|---|
fraudulent |
Customer claims unauthorized | Medium (40%) | IP match, email validation, usage logs |
product_not_received |
Claims non-delivery | High (60%) | Delivery tracking, access logs |
duplicate |
Claims charged twice | High (70%) | Transaction records showing distinct charges |
subscription_canceled |
Claims they cancelled | Medium (50%) | Cancellation policy, no cancellation record |
unrecognized |
Doesn't recognize charge | High (55%) | Clear billing descriptor, receipt email |
The fraudulent reason code is the most common and also the most important to contest. This is where pre-transaction data makes the biggest difference.
The Evidence That Wins Disputes
For "Fraudulent" Disputes
This is where fraud prevention data becomes your strongest weapon:
- Email validation proof — Show that the email passed validation: not disposable, valid DNS, low risk score. This demonstrates the customer used a real email address.
- IP address and geolocation — Show the purchase IP matches the customer's billing country. Include VPN/proxy detection results.
- Login and usage logs — Timestamps showing the customer logged in and used the product after purchase. This is your strongest evidence for digital products.
- Device consistency — Same device/browser used for signup and purchase.
// Example evidence data from Fidro validation
{
"email": "customer@gmail.com",
"disposable": false,
"dns_valid": true,
"risk_score": 0.12,
"ip": "203.0.113.42",
"ip_country": "US",
"vpn": false,
"proxy": false,
"validated_at": "2025-09-15T14:23:00Z"
}
For "Unrecognized" Disputes
These are often the easiest to win:
- Billing descriptor — Show what appears on their statement. If it's unclear, fix it in Stripe.
- Receipt email — Proof the customer received a receipt at their email address.
- Account activity — Login records showing continued use of the service.
For "Product Not Received" Disputes
- Access logs — For digital products, show the customer accessed the service.
- Delivery tracking — For physical products, provide shipping confirmation and tracking number.
- Download records — If applicable, show file downloads or content access.
Automating Evidence Collection
Set up a Stripe webhook listener that automatically gathers evidence when a dispute is filed:
// Stripe webhook handler
app.post('/webhooks/stripe', async (req, res) => {
const event = req.body;
if (event.type === 'charge.dispute.created') {
const dispute = event.data.object;
const charge = await stripe.charges.retrieve(dispute.charge);
// Retrieve stored Fidro validation data
const fraudData = await getFraudCheckForCustomer(charge.customer);
// Retrieve usage/access logs
const accessLogs = await getAccessLogs(charge.customer);
// Submit evidence automatically
await stripe.disputes.update(dispute.id, {
evidence: {
customer_email_address: charge.receipt_email,
customer_purchase_ip: fraudData?.ip,
access_activity_log: formatAccessLogs(accessLogs),
uncategorized_text: formatFraudEvidence(fraudData),
},
});
}
res.sendStatus(200);
});
The Prevention-First Approach
Fighting chargebacks is expensive even when you win. The $15 fee is non-refundable, and the operational cost of gathering evidence adds up.
The most effective strategy is preventing chargebacks before they happen:
- Validate emails at signup — Block disposable emails and flag high-risk addresses using Fidro's API
- Check IPs at checkout — Catch geographic mismatches and VPN usage
- Use clear billing descriptors — Set this in your Stripe dashboard
- Send receipt emails — Immediate confirmation reduces "unrecognized" disputes
- Offer easy refunds — A self-service refund is cheaper than a chargeback
Next Steps
- Set up the
charge.dispute.createdwebhook in Stripe - Start collecting fraud prevention data at signup with Fidro's free plan
- Attach validation data to every Stripe customer record
- Build your automated evidence submission pipeline