Who gets paid
The creator is the seller on every experience invoice, at the standard Fanvue fee. Your app isn’t a party to the charge and receives no share. Every price is in USD cents, from 300 to 50000. What each access mode charges, and when it renews:Paid access
Fans buyPAID access in Fanvue’s native checkout from the detail page, a chat card or the experience dialog. The purchase.new webhook carries experienceUuid and experienceAppUuid, and so does every row of GET /insights/earnings for the experience.
Recurring access mints a monthly price, and subscriptions renew automatically at the original price. Renewal pauses while the app is suspended, and stops when:
- the experience is unpublished
- the experience is no longer
PAID - the experience is no longer recurring
- the app is uninstalled
creator.experience_subscription.activated and creator.experience_subscription.deactivated webhooks report the lifecycle; see Creator events: experience subscriptions.
SUBSCRIPTION access produces no charge and no webhook of its own.
Priced actions
A priced action is something a fan buys inside your experience, such as a spin or a reveal. Each experience carries a catalogue of up to 10. The creator prices them, in the confirmation dialog or through aprice-request from your creator surface, unless your app prices them in a direct publish.
GET /experiences/{experienceUuid}/actions (read:experience) returns the live catalogue, re-priced on every read.
title is the creator-facing label shown in the payment dialog. status is always active, because a withdrawn action is omitted rather than returned as disabled.
GET /apps/{appUuid}/experience-action-definitions (read:experience) returns the actions your app has declared, without any amount. It answers 404 when the creator hasn’t installed your app.
Charge path 1: the purchase bridge
Your fan surface posts a purchase request and Fanvue opens its native payment dialog. The request never carries an amount, because the price comes from the catalogue.fanvue:experience:topup-requestwith{ amountMinorUnits, clientReferenceId? }opens the top-up dialog and answerstopup-resultwith{ status, clientReferenceId?, invoiceNumber? }.fanvue:experience:consent-requestwith{ clientReferenceId? }asks for spend consent and answersconsent-resultwith{ status: "granted" | "declined" | "failed" }. A fan who has already consented getsgrantedwith no dialog.
Charge path 2: wallet charge from your server
POST /experiences/{experienceUuid}/action-purchases (write:experience) charges one action to the fan’s wallet with no dialog. The Idempotency-Key header is required.
walletBalance, the fan’s remaining balance in USD cents. Purchase references are prefixed expact_.
Idempotency keys are scoped to your app, the fan and the experience, and remembered for 24 hours. Reusing a key replays the first charge once it has settled.
The charge needs a live spend consent for this app and experience. The fan grants it by topping up inside the experience or by answering consent-request, and can revoke it.
Fulfil on the webhook
Fulfil only onapp.experience.action.payment.succeeded, keyed on purchase_reference, so a redelivery grants nothing twice. The bridge result is never proof of payment. For what to do on each status, including when to revoke a grant, see the fulfilment rule.
Six events cover the lifecycle, under the read:self scope: app.experience.action.payment.pending, app.experience.action.payment.succeeded, app.experience.action.payment.failed, app.experience.action.refund.created, app.experience.action.dispute.flagged and app.experience.action.dispute.created. App events: experience actions has the payloads.
Reconcile
GET /experiences/{experienceUuid}/action-purchases lists every attempt, newest first, with keyset paging through nextCursor (limit default 50, max 100). GET /experiences/{experienceUuid}/action-purchases/{purchaseReference} reads one.
Refunds
Refunds have no API. Fanvue re-derives access from the payment ledger on every launch, so a refunded unlock loses access on the fan’s next launch. A refunded action reportsrefunded on the webhook and on the purchase reads.