Skip to main content
As your Merchant of Record, Dodo Payments manages the dispute and chargeback process with the card networks on your behalf. These webhooks keep your systems in sync as a dispute moves through its lifecycle so you can revoke access, gather evidence, and reconcile your records.

Dispute Webhook Events

A dispute emits an event at each stage of its lifecycle:
EventFires whenWhat it usually means
dispute.openedA cardholder opens a dispute on a paymentFunds are held; prepare to respond
dispute.challengedEvidence has been submitted to contest the disputeThe dispute is being reviewed by the network
dispute.acceptedThe dispute was accepted (not contested)The funds are returned to the cardholder
dispute.cancelledThe dispute was withdrawn or cancelledNo further action needed
dispute.expiredThe response window passed without resolutionTypically resolves against you
dispute.wonThe dispute was resolved in your favorFunds are retained
dispute.lostThe dispute was resolved in the cardholder’s favorFunds are returned to the cardholder
Disputes auto-resolved through Visa Rapid Dispute Resolution (RDR) appear as dispute.lost with is_resolved_by_rdr: true. This is expected — the refund was issued automatically to prevent a formal chargeback.

Handling Dispute Events

When dispute.opened fires, the disputed amount is held immediately. Use the event to update your records and, if you intend to contest it, gather evidence in the dashboard.
Handling dispute events
app.post('/webhooks/dodo', async (req, res) => {
  const event = req.body;

  switch (event.type) {
    case 'dispute.opened': {
      const dispute = event.data;
      // Record the dispute and consider revoking access while it is open
      await recordDispute(dispute.dispute_id, dispute.payment_id, dispute.amount);
      // Gather and submit evidence from the Dodo Payments dashboard (within 4 days)
      break;
    }
    case 'dispute.won': {
      // Funds retained — restore normal state in your records
      await markDisputeResolved(event.data.dispute_id, 'won');
      break;
    }
    case 'dispute.lost': {
      // Funds returned to the cardholder — reconcile and keep access revoked
      await markDisputeResolved(event.data.dispute_id, 'lost');
      break;
    }
  }

  res.json({ received: true });
});
Always verify the webhook signature before processing — see the Webhooks guide for setup. The handler above omits verification for brevity.
You have 4 days to respond to a dispute after it is created. See Dispute Response Best Practices for the evidence to gather and how to format it.

Dispute Status and Stage

The dispute object reports its progress through two fields:
FieldValues
dispute_statusdispute_opened, dispute_expired, dispute_accepted, dispute_cancelled, dispute_challenged, dispute_won, dispute_lost
dispute_stagepre_dispute, dispute, pre_arbitration

Managing Disputes

How to respond to disputes, submit evidence, and how RDR protects your dispute rate.

Handle Payment Failures

Detect and recover failed payments before they become disputes.

Webhook Payload Schema

amount
string
required

The amount involved in the dispute, represented as a string to accommodate precision.

business_id
string
required

The unique identifier of the business involved in the dispute.

created_at
string<date-time>
required

The timestamp of when the dispute was created, in UTC.

currency
string
required

The currency of the disputed amount, represented as an ISO 4217 currency code.

dispute_id
string
required

The unique identifier of the dispute.

dispute_stage
enum<string>
required

The current stage of the dispute process.

Available options:
pre_dispute,
dispute,
pre_arbitration
dispute_status
enum<string>
required

The current status of the dispute.

Available options:
dispute_opened,
dispute_expired,
dispute_accepted,
dispute_cancelled,
dispute_challenged,
dispute_won,
dispute_lost
payment_id
string
required

The unique identifier of the payment associated with the dispute.

is_resolved_by_rdr
boolean | null

Whether the dispute was resolved by Rapid Dispute Resolution

remarks
string | null

Remarks

Last modified on June 17, 2026