Skip to main content
Six events tell your app what happened to a priced-action charge inside one of its experiences. Fulfil only on payment.succeeded, and key everything on purchase_reference. Payments inside experiences covers how priced actions are declared and charged. The events are emitted for creators who have priced actions enabled. Every event requires read:self and reaches your app’s destinations only, so register the topics in the Events tab or in webhooks.destinations of your App Manifest. Each arrives in the envelope, and the tables below describe data. The fan is the buyer, the creator is the seller, and your app fulfils the action. These resources are distinct from app.payment.*, which describes your app selling its own plans to a creator, so a handler reconciling your own sales never has to filter them out.

Fulfilment rule

Grant the action once per purchase_reference, and only after app.experience.action.payment.succeeded for that reference or a succeeded status on GET /experiences/{uuid}/action-purchases. pending describes a charge that may never land and failed one that did not. The bridge message your experience receives is interface state, not proof of payment. Granting on anything else gives the action away. Only payment.succeeded has durable retry behind it, because a settled charge whose event could not be handed over is replayed from the ledger. The other five are best effort, and the purchases read is their backstop. The read endpoint’s status set differs from the webhook status. The webhook payment resource carries only pending, succeeded and failed, and reversals arrive as their own events. An open dispute that has not been lost still reads succeeded, so watch app.experience.action.dispute.* for that, not the read. Amounts are integers in USD cents. metadata is the client_metadata object captured with the purchase, with string keys and values, and {} when none was set.

Payment resource

data.object is "experience_action_payment". pending and failed carry the same body as succeeded.

Example: app.experience.action.payment.succeeded

pending and failed deliveries differ in status, in paid_at being null and in the event id.

Refund resource

data.object is "experience_action_refund". The resource carries the same purchase_reference as the succeeded event it reverses, so you revoke exactly the grant you made against that key. It carries amount rather than gross, because a reversal reports what went back, not what the sale was worth. A refund and a later chargeback on one purchase are two events with two reversal invoice numbers and two event ids.

Example: app.experience.action.refund.created

Dispute resource

data.object is "experience_action_dispute". flagged is an early-warning alert and created a formal chargeback. Both are advisory. The money is still the creator’s at flagged, and the reversal, when one follows, arrives as app.experience.action.refund.created with reason: "chargeback".

Example: app.experience.action.dispute.created

app.experience.action.dispute.flagged uses the identical shape with "status": "warning".

Deduplicating

The event id hashes your app, the event’s own identifier and the topic. The identifier is the purchase_reference for a payment status, the reversal invoice number for a refund and the processor’s dispute id for a dispute. A re-emit of one topic for the same purchase reuses the id, and the same purchase reaching two topics gets two ids. The id alone is a valid idempotency key on all six topics. See Delivery, retries and idempotency.