Disputes & Chargebacks
Comprehensive guide to understanding, managing, and responding to payment disputes and chargebacks to protect your revenue and maintain compliance.
Overviewโ
A dispute (also called a chargeback) occurs when a customer questions a charge with their card issuer instead of contacting you directly. The card issuer withdraws funds from your account and launches an investigation. Understanding the dispute process and responding effectively is critical to recovering revenue and maintaining a low chargeback ratio.
Key Concepts:
- โ Dispute - Customer questions a charge with their bank
- โ Chargeback - Bank reverses the transaction
- โ Evidence - Documentation proving transaction validity
- โ Representment - Your response to dispute with evidence
- โ Chargeback ratio - Disputes / total transactions (keep < 1%)
- โ Inquiry - Pre-dispute customer question (can prevent dispute)
Dispute Lifecycleโ
Common Dispute Reasonsโ
1. Fraudulent (Fraud)โ
Customer claim: "I didn't make this purchase"
Common causes:
- Card was stolen
- Account compromised
- Family member made unauthorized purchase
- True fraud
Prevention:
- Enable 3D Secure
- Verify shipping address
- Check for suspicious patterns
- Use fraud protection tools
Evidence needed:
- Proof of delivery
- IP address logs
- Customer communication
- Device fingerprints
2. Unrecognized (No Authorization)โ
Customer claim: "I don't recognize this charge"
Common causes:
- Billing descriptor unclear
- Forgot about purchase
- Subscription renewal forgotten
Prevention:
- Use clear billing descriptor
- Send email confirmations
- Reminder emails for subscriptions
- Clear communication
Evidence needed:
- Purchase confirmation emails
- Account activity logs
- Service usage records
- Customer login history
3. Product Not Received (Non-Receipt)โ
Customer claim: "I never received the product"
Common causes:
- Delivery failed
- Wrong address
- Delayed shipping
- Customer moved
Prevention:
- Use tracked shipping
- Confirm delivery address
- Send shipping notifications
- Provide tracking numbers
Evidence needed:
- Tracking information
- Delivery confirmation (signature)
- Shipping labels
- Communication about delivery
4. Product Unacceptable (Not as Described)โ
Customer claim: "Product is defective/not as described"
Common causes:
- Product damaged
- Wrong item sent
- Misleading description
- Quality issues
Prevention:
- Accurate product descriptions
- Clear photos
- Quality control
- Easy return policy
Evidence needed:
- Product descriptions
- Photos/videos
- Return policy
- Customer communication about issue
5. Duplicate Chargeโ
Customer claim: "I was charged twice"
Common causes:
- Technical error
- Customer submitted twice
- Subscription + one-time charge
- Authorization + capture confusion
Prevention:
- Idempotency keys
- Clear subscription terms
- Transaction deduplication
- User-friendly checkout
Evidence needed:
- Transaction logs
- Explanation of charges
- Proof of separate purchases
- Refund of duplicate (if applicable)
6. Credit Not Processedโ
Customer claim: "I returned item but wasn't refunded"
Common causes:
- Refund delayed
- Refund to different card
- Partial refund confusion
- Processing time not communicated
Prevention:
- Process refunds promptly
- Clear refund timeline
- Confirmation emails
- Check refund status
Evidence needed:
- Refund confirmation
- Refund timing explanation
- Return receipt
- Communication about refund
7. Canceled Serviceโ
Customer claim: "I canceled but was still charged"
Common causes:
- Cancellation not processed
- Billing cycle already started
- Prorated charges
- Trial period ended
Prevention:
- Immediate cancellation confirmation
- Clear cancellation policy
- Prorated refunds
- Grace periods
Evidence needed:
- Cancellation date
- Billing cycle explanation
- Terms of service
- Service usage logs
Dispute Statusesโ
| Status | Meaning | Action Required |
|---|---|---|
| open | Dispute filed, awaiting evidence | Submit evidence immediately |
| pending | Evidence submitted, under review | Wait for decision (45-90 days) |
| won | You won the dispute | Funds reinstated to account |
| lost | Customer won the dispute | Funds remain withdrawn |
| charge_refunded | You refunded before ruling | No further action |
| closed | Dispute resolved (various reasons) | Review outcome |
Responding to Disputesโ
Step 1: Review Disputeโ
// Retrieve dispute details via API
const dispute = await omise.disputes.retrieve('dspt_test_...');
console.log('Reason:', dispute.reason_code);
console.log('Amount:', dispute.amount / 100);
console.log('Due date:', dispute.closed_at);
console.log('Transaction:', dispute.charge);
Step 2: Gather Evidenceโ
Universal evidence for all disputes:
- Customer name and email
- Billing and shipping address
- Purchase date and time
- Transaction ID
- Product/service description
- Customer IP address
- Communication history
Specific evidence by type:
For fraud disputes:
- Proof of delivery with signature
- AVS and CVV match results
- IP address geolocation
- Device fingerprints
- Previous purchase history
- Photos of delivered item (if available)
For non-receipt:
- Tracking number
- Delivery confirmation
- Carrier name
- Delivery date and time
- Signed delivery receipt
- Photos of package at address
For not-as-described:
- Product photos and descriptions
- Return policy
- Communications about product
- Quality assurance records
- Proof of resolution attempt
Step 3: Submit Evidenceโ
// Submit evidence via API
const evidence = await omise.disputes.update('dspt_test_...', {
message: 'Customer received product as confirmed by tracking',
metadata: {
tracking_number: '1Z999AA10123456784',
delivery_date: '2025-01-15',
carrier: 'DHL'
}
});
// Upload document
const document = await omise.disputes.upload('dspt_test_...', {
file: fs.readFileSync('/path/to/delivery-proof.pdf'),
description: 'Delivery confirmation with signature'
});
Via Dashboardโ
- Log in to Omise Dashboard
- Navigate to Disputes
- Select the dispute
- Click "Submit Evidence"
- Fill in evidence form:
- Write explanation
- Upload documents (PDFs, images)
- Provide tracking information
- Review and submit
Step 4: Monitor Statusโ
app.post('/webhooks/omise', (req, res) => {
const event = req.body;
switch (event.key) {
case 'dispute.create':
handleNewDispute(event.data);
break;
case 'dispute.update':
handleDisputeUpdate(event.data);
break;
case 'dispute.close':
handleDisputeClosed(event.data);
break;
}
res.sendStatus(200);
});
async function handleDisputeClosed(dispute) {
if (dispute.status === 'won') {
console.log('Won dispute!', dispute.id);
notifyTeam('Dispute won', dispute);
} else if (dispute.status === 'lost') {
console.log('Lost dispute', dispute.id);
analyzeFailureReason(dispute);
}
}
Best Practicesโ
1. Respond Quicklyโ
// Set up alerts
async function handleNewDispute(dispute) {
// Immediately notify team
await sendSlackNotification({
text: `โ ๏ธ New dispute filed! Amount: ${dispute.amount / 100} ${dispute.currency}`,
dispute_id: dispute.id,
reason: dispute.reason_code,
due_date: dispute.closed_at
});
// Create task
await createJiraTicket(dispute);
// Send email to support team
await emailSupportTeam(dispute);
}
Timeline:
- Submit evidence within 7-10 days for best results
- Final deadline: Varies by card network (14-21 days)
- Late submissions: May be rejected automatically
2. Maintain Detailed Recordsโ
// Log everything
async function createCharge(orderData) {
const charge = await omise.charges.create({
amount: orderData.amount,
currency: 'THB',
card: orderData.tokenId,
metadata: {
order_id: orderData.orderId,
customer_email: orderData.email,
customer_phone: orderData.phone,
billing_address: JSON.stringify(orderData.billingAddress),
shipping_address: JSON.stringify(orderData.shippingAddress),
ip_address: orderData.ipAddress,
user_agent: orderData.userAgent,
product_description: orderData.productDescription,
shipping_method: orderData.shippingMethod,
tracking_number: orderData.trackingNumber // Add when available
}
});
// Store in database
await db.transactions.create({
charge_id: charge.id,
customer_id: orderData.customerId,
session_data: orderData.sessionData,
timestamp: new Date()
});
return charge;
}
3. Clear Communicationโ
// Send immediate confirmation
async function sendOrderConfirmation(order) {
await sendEmail({
to: order.customer_email,
subject: `Order Confirmation #${order.id}`,
html: `
<h2>Thank you for your order!</h2>
<p><strong>Order #:</strong> ${order.id}</p>
<p><strong>Total:</strong> $${order.amount / 100}</p>
<p><strong>Billing descriptor:</strong> YourCompany.com</p>
<h3>What's Next?</h3>
<ul>
<li>Processing: 1-2 business days</li>
<li>Shipping: 3-5 business days</li>
<li>Tracking: Will be emailed when shipped</li>
</ul>
<p>Questions? Reply to this email or visit our support page.</p>
<p><strong>Note:</strong> The charge will appear as "YourCompany.com" on your statement.</p>
`
});
}
4. Prevent Disputes Proactivelyโ
// Identify high-risk orders
function calculateDisputeRisk(order) {
let risk = 0;
// High-value order
if (order.amount > 500000) risk += 20;
// First-time customer
if (order.customer.first_order) risk += 15;
// International shipping
if (order.shipping_country !== order.billing_country) risk += 25;
// Different billing/shipping address
if (order.shipping_address !== order.billing_address) risk += 15;
// Express shipping (rush orders often disputed)
if (order.shipping_method === 'express') risk += 10;
return risk;
}
// Take action based on risk
async function processHighRiskOrder(order) {
const risk = calculateDisputeRisk(order);
if (risk > 50) {
// Require additional verification
await requestPhoneVerification(order);
await enable3DSecure(order);
await addManualReview(order);
} else if (risk > 30) {
// Extra tracking
await useSignatureShipping(order);
await sendExtraConfirmations(order);
}
}
5. Accept When Appropriateโ
// Don't fight unwinnable disputes
async function evaluateDispute(dispute) {
const charge = await omise.charges.retrieve(dispute.charge);
// Check if we can win
const canWin = await assessEvidence(dispute, charge);
if (!canWin) {
// Accept the dispute
// Save time and resources for winnable cases
console.log('Insufficient evidence, accepting dispute');
// Analyze to prevent future
await analyzeDisputePattern(dispute);
await updateFraudRules(dispute);
return; // Don't submit evidence
}
// Fight with strong evidence
await submitCompellingEvidence(dispute, charge);
}
6. Monitor Chargeback Ratioโ
// Calculate monthly chargeback ratio
async function calculateChargebackRatio(month) {
const totalTransactions = await db.charges.count({
created: { $gte: month.start, $lt: month.end }
});
const disputes = await db.disputes.count({
created: { $gte: month.start, $lt: month.end }
});
const ratio = (disputes / totalTransactions) * 100;
console.log(`Chargeback ratio: ${ratio.toFixed(2)}%`);
// Alert if exceeding thresholds
if (ratio > 1.0) {
await alertManagement('High chargeback ratio!', ratio);
}
return ratio;
}
Industry thresholds:
- < 0.65%: Healthy
- 0.65% - 1.0%: Monitor closely
- > 1.0%: High risk (card networks may penalize)
- > 1.5%: Excessive (risk of losing processing)
FAQโ
How long do I have to respond to a dispute?
You typically have 7-21 days depending on the card network. However, respond within 7-10 days for best results. Check the dispute's closed_at date in the dashboard or API.
What happens if I don't respond?
If you don't submit evidence by the deadline, you automatically lose the dispute and the funds remain withdrawn. Always respond, even with limited evidence.
Can I refund to avoid a dispute?
Yes! If you receive a dispute and determine the customer has a valid claim, you can issue a refund. This resolves the dispute and may help maintain goodwill.
How often do merchants win disputes?
Win rates vary widely (10-40%) depending on evidence quality and dispute reason. Fraudulent disputes are hardest to win without strong delivery proof.
Does 3D Secure prevent disputes?
3D Secure shifts liability for fraud disputes to the card issuer, meaning you won't lose funds even if a fraud dispute is filed. However, customers can still file non-fraud disputes.
What's a good chargeback ratio?
- Excellent: < 0.5%
- Good: 0.5% - 0.75%
- Acceptable: 0.75% - 1.0%
- High Risk: > 1.0%
Card networks may impose penalties above 1%.
Can customers file disputes after receiving a refund?
Unfortunately, yes. Some customers file disputes without realizing they've been refunded, or file both a dispute and request a refund. Always check for existing disputes before processing refunds.
Related Resourcesโ
- Fraud Protection - Prevent disputes before they happen
- 3D Secure - Shift liability for fraud
- Refunds - Process refunds to avoid disputes
- Webhooks - Receive dispute notifications
- Documents API - Upload evidence programmatically