curl --request POST \
--url https://api.fanvue.com/v1/webhooks/subscriptions \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--header 'X-Fanvue-API-Version: <x-fanvue-api-version>' \
--data '
{
"url": "<string>",
"events": []
}
'import requests
url = "https://api.fanvue.com/v1/webhooks/subscriptions"
payload = {
"url": "<string>",
"events": []
}
headers = {
"X-Fanvue-API-Version": "<x-fanvue-api-version>",
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {
'X-Fanvue-API-Version': '<x-fanvue-api-version>',
Authorization: 'Bearer <token>',
'Content-Type': 'application/json'
},
body: JSON.stringify({url: '<string>', events: []})
};
fetch('https://api.fanvue.com/v1/webhooks/subscriptions', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));{
"id": "d4e5f6g7-8h9i-0j1k-2l3m-n4o5p6q7r8s9",
"signingSecret": "whsec_3b1f8a0c2d4e6f8091a2b3c4d5e6f70819a2b3c4d5e6f70819a2b3c4d5e6f708"
}{
"error": "<string>",
"message": "<string>"
}{
"error": "<string>"
}{
"error": "<string>"
}{
"error": "<string>",
"message": "<string>",
"nextVersion": "<string>"
}{
"error": "<string>"
}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, 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.
curl --request POST \
--url https://api.fanvue.com/v1/webhooks/subscriptions \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--header 'X-Fanvue-API-Version: <x-fanvue-api-version>' \
--data '
{
"url": "<string>",
"events": []
}
'import requests
url = "https://api.fanvue.com/v1/webhooks/subscriptions"
payload = {
"url": "<string>",
"events": []
}
headers = {
"X-Fanvue-API-Version": "<x-fanvue-api-version>",
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {
'X-Fanvue-API-Version': '<x-fanvue-api-version>',
Authorization: 'Bearer <token>',
'Content-Type': 'application/json'
},
body: JSON.stringify({url: '<string>', events: []})
};
fetch('https://api.fanvue.com/v1/webhooks/subscriptions', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));{
"id": "d4e5f6g7-8h9i-0j1k-2l3m-n4o5p6q7r8s9",
"signingSecret": "whsec_3b1f8a0c2d4e6f8091a2b3c4d5e6f70819a2b3c4d5e6f70819a2b3c4d5e6f708"
}{
"error": "<string>",
"message": "<string>"
}{
"error": "<string>"
}{
"error": "<string>"
}{
"error": "<string>",
"message": "<string>",
"nextVersion": "<string>"
}{
"error": "<string>"
}read:self— Access your own user profile information, including basic account details and settings.
Authorizations
OAuth 2.0 access token, presented as a JWT bearer token in the Authorization header. Obtain a token via the authorization-code flow; the scopes granted to the token determine which operations it may call.
Headers
API version to use for the request
"2025-06-26"
Body
Public HTTPS URL the event payloads are delivered to (no redirects, no localhost)
One or more platform events this subscription delivers
1The platform event the webhook subscription delivers
checkout_link.payment.pending, checkout_link.payment.succeeded, checkout_link.payment.failed, checkout_link.subscription.activated, checkout_link.subscription.deactivated, checkout_link.subscription.cancel_at_period_end_changed, checkout_link.refund.created, checkout_link.dispute.flagged, checkout_link.dispute.created, checkout_link.installment.paid, checkout_link.installment.failed, checkout_link.plan.completed, payout.paid, payout.failed, follow.new, message.read, message.received, purchase.new, subscription.new, subscription.renewed, subscription.cancelled, subscription.expired, tip.new, creator.payment.succeeded, creator.subscription.activated, creator.subscription.renewed, creator.subscription.deactivated, creator.subscription.cancel_at_period_end_changed, creator.experience_subscription.deactivated, creator.experience_subscription.activated, creator.post.liked, creator.post.commented, creator.message.reaction, creator.message.deleted, creator.refund.created, creator.dispute.flagged, creator.dispute.created, creator.reward.created, creator.reward.reversed, creator.fan.status_changed, creator.fan.presence_changed, creator.follow.created, creator.message.received, creator.message.sent, creator.message.mass_sent, creator.message.read, creator.message.read_by_fan Was this page helpful?