Skip to main content
RapidDev - Software Development Agency
stripe-guide

How to manage disputes in Stripe

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.

What you'll learn

  • How to navigate and use the Stripe Disputes Dashboard
  • How to organize evidence based on dispute reason codes
  • How Smart Disputes automates evidence submission
  • How to build a dispute management workflow for your team
Book a free consultation
4.9Clutch rating
600+Happy partners
17+Countries served
190+Team members
Intermediate6 min read20 minutesStripe API v2024-12+, Node.js 18+, Stripe DashboardMarch 2026RapidDev Engineering Team
TL;DR

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

1

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.

2

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.

typescript
1// Dispute reason codes and what evidence to provide:
2
3// 'fraudulent' — Customer claims they didn't authorize the charge
4// Evidence: AVS/CVC match, IP address, shipping address matching billing
5
6// 'product_not_received' — Customer says item never arrived
7// Evidence: Shipping tracking, delivery confirmation, signed receipt
8
9// 'duplicate' — Customer charged twice for same thing
10// Evidence: Proof charges were for different products/services
11
12// 'subscription_canceled' — Customer says they canceled
13// Evidence: Cancellation policy, proof subscription was active
14
15// 'credit_not_processed' — Customer says refund was promised but not given
16// Evidence: Refund policy, communication showing no refund was agreed
17
18// 'product_unacceptable' — Product not as described
19// Evidence: Product description, delivery confirmation, customer communication

Expected result: You know which evidence to gather based on the dispute reason.

3

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.

4

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.

5

Upload evidence files via the API

For automated workflows, upload evidence files and submit dispute evidence programmatically.

typescript
1const stripe = require('stripe')(process.env.STRIPE_SECRET_KEY);
2const fs = require('fs');
3
4// Upload a file as evidence
5const 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});
13
14// Submit evidence with the uploaded file
15await 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

manage-disputes.js
1const express = require('express');
2const stripe = require('stripe')(process.env.STRIPE_SECRET_KEY);
3
4const app = express();
5
6// Webhook for dispute events
7app.post('/webhook',
8 express.raw({ type: 'application/json' }),
9 (req, res) => {
10 const sig = req.headers['stripe-signature'];
11 let event;
12
13 try {
14 event = stripe.webhooks.constructEvent(
15 req.body,
16 sig,
17 process.env.STRIPE_WEBHOOK_SECRET
18 );
19 } catch (err) {
20 return res.status(400).send(`Webhook Error: ${err.message}`);
21 }
22
23 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 }
30
31 res.json({ received: true });
32 }
33);
34
35app.use(express.json());
36
37// List disputes with filtering
38app.get('/api/disputes', async (req, res) => {
39 try {
40 const { status, limit = 20 } = req.query;
41 const params = { limit: parseInt(limit, 10) };
42
43 const disputes = await stripe.disputes.list(params);
44
45 const filtered = status
46 ? disputes.data.filter((d) => d.status === status)
47 : disputes.data;
48
49 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_by
56 ? 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});
63
64// Get dispute detail
65app.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});
73
74const 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.

ChatGPT Prompt

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.

Stripe Prompt

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.

RapidDev

Talk to an Expert

Our team has built 600+ apps. Get personalized help with your project.

Book a free consultation

Need help with your project?

Our experts have built 600+ apps and can accelerate your development. Book a free consultation — no strings attached.

Book a free consultation

We put the rapid in RapidDev

Need a dedicated strategic tech and growth partner? Discover what RapidDev can do for your business! Book a call with our team to schedule a free, no-obligation consultation. We'll discuss your project and provide a custom quote at no cost.