Setup and delivery
App webhooks are configured like every other Fanvue webhook: in the Developer Area Events tab, add an endpoint and select theapp.* events you want, then
enable the required scope. See Webhooks Overview
for the full setup, signing secret, and local testing flow.
- Scope: every
app.*event requires theread:selfscope — the payload only concerns your app’s own sale (the buyer uuid and amounts). Enable it in the Authentication tab. - One endpoint, many events:
app.*events arrive on the same endpoints as the platform events (follow.new,purchase.new, …) and checkout events (checkout_link.*) you have subscribed to. Branch on the eventtype(anddata.object) to route them.
Amounts and currency
Monetary amounts are integers in the currency’s minor units (for USD, cents, so999 means $9.99). Each resource carries its own currency (ISO 4217),
which may be null when not yet known.
Event envelope
Every app webhook is delivered as an HTTPPOST with a
Standard-Webhooks-style envelope:
id: unique event id, stable across delivery retries (use it to dedupe). Onapp.subscription.*the id covers the state transition rather than the occurrence, so pair it withtimestampif the same transition can repeat within a billing period — see Delivery, Retries and Idempotency.type: the event topic (see Available events).timestamp: ISO 8601 time the event was emitted.data: the resource object.data.objectis"payment","subscription","refund", or"dispute".
data are snake_case.
Available events
Allapp.* events require the read:self scope. Each group below links to a
reference page with full field definitions and example payloads.
Payments (reference)
app.payment.pending: a charge is created and awaiting confirmationapp.payment.succeeded: a charge succeedsapp.payment.failed: a charge fails
app.payment.* events cover both one-time purchases and subscription
charges; branch on billing_reason to tell them apart.
Subscriptions (reference)
app.subscription.activated: a subscription becomes activeapp.subscription.cancel_at_period_end_changed: auto-renew is turned off; access continues until period end
Refunds and disputes (reference)
app.refund.created: a one-time purchase is refunded, charged back, or cancelledapp.payment.refunded: deprecated alias ofapp.refund.createdapp.dispute.flagged: an early chargeback warning, before a formal disputeapp.dispute.created: a formal dispute (chargeback) is opened
Money and access are separate events
The money and the access state arrive as different events: a subscription’s initial charge emits bothapp.payment.succeeded (with
billing_reason: subscription_initial) and app.subscription.activated.
Fulfil access off the subscription event and reconcile revenue off the payment
event.
Refund and dispute events (
app.refund.created, app.payment.refunded,
app.dispute.*) cover one-time purchases only, identified by a
purchase_reference with the appotp_ prefix. Subscription reversals and
chargebacks are reconciled through the App
Subscriptions endpoints, not these webhooks.app.subscription.deactivated is reserved for when a subscription’s access
actually ends, but is not emitted yet. Read live subscription state with
the App Subscriptions endpoints in the
meantime.client_reference_id and metadata appear on every app resource, but are
currently always null / empty — Fanvue does not yet capture an app-supplied
external reference or attribution map at purchase time. Do not depend on them
yet.Verifying signatures
App webhooks are signed exactly like the rest of Fanvue’s webhooks, with anX-Fanvue-Signature header (t=<timestamp>,v0=<hmac-sha256-hex>). Verify it
against the raw request body before parsing JSON. The header breakdown, the
verification flow, and complete Node and Python samples live in
Verify Webhook Signatures.
Reconciliation
Webhooks can be missed or delayed, so reconcile against the REST endpoints. The app one-time payments endpoints are read-only, require theread:self scope, and
split into owner-scoped (all buyers of an app you own) and caller-scoped (/me,
the authenticated user’s own payments):
The
invoiceNumber path parameter matches data.id (for a payment) or
data.payment_id (for the original payment behind a refund). For subscription
state, use the App Subscriptions endpoints.
These payment endpoints are not yet part of the generated API
Reference; they are documented here until they
appear in the OpenAPI spec.