Create a webhook subscription
Subscribe a public HTTPS URL to one or more platform events. Every requested event is delivered to the same URL and signed with the single signingSecret returned in the response — store it, as it is only returned at creation time. The token must hold the OAuth scope each requested event needs: read:creator for subscription.new, subscription.renewed, subscription.cancelled, subscription.expired, follow.new, purchase.new, tip.new, the checkout_link.* and payout.paid events, and the creator.payment.succeeded, creator.subscription.*, creator.refund.created, and creator.dispute.* events; read:post for creator.post.liked and creator.post.commented; read:chat for message.received, message.read, creator.message.received, creator.message.sent, creator.message.mass_sent, creator.message.read, creator.message.read_by_fan, creator.message.reaction, creator.message.deleted, and creator.chat.marked_unread; read:experience for the creator.experience_subscription.* events.
creator.experience_subscription.deactivated fires whenever a fan's paid fan-experience subscription stops granting access — they cancelled and the period ran out, a renewal failed, the charge was refunded or charged back, or we or the creator ended it. Act on access_ends_at, the moment access was revoked, which is not always expires_at (a refund, chargeback, ban or unpublish ends access mid-period). A cancellation on its own does not fire it, because access continues to period end. Treat expires_at as a deadline in its own right rather than waiting only for this event: access also lapses on the clock when a renewal is still settling or an upstream lookup fails, and nothing is sent until a later hourly sweep resolves the subscription.
Pair it with creator.experience_subscription.activated, which fires when access starts: activation_reason is subscribed on the fan's initial purchase and renewal_recovered when a renewal charge that had already failed is recovered by a later retry. Handling the recovery case is required if you act on the deactivated event, because a failed renewal revokes access before the retries that may still pay for the period are exhausted.
The two read receipts are separate directions and neither replaces the other: creator.message.read fires when the creator reads the fan's messages, creator.message.read_by_fan when the fan reads the creator's. Their topic names the actor while the object in the payload (fan_message_read / creator_message_read) names whose messages were read, so the two names run on different axes.
creator.chat.marked_unread is the other half of the inbox badge: the creator deliberately marked a conversation unread, where creator.message.read is the event that clears it. It is conversation state, not message state — no message's read status changes, so do not revert the read ticks you took from creator.message.read_by_fan. unread_messages_count is the conversation's real unread count and is unchanged by the mark, so 0 is normal: render a chat as unread when the marker arrives OR that count is above zero. The two halves are delivered independently and are not ordered against each other, so compare marked_at with the read_at on creator.message.read and apply whichever is later rather than whichever arrives last. It reports the transition into unread, so re-marking a conversation that is already unread emits nothing.
Mass messages are delivered on creator.message.mass_sent, never on creator.message.sent, so subscribe to both to see every creator-to-fan send. The event describes the send, not each copy of it: one mass_message per broadcast, carrying the broadcast's uuid, its message_type and recipient_count. There is no fan — a broadcast has no single recipient — and text is the authored body with its personalisation tokens ({{handle}}) left intact, because there is no one recipient to render it for. Substitute per fan if you need the rendered text. Which fans received a send is not carried on the event; that list is not yet exposed on the API.
Headers
API version to use for the request
Request body
Response
Webhook subscription created successfully