All dunning retries were exhausted; the subscription was canceled.
All webhook payloads follow a consistent top-level structure with event-specific data nested within the data object.
The invoice whose retries were exhausted.
The human-readable invoice number.
The customer ID. Returns your externalId if you provided one when creating the customer, otherwise returns the Commet publicId.
The subscription ID.
The payment provider the charge was routed to: stripe, commet, or dlocal.
Terminal dunning reason, usually the last processor decline code or "dunning_exhausted".
{
"event": "payment.retry_failed",
"timestamp": "2026-06-23T14:30:00.000Z",
"organizationId": "8f14e45f-ceea-4e7a-9c3d-1c2b3a4d5e6f",
"mode": "live",
"apiVersion": "2026-08-27",
"data": {
"invoiceId": "inv_n4o5p6",
"invoiceNumber": "INV-0043",
"customerId": "user_123",
"subscriptionId": "sub_1a2b3c4d",
"provider": "stripe",
"reason": "card_declined"
}
}After a payment failure puts a subscription in past_due, Commet retries the outstanding invoice on the dunning schedule. When the final retry fails, the invoice is marked uncollectible and the subscription is canceled — this event marks that terminal outcome.
It is the end of the dunning flow: payment.recovered will not follow, and subscription.canceled fires alongside it. Revoke access when you receive this event.
How is this guide?