Skip to main content
Two events report whether a fan’s paid fan-experience subscription currently grants access. They are the grant and revoke pair an app uses to open and close whatever the experience gates, a Discord or Telegram group for example. Both require the read:experience scope, not the read:creator scope the rest of the creator.* domain uses. Both are delivered in the Standard-Webhooks envelope; the fields below describe the data object.
A fan-experience subscription is not a profile subscription. They are separate resources and 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. It says nothing about their profile subscription, and revoking profile-gated content on it removes access the fan still pays for. Profile subscriptions ride creator.subscription.* with data.object: "subscription"; these events carry data.object: "experience_subscription". Discriminate on type or on data.object, never on the word “subscription”.

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. creator.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 key it on expires_at alone, 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

These two topics do not use the creator.* delivery model. Other creator.* events fan out to every app holding the required scope for that creator. These reach only:
  • the app that owns the experience, resolved from the subscription’s own app.uuid, unconditionally, and
  • the creator’s connector destinations subscribed to the topic.
An experience subscription belongs to one app, so a creator-wide fan-out would tell app A which fans stopped paying app B. If your app does not own the experience, you do not receive the event, however many scopes you hold for that creator.

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. Compare them to tell the two cases apart: access_ends_at < expires_at means the fan lost time they had paid for.

End reasons

end_reason is a required discriminator on creator.experience_subscription.deactivated. The payload carries no retry state. A payment_failed event tells you the charge that was due has been declined and access is gone as of access_ends_at, nothing more, any retry state would already be stale by the time you process it. Revoke on it and wait for creator.experience_subscription.activated.

Activation reasons

activation_reason is a required discriminator on creator.experience_subscription.activated.
Handling renewal_recovered is required if you revoke on deactivated. A declined renewal revokes access and fires deactivated with end_reason: "payment_failed" before the dunning retries run. A retry that settles pays for the period and restores access. An app that revoked and never re-grants leaves a fan who has paid locked out permanently.

Example: creator.experience_subscription.deactivated

A cancellation reaching the end of its paid period, the one case where access_ends_at and expires_at agree.
A mid-period revocation carries the same shape with access_ends_at before expires_at:

Example: creator.experience_subscription.activated

The recovery case, the reason an app that revokes has to handle this topic.

Revoking access on subscription end

Gate the resource on one pair of handlers: revoke on deactivated, grant on activated. Verify the signature first, return 2xx immediately, and do the revocation out of band, see Delivery, Retries and Idempotency.
Two rules this handler encodes:
  1. Revoke on the event, not on a cancellation. cancel_at_period_end: true on a deactivated event is context, it tells you the fan chose to leave rather than failed to pay. It is never itself the trigger.
  2. Always pair revoke with grant. Revoking on deactivated without handling activated permanently locks out any fan whose renewal recovered after a declined charge.
Access can also lapse silently at expires_at. A subscription grants access only while it is not deleted and expires_at is in the future. The hourly expiry sweep defers a row when a renewal is still settling or an upstream lookup fails, so the fan loses access on the clock and no event is sent until a later sweep resolves the row. Treat expires_at as a deadline in its own right: expire your own cached grant at expires_at and let activated extend it, rather than waiting only for deactivated.

See also