subscription.cancellation_scheduled
Fired when a cancellation is scheduled for the end of the billing period. Do NOT revoke access yet.
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.
Still "active" — the subscription remains usable until effectiveAt.
ISO 8601 datetime when the cancellation was requested.
The reason for cancellation, if provided.
ISO 8601 datetime when the cancellation will execute (the billing period end). subscription.canceled fires at this moment.
{
"event": "subscription.cancellation_scheduled",
"timestamp": "2026-04-20T10:15:00.000Z",
"organizationId": "org_abc123",
"mode": "live",
"apiVersion": "2026-05-25",
"data": {
"subscriptionId": "sub_1a2b3c4d",
"customerId": "user_123",
"status": "active",
"canceledAt": "2026-04-20T10:15:00.000Z",
"cancelReason": "Too expensive",
"effectiveAt": "2026-04-25T00:00:00.000Z"
}
}Cancellation lifecycle
This event marks the start of the cancellation lifecycle. The subscription stays fully usable until effectiveAt:
| Moment | Event | status | What to do |
|---|---|---|---|
| Customer requests cancellation | subscription.cancellation_scheduled | active | Show "ending on {effectiveAt}" in your UI. Do NOT revoke access. |
| Customer reverts the cancellation | subscription.cancellation_revoked | active | Remove the "ending on" notice. |
| Billing period ends | subscription.canceled | canceled | Revoke access. |
subscription.updated also fires at the scheduling moment for backward compatibility — if you already handle the scheduled-cancel state through subscription.updated, you can keep doing so. This event carries the same intent with an explicit name and the exact effectiveAt.
How is this guide?