subscription.canceled
Fired when a subscription is terminated at the end of the billing period. Revoke access here.
Payload
All webhook payloads follow a consistent top-level structure with event-specific data nested within the data object.
The subscription ID.
The customer ID. Returns your externalId if you provided one when creating the customer, otherwise returns the Commet publicId.
Always "canceled" for this event. Revoke access when you receive this.
ISO 8601 datetime when the customer originally requested cancellation.
The reason for cancellation, if provided.
ISO 8601 datetime when the subscription ended (matches the billing period end).
{
"event": "subscription.canceled",
"timestamp": "2026-04-25T00:00:00.000Z",
"organizationId": "org_abc123",
"mode": "live",
"apiVersion": "2026-05-25",
"data": {
"subscriptionId": "sub_1a2b3c4d",
"customerId": "user_123",
"status": "canceled",
"canceledAt": "2026-04-20T10:15:00.000Z",
"cancelReason": "Too expensive",
"endDate": "2026-04-25T00:00:00.000Z"
}
}Cancellation lifecycle
Commet cancellations are always scheduled for the end of the current billing period. Two events fire at different moments:
| Moment | Event | status | What to do |
|---|---|---|---|
| Customer requests cancellation | subscription.updated | active | Show "ending on {endDate}" in your UI. Do NOT revoke access. |
| Billing period ends | subscription.canceled | canceled | Revoke access. |
POST /subscriptions/{id}/cancel
└→ subscription.updated (status: "active", canceledAt: set, endDate: set)
... time passes until billing period ends ...
└→ subscription.canceled (status: "canceled")How is this guide?