---
title: "Create a webhook subscription"
method: POST
path: "/webhooks/subscriptions"
---

# Create a webhook subscription

`POST /webhooks/subscriptions`

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`, and `creator.message.deleted`; `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.

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. Splitting them lets a subscriber take 1:1 messages without a broadcast fan-out that can reach tens of thousands of events for one send. A mass message is one message delivered to many conversations, so every recipient's event carries the same message `uuid` with a different `fan`: key it on the pair. `text` arrives already personalised for that recipient.

## Headers

- `X-Fanvue-API-Version` string, required

## Request body

- object
  - `url` string, uri, required — Public HTTPS URL the event payloads are delivered to (no redirects, no localhost)
  - `events` string[], required — One or more platform events this subscription delivers

## Response `201`

Webhook subscription created successfully

- object
  - `id` string, uuid, required — ID of the created webhook subscription
  - `signingSecret` string, required — HMAC signing secret for verifying delivery signatures. Returned only on creation — store it securely now.

## Other responses

- `400` — Bad Request - API version not supported OR validation failed
- `401` — Unauthorized Response
- `403` — Unauthorized Response
- `410` — API version no longer supported (sunset)
- `429` — Too many requests - rate limit exceeded

## Changes

- **2026-08-30** `dce5621fe589` — 6 info
  - added the new `creator.experience_subscription.activated` enum value to the request property `events/items/`
  - added the new `creator.experience_subscription.deactivated` enum value to the request property `events/items/`
  - added the new `creator.fan.presence_changed` enum value to the request property `events/items/`
  - added the new `creator.message.mass_sent` enum value to the request property `events/items/`
  - …2 more

[Change history](https://skmtc.dev/fanvue/apis/fanvue-api/changes/webhooks/subscriptions/post.md)

---

[API](https://skmtc.dev/fanvue/apis/fanvue-api.md) · [All operations](https://skmtc.dev/fanvue/apis/fanvue-api/llms.txt) · [OpenAPI document](https://skmtc-service-production.skmtc.workers.dev/v1/apis/fanvue/fanvue-api/revisions/dce5621fe589/schema)
