---
title: "List action purchases for one of your experiences"
method: GET
path: "/experiences/{experienceUuid}/action-purchases"
---

# List action purchases for one of your experiences

`GET /experiences/{experienceUuid}/action-purchases`

Returns the action purchases fans have made in one of your experiences, newest first, so you can reconcile against the webhooks you received.

    **Fulfil on the webhook, never on the bridge result.** Grant the action when you receive `app.experience.action.payment.succeeded`, keyed on `purchase_reference` so a redelivery grants nothing twice. The `purchaseResult` message your iframe receives from Fanvue is UX only — it tells your surface to stop showing a spinner, and it is never proof that money moved. This read is the reconciliation path: poll it when you think you missed a webhook, or to confirm one you are unsure about.

    Owner app only: the experience must belong to the app whose credentials make the call, otherwise 403. Purchases belonging to another app are never returned, and a foreign experience uuid is refused before anything about it is read — this is not a way to enumerate experiences, creators or fans.

    Every attempt is listed, not only the settled ones, so a `pending` that never landed and a `refunded` purchase are both visible. `amount` is in minor units (cents), frozen at the purchase attempt. Paging is keyset: pass the `nextCursor` from a prior response, and a purchase created while you page never shifts a row onto or off a later page.

## Path parameters

- `experienceUuid` string, uuid, required

## Query parameters

- `limit` integer — Number of results to return (default 50, max 100).
- `cursor` string — Opaque cursor for the next page, from a prior response.

## Headers

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

## Response `200`

A page of the experience's action purchases

- object
  - `data` object[], required
    - `purchaseReference` string, required — The `expact_…` reference minted with the purchase attempt. THE fulfilment idempotency key: grant the action at most once per reference, and only for a purchase whose status is `succeeded`.
    - `experienceUuid` string, uuid, required — The experience the action belongs to.
    - `externalActionId` string, required — The app's own stable key for the action that was bought.
    - `clientReferenceId` string, nullable, required — The app-supplied reference carried through the purchase, or null when the app supplied none.
    - `buyerUuid` string, uuid, required — UUID of the fan who bought the action. The only identifier of the buyer this surface carries — no handle, no display name, no email.
    - `amount` integer, required — Price in minor currency units (cents), frozen at the purchase attempt. A later re-pricing of the action does not move it.
    - `currency` string, required — ISO 4217 code of the amount. USD only today.
    - `status` 'pending' | 'succeeded' | 'failed' | 'refunded' | 'disputed' | 'cancelled', required — Where the money for this purchase attempt ended up. Fulfil only on `succeeded`. `refunded`, `disputed` and `cancelled` all mean the money is not the creator's, so revoke on any of them — the difference between them only records how the reversal was written, not whether to act. `refunded` is a reversal carrying a refund reference (a settled payment paid back, or an authorisation voided before capture); `disputed` is a chargeback that was lost and reversed; `cancelled` is a reversal carrying neither reference (a delayed capture that failed, or the uncaptured-invoice sweeper). An open dispute that has not been lost is still `succeeded` here — the money has not moved — so watch `app.experience.action.dispute.*` for that, not this field. A refund the processor accepted and then rejected also reports `succeeded` again: this field is where the money ended up, not what was attempted.
    - `invoiceNumber` string, required — Fanvue invoice number for the charge. For support and accounting, not fulfilment.
    - `createdAt` string, date-time, required — When the purchase attempt was opened.
    - `paidAt` string, date-time, nullable, required — When the charge settled, or null while it has not.
  - `nextCursor` string, nullable, required — Cursor for the next page, or null if none.

## Other responses

- `400` — Bad Request - API version not supported OR validation failed OR the cursor could not be decoded
- `401` — Unauthorized Response
- `403` — Unauthorized Response
- `404` — Experience not found, or not owned by the calling app
- `410` — API version no longer supported (sunset)
- `429` — Too many requests - rate limit exceeded
- `502` — Failed to read the purchases from the upstream
- `503` — Developer API upstream is not configured

## Changes

- **2026-09-10** `4d08f36ad6c8` — 1 info
  - endpoint added

[Change history](https://skmtc.dev/fanvue/apis/fanvue-api/changes/experiences/:experienceUuid/action-purchases/get.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.dev/fanvue/apis/fanvue-api/revisions/431868e8a264?raw)
