WebhooksEvents
subscription.updated
Fires whenever any field on a subscription changes
Fires whenever any field on a subscription changes — plan swap, quantity bump, metadata edit, status transition. The envelope's data.previous_attributes tells you what changed.
This event fires often. Subscribe to it only if your consumer needs to react to every state delta. For lifecycle-only consumers, subscribe to the narrower events: subscription.created, subscription.canceled, subscription.renewed, subscription.paused, subscription.resumed.
Payload
{
"id": "evt_1a2b3c4d5e6f",
"type": "subscription.updated",
"created": 1705689600,
"livemode": true,
"data": {
"object": {
"id": "sub_01HK4X7Z2M5N8P0Q3R6S9T2V5",
"object": "subscription",
"status": "active",
"customer_id": "cus_01HK4X7Z2M5N8P0Q3R6S9T2V5",
"price_id": "price_01HK4X7Z2M5N8P0Q3R6S9T2V5",
"quantity": 5,
"current_period_start": "2026-01-01T00:00:00Z",
"current_period_end": "2026-02-01T00:00:00Z",
"cancel_at_period_end": false,
"trial_end": null,
"metadata": {}
},
"previous_attributes": {
"quantity": 3
}
}
}Common triggers
| Change | What changed in previous_attributes |
|---|---|
| Plan swap | price_id, quantity |
| Seat change | quantity |
| Pause | status: active → status: paused |
| Resume | status: paused → status: active |
| Schedule cancellation | cancel_at_period_end: false |
| Renewal | current_period_start, current_period_end |
| Trial → active | status: trialing or trial_end |
Handler contract
- Verify the signature.
- Deduplicate by
event.id. - Read
data.objectfor the current state — do not reconstruct state fromprevious_attributes. - If
status: canceledand your entitlement model cuts off immediately → revoke access. - If
cancel_at_period_end: true→ mark the account to revoke atcurrent_period_end(via scheduled job or cron). - Return
2xx.
Narrower alternatives
If you only care about:
- Cancellation → subscribe to
subscription.canceled, notsubscription.updated - Renewals → subscribe to
subscription.renewed(fires after the payment succeeds for the new period) - Trial ending → subscribe to
subscription.trial_will_end(fires 3 days before the end)
Narrower subscriptions = fewer handler invocations + less dedup work.
Related events
subscription.created— new subscriptionsubscription.canceled— fully cancelledsubscription.renewed— renewal succeededsubscription.trial_will_end— 3-day warninginvoice.paid— matching invoice-level event on renewals