Abandoned Cart Recovery Events
The following webhook events track the abandoned cart recovery lifecycle:
Event Description abandoned_checkout.detectedAn abandoned checkout has been detected. Sent when a payment is identified as abandoned (failed or incomplete) and the recovery workflow begins. abandoned_checkout.recoveredThe customer completed payment through the recovery link. The recovered_payment_id field contains the successful payment ID.
Abandoned Checkout Payload Fields
The original payment that was abandoned. Use this to look up product, amount, and currency details.
The customer who abandoned the checkout.
Why the checkout was abandoned. One of:
payment_failed — Customer attempted payment but it failed
checkout_incomplete — Customer visited checkout but never attempted payment
Current lifecycle state of this recovery attempt. One of:
abandoned — Detected, no emails sent yet
recovering — At least one recovery email sent
recovered — Customer completed payment
exhausted — All emails sent or newer checkout found
opted_out — Customer unsubscribed
ISO 8601 timestamp of when the checkout was detected as abandoned.
The payment ID of the successful recovery payment. null until the checkout is recovered.
Example: Handling ACR Webhooks
app . post ( '/webhooks/dodo' , async ( req , res ) => {
const event = req . body ;
switch ( event . type ) {
case 'abandoned_checkout.detected' :
console . log ( `Checkout abandoned: ${ event . data . payment_id } ` );
console . log ( `Reason: ${ event . data . abandonment_reason } ` );
// Track abandonment in your analytics
await trackAbandonment ( event . data );
break ;
case 'abandoned_checkout.recovered' :
console . log ( `Checkout recovered: ${ event . data . payment_id } ` );
console . log ( `Recovery payment: ${ event . data . recovered_payment_id } ` );
// Grant access, update records
await handleRecovery ( event . data );
break ;
}
res . json ({ received: true });
});
Dunning Events
The following webhook events track the subscription dunning lifecycle:
Event Description dunning.startedA dunning attempt has been created for a subscription that entered on_hold or was cancelled by the customer. dunning.recoveredThe customer updated their payment method and the resulting payment succeeded. The payment_id field contains the successful payment ID.
Dunning Attempt Payload Fields
The subscription that triggered the dunning attempt.
The customer who owns the subscription.
The subscription state that triggered dunning. One of:
on_hold — Subscription paused due to payment failure
cancelled — Customer cancelled from the customer portal
Current lifecycle state of this dunning attempt. One of:
recovering — Dunning emails are being sent
recovered — Customer updated payment method and payment succeeded
exhausted — All emails sent or subscription state changed
ISO 8601 timestamp of when the dunning attempt was created.
The payment ID of the successful recovery payment. null while recovering.
Example: Handling Dunning Webhooks
app . post ( '/webhooks/dodo' , async ( req , res ) => {
const event = req . body ;
switch ( event . type ) {
case 'dunning.started' :
console . log ( `Dunning started for subscription: ${ event . data . subscription_id } ` );
console . log ( `Trigger: ${ event . data . trigger_state } ` );
// Track dunning in your system
await trackDunning ( event . data );
break ;
case 'dunning.recovered' :
console . log ( `Subscription recovered: ${ event . data . subscription_id } ` );
console . log ( `Recovery payment: ${ event . data . payment_id } ` );
// Reactivate access, update records
await handleDunningRecovery ( event . data );
break ;
}
res . json ({ received: true });
});
Subscribe to both dunning.started and dunning.recovered to track the full dunning lifecycle. Use dunning.started to pause grace periods or flag at-risk subscriptions in your system.
Abandoned Cart Recovery Configure ACR email sequences and discount incentives.
Subscription Dunning Configure dunning email sequences for lapsed subscriptions.
Subscription Webhooks Related subscription lifecycle events like subscription.on_hold and subscription.cancelled.
Webhook Payload Schema Webhook payload for abandoned_checkout.detected and abandoned_checkout.recovered events
abandoned_at
string<date-time>
required
Available options:
payment_failed,
checkout_incomplete
Available options:
abandoned,
recovering,
recovered,
exhausted,
opted_out