Manage Stripe disputes from Dashboard → Payments → Disputes where you can view details, submit evidence, and track outcomes. Enable Smart Disputes for AI-assisted evidence gathering. Each dispute has a deadline (7-21 days), a $15 fee, and requires specific evidence matching the dispute reason code. Organize your evidence around the reason code for the best chance of winning.
Managing Disputes Effectively in Stripe
When a customer files a dispute with their bank, you need a structured process to respond. The Stripe Dashboard provides a dedicated Disputes section showing all open, under review, won, and lost disputes. Each dispute includes the reason code (fraudulent, product_not_received, duplicate, etc.), the evidence deadline, and a form to submit your response. Smart Disputes, a Stripe feature, can automatically submit evidence for clear-cut cases. For everything else, matching your evidence to the specific reason code is the key to winning.
Prerequisites
- A Stripe account with Dashboard access (admin or analyst role)
- Understanding of your order fulfillment and customer service processes
- Node.js 18 or newer (for API evidence submission)
- Your Stripe API keys from Dashboard → Developers → API keys
Step-by-step guide
Access the Disputes Dashboard
Access the Disputes Dashboard
In the Stripe Dashboard, go to Payments → Disputes (or use the top search bar to find a specific dispute). The disputes list shows status, amount, reason, and deadline for each dispute. Filter by status: needs response, under review, won, or lost.
Expected result: You see all disputes organized by status with deadlines clearly visible.
Understand dispute reason codes
Understand dispute reason codes
Each dispute has a reason code that tells you what the customer is claiming. Tailor your evidence to directly address the specific reason.
1// Dispute reason codes and what evidence to provide:23// 'fraudulent' — Customer claims they didn't authorize the charge4// Evidence: AVS/CVC match, IP address, shipping address matching billing56// 'product_not_received' — Customer says item never arrived7// Evidence: Shipping tracking, delivery confirmation, signed receipt89// 'duplicate' — Customer charged twice for same thing10// Evidence: Proof charges were for different products/services1112// 'subscription_canceled' — Customer says they canceled13// Evidence: Cancellation policy, proof subscription was active1415// 'credit_not_processed' — Customer says refund was promised but not given16// Evidence: Refund policy, communication showing no refund was agreed1718// 'product_unacceptable' — Product not as described19// Evidence: Product description, delivery confirmation, customer communicationExpected result: You know which evidence to gather based on the dispute reason.
Submit evidence through the Dashboard
Submit evidence through the Dashboard
Click on a dispute, then click 'Submit evidence'. Fill in the relevant fields based on the reason code. Upload supporting files (PDFs, screenshots). Add a clear summary in the 'Uncategorized text' field explaining why the charge is legitimate. Click 'Submit evidence' — this is final and cannot be edited.
Expected result: Evidence is submitted and the dispute moves to 'under review' status.
Enable Smart Disputes
Enable Smart Disputes
Go to Settings → Disputes in the Dashboard and enable Smart Disputes. When enabled, Stripe automatically submits evidence for disputes where it has strong data (like delivery tracking from Stripe-connected shipping providers). Smart Disputes handles simple cases so you can focus on complex ones.
Expected result: Smart Disputes is enabled. Stripe auto-responds to clear-cut disputes using available data.
Upload evidence files via the API
Upload evidence files via the API
For automated workflows, upload evidence files and submit dispute evidence programmatically.
1const stripe = require('stripe')(process.env.STRIPE_SECRET_KEY);2const fs = require('fs');34// Upload a file as evidence5const file = await stripe.files.create({6 purpose: 'dispute_evidence',7 file: {8 data: fs.readFileSync('/path/to/receipt.pdf'),9 name: 'receipt.pdf',10 type: 'application/pdf',11 },12});1314// Submit evidence with the uploaded file15await stripe.disputes.update('dp_ABC123', {16 evidence: {17 receipt: file.id,18 customer_name: 'Jane Smith',19 customer_email_address: 'jane@example.com',20 product_description: 'Annual SaaS subscription — project management tool',21 service_date: '2025-01-15',22 uncategorized_text: 'Customer purchased on Jan 15, 2025. Access logs show 47 logins through Feb 14. Cancellation policy requires 30-day notice. No cancellation request received.',23 },24 submit: true,25});Expected result: Evidence file is uploaded and the dispute evidence is submitted via the API.
Complete working example
1const express = require('express');2const stripe = require('stripe')(process.env.STRIPE_SECRET_KEY);34const app = express();56// Webhook for dispute events7app.post('/webhook',8 express.raw({ type: 'application/json' }),9 (req, res) => {10 const sig = req.headers['stripe-signature'];11 let event;1213 try {14 event = stripe.webhooks.constructEvent(15 req.body,16 sig,17 process.env.STRIPE_WEBHOOK_SECRET18 );19 } catch (err) {20 return res.status(400).send(`Webhook Error: ${err.message}`);21 }2223 if (event.type === 'charge.dispute.created') {24 const dispute = event.data.object;25 const deadline = new Date(dispute.evidence_details.due_by * 1000);26 console.log(`ALERT: New dispute ${dispute.id}`);27 console.log(`Reason: ${dispute.reason}, Amount: $${dispute.amount / 100}`);28 console.log(`Evidence deadline: ${deadline.toISOString()}`);29 }3031 res.json({ received: true });32 }33);3435app.use(express.json());3637// List disputes with filtering38app.get('/api/disputes', async (req, res) => {39 try {40 const { status, limit = 20 } = req.query;41 const params = { limit: parseInt(limit, 10) };4243 const disputes = await stripe.disputes.list(params);4445 const filtered = status46 ? disputes.data.filter((d) => d.status === status)47 : disputes.data;4849 res.json(filtered.map((d) => ({50 id: d.id,51 amount: d.amount / 100,52 currency: d.currency,53 reason: d.reason,54 status: d.status,55 deadline: d.evidence_details.due_by56 ? new Date(d.evidence_details.due_by * 1000).toISOString()57 : null,58 })));59 } catch (err) {60 res.status(500).json({ error: err.message });61 }62});6364// Get dispute detail65app.get('/api/disputes/:id', async (req, res) => {66 try {67 const dispute = await stripe.disputes.retrieve(req.params.id);68 res.json(dispute);69 } catch (err) {70 res.status(500).json({ error: err.message });71 }72});7374const PORT = process.env.PORT || 3000;75app.listen(PORT, () => console.log(`Server on port ${PORT}`));Common mistakes when managing disputes in Stripe
Why it's a problem: Submitting evidence that does not address the specific reason code
How to avoid: Read the reason code carefully. 'product_not_received' needs delivery proof, not product descriptions. 'fraudulent' needs authorization proof, not shipping receipts.
Why it's a problem: Submitting evidence too late
How to avoid: Evidence deadlines are strict (7-21 days). Set up webhooks for charge.dispute.created and create an internal SLA of 48 hours to respond.
Why it's a problem: Editing evidence after clicking Submit
How to avoid: Evidence submission is final — you cannot edit or add more after submitting. Use submit: false to save drafts, then submit: true only when complete.
Why it's a problem: Not monitoring overall dispute rate
How to avoid: Track your dispute rate (disputes / total charges). Visa and Mastercard flag merchants at 0.75%. Monitor in Dashboard → Analytics.
Best practices
- Respond to every dispute, even if you think you will lose — it demonstrates good business practices to card networks
- Match evidence specifically to the dispute reason code for the highest win rate
- Enable Smart Disputes to auto-handle straightforward cases
- Set up charge.dispute.created webhooks for immediate team notification
- Use the uncategorized_text field to tell a clear, factual story with dates and specifics
- Upload evidence as PDFs rather than images for clarity and professionalism
- Save evidence drafts (submit: false) before final submission to allow team review
- Track dispute patterns to identify and fix root causes
Still stuck?
Copy one of these prompts to get a personalized, step-by-step explanation.
Write a Node.js Express API for Stripe dispute management. Include endpoints to list disputes with status filtering, retrieve dispute details, and submit evidence for a dispute via stripe.disputes.update. Add a webhook handler for charge.dispute.created events using stripe.webhooks.constructEvent with raw body.
Build a dispute management dashboard backend for my app. List all disputes with their reason codes and deadlines, allow evidence submission through the API, and set up webhooks to alert the team when new disputes arrive. Track dispute rates.
Frequently asked questions
What is Smart Disputes?
Smart Disputes is a Stripe feature that automatically submits evidence for disputes where Stripe has strong supporting data. Enable it in Dashboard → Settings → Disputes. It handles clear-cut cases so you can focus on complex disputes.
How long do I have to respond to a dispute?
Deadlines vary by card network: Visa gives 20 days, Mastercard gives 45 days, and Amex gives 20 days from the dispute creation date. Always check the evidence_details.due_by field.
Can I submit evidence more than once?
No. Once you click Submit (or set submit: true via API), the evidence is final. You cannot add or modify it. Use draft mode (submit: false) to prepare your evidence before final submission.
What is an inquiry vs a dispute?
An inquiry (also called a retrieval request) is a pre-dispute information request from the bank. Responding to inquiries promptly can prevent them from escalating to full disputes.
How do I test disputes in test mode?
Use the test payment method pm_card_createDispute to create a charge that automatically generates a dispute. You can then practice submitting evidence.
What if I need a comprehensive dispute management solution?
For businesses processing high volumes that need automated evidence gathering, team workflows, and analytics to reduce dispute rates, the RapidDev team can build a tailored dispute management system.
Talk to an Expert
Our team has built 600+ apps. Get personalized help with your project.
Book a free consultation