Both require the
read:experience scope, not read:creator, and reach only the app that owns the experience (see Delivery). Each event arrives in the envelope, and the tables below describe data.
A fan-experience subscription is not a profile subscription. A fan can hold both against the same creator at the same time, plus one per experience. creator.experience_subscription.deactivated says a fan lost access to one experience and nothing about their profile subscription, so revoking profile-gated content on it removes access the fan still pays for. Profile subscriptions ride creator.subscription.* with data.object: "subscription", while these events carry data.object: "experience_subscription". Discriminate on type or data.object.
Access ended, not billing changed
A cancellation is not an access-ended signal. A fan turning auto-renew off keeps access until the period they paid for runs out, andcreator.experience_subscription.deactivated fires at that point, not at the moment they cancel.
Key every revocation on access_ends_at and on the event arriving. Never key it on cancel_at_period_end being true, and never on expires_at alone, because a refund, chargeback, ban or unpublish ends access mid-period and leaves expires_at in the future.
Fan experiences have no intent-to-cancel event. creator.subscription.cancel_at_period_end_changed covers auto-renew changes for profile subscriptions only and has no fan-experience equivalent.
Delivery
Othercreator.* events fan out to every app holding the required scope for that creator. Experience subscription events reach only two kinds of recipient:
- the app that owns the experience, resolved from the subscription’s own
app.uuid, and - the creator’s connector destinations subscribed to the topic.
Experience subscription resource
access_ends_at and expires_at agree only on a period-end cancellation. Every other end_reason revokes mid-period, leaving expires_at the later of the two. access_ends_at < expires_at means the fan lost time they had paid for.
These events carry no charge amounts. price is frozen at subscribe time, so it is not the amount of any particular renewal. For what was charged, read GET /insights/earnings and match rows on experienceUuid, which is this payload’s experience.uuid. See Attributing fan-experience revenue.
End reasons
end_reason is always present on creator.experience_subscription.deactivated.
A subscription keeps renewing while auto-renew is on and the experience is still sold as a recurring paid experience by an app the creator still has installed. Renewal stops when the experience is unpublished, leaves the paid access mode, is re-priced to a one-off price or its app is uninstalled, and the subscription ends with
end_reason: "experience_unavailable".
The payload carries no retry state. A payment_failed event means the due charge was declined and access is gone as of access_ends_at, so revoke on it and wait for creator.experience_subscription.activated.
Activation reasons
activation_reason is always present on creator.experience_subscription.activated.
Examples
creator.experience_subscription.deactivated
A cancellation reaching the end of its paid period, so access_ends_at and expires_at agree.
access_ends_at before expires_at:
creator.experience_subscription.activated
The recovery case, after a payment_failed revocation.
Revoking access on subscription end
Gate the resource on one pair of handlers that revokes ondeactivated and grants on activated. Verify the signature first, return 2xx immediately, and do the revocation out of band.
Access can also lapse silently at
expires_at. A subscription grants access only while expires_at is in the future. The expiry sweep defers a row when a renewal is still settling, the owning app is suspended or an upstream lookup fails. The fan then loses access on the clock, with no event until a later sweep resolves the row. Expire your own cached grant at expires_at and let activated extend it.Attributing revenue to an experience
Experience subscription events are access signals, not money events. They don’t fire per charge, so a renewal that keeps a fan’s access produces no event on this topic. Use them to grant and revoke, and read revenue frompurchase.new or GET /insights/earnings.
Per settled charge. purchase.new carries experienceUuid and experienceAppUuid on purchaseType: "fan_experience" purchases. It covers one-off access purchases only. Recurring subscription charges have no real-time event.
Per experience, for reconciliation. GET /insights/earnings reports experienceUuid and experienceAppUuid on every fan-experience charge, and accepts experienceUuid as a filter:
read:insights scope, not read:experience.
Don’t detect experience revenue with source. A renewal reports source: "renewal", so source=fanExperience returns only first payments and one-off purchases and under-reports recurring experience revenue from the second charge onwards. Filter on experienceUuid, or key on the field being present.