subscription.new, subscription.cancelled, and subscription.expired events.
Requires the
read:creator scope. Delivered in the Standard-Webhooks envelope; the fields below describe the data object.
A typical churn sequence is
cancel_at_period_end_changed (auto-renew off, access continues) followed by deactivated when the paid period runs out. A failed renewal can deactivate a subscription with no prior cancel_at_period_end_changed.activated vs renewed
Both report a subscription that is active and set to renew. They differ in what happened:creator.subscription.renewed, the fan’s access never lapsed and the subscription simply rolled into a new billing period. Readexpires_atandcurrent_period_startoff this event; the money for the same cycle arrives oncreator.payment.succeededwithbilling_reason: "subscription_renewal".creator.subscription.activated, access is being granted where there was none: a new subscriber, a lapsed fan re-subscribing, or a renewal that only succeeded after the subscription had already been deactivated.
renewed if you cache expires_at. Without it a cached period goes stale every cycle, because the payment event carries the money but no new dates.
Subscription resource
status is never "cancelled". A cancelled-but-still-active subscription reports status: "active" with cancel_at_period_end: true, the fan keeps access until expires_at. Only deactivated reports expired. Gate access on expires_at and cancel_at_period_end, not on status alone.price is the signup price, not the amount charged. A discount or free trial makes the charged amount differ, and a creator who changes their subscription price bills the new price on renewal without this value being rewritten. For the amount actually taken, read gross on the correlated creator.payment.succeeded.Use current_period_start, not created_at, for “since when is this fan on their current period”. created_at is the first-ever subscription date and never advances, so it reports a stale period for any returning subscriber. current_period_start falls back to created_at for a fan with no paid charge yet, for example one still inside a free trial.Correlating with the money
Native profile subscriptions have no external uuid; the identity is the(purchaser, creator) pair. id is a correlation token, the subscription’s initial-payment invoice number, carried on activated and renewed so you can join the access event to the money event: subscription.id here equals payment.subscription.id on creator.payment.succeeded. It is null on deactivated and cancel_at_period_end_changed, so key your own records on the (purchaser, creator) pair rather than on id.
Example: creator.subscription.activated
Example: creator.subscription.renewed
The same shape, with the billing period rolled forward. created_at is unchanged, it is the first-ever subscription date.
Example: creator.subscription.deactivated
Access has ended, so renew_date and renew_price are null and id is not carried.
cancel_at_period_end is false on a deactivated subscription that simply ran out, it reports the auto-renew flag at the moment of deactivation, not whether the fan had cancelled earlier. Look for the preceding cancel_at_period_end_changed if you need to tell voluntary churn from a failed renewal, or read deactivation_reason.Example: creator.subscription.cancel_at_period_end_changed
Auto-renew has been turned off. status stays active and the fan keeps access until expires_at; renew_date and renew_price go null because no charge will occur. Turning auto-renew back on emits the same event with cancel_at_period_end: false, auto_renew: true, and the renewal fields repopulated.