---
title: "Update one of your experiences for this creator"
method: PATCH
path: "/experiences/{experienceUuid}"
---

# Update one of your experiences for this creator

`PATCH /experiences/{experienceUuid}`

## Request

- Base URL: `https://api.fanvue.com`
- URL: `https://api.fanvue.com/experiences/{experienceUuid}`
- Auth: OAuth 2
  - Authorization code: `https://auth.fanvue.com/oauth2/auth`
  - Token URL: `https://auth.fanvue.com/oauth2/token` scopes: `write:experience`

Updates an experience your app published for the creator whose token is calling. Only the fields sent change. Re-pricing mints a new price; fans who already paid keep what they bought. `actions` re-prices the actions listed and withdraws every other active one — declaring a new action is a publish, not an update.

    Hiding a published experience that fans have paid for answers 409 with the impact, exactly as a publish does. An experience owned by another app answers 404.

## Path parameters

- `experienceUuid` string, uuid, required

## Headers

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

## Request body

- object
  - `appUuid` string, uuid, required: Your app's UUID.
  - `title` string
  - `description` string
  - `imageUrl` string, uri, nullable: Replaces the cover. `null` clears it; omit to leave it alone. One that cannot be fetched leaves the current cover in place.
  - `accessMode` 'FREE' | 'SUBSCRIPTION' | 'PAID' | 'HIDDEN': Moving an experience that is not PAID to `PAID` requires `priceCents`; an experience that is PAID already keeps its price unless re-priced.
  - `deliveryMode` 'EMBEDDED' | 'EXTERNAL'
  - `externalUrl` string, uri, nullable: Where an `EXTERNAL` experience opens. Must be https (checked here). The platform additionally refuses Fanvue, localhost, IP and dev-tunnel hosts; such a URL answers 400 with a `message` naming the field.
  - `hidden` boolean: Keep the experience off the creator's profile. Ignored when accessMode is HIDDEN, which always hides.
  - `priceCents` integer: Re-prices a PAID experience (send `accessMode: "PAID"` alongside). Fans who already paid keep what they bought.
  - `priceRecurring` boolean: With `priceCents`: bill monthly as an app subscription instead of a one-off unlock. Omitted, the experience keeps the cadence of its current price.
  - `experienceType` 'LIVE_STREAM' | 'LIVE_AUDIO' | 'VIDEO' | 'AUDIO' | 'GAME' | 'CHALLENGE' | 'QUIZ' | 'EVENT' | 'OTHER': What kind of experience this is. Decides how it presents itself where it is embedded (for example the category tag on a chat card). Omit for the generic `OTHER`.
  - `actions` object[]: Re-prices the actions listed and withdraws every other active one. Only actions that already exist on the experience may appear; declaring a new one is a publish.
    - `externalActionId` string, required
    - `priceCents` integer, required: Price in USD cents, between 300 and 50000.
  - `acknowledgePaidImpact` boolean: Set to `true` on a retry to accept the paid impact a previous attempt answered 409 with. Send the 409's `impact` alongside as `acknowledgedImpact`.
  - `acknowledgedImpact` object: The `impact` the previous 409 reported, echoed back verbatim.
    - `affectedFanCount` integer, required: Distinct fans holding paid access right now, across subscriptions and purchases.
    - `activeSubscriptionCount` integer, required: Subscriptions that still grant access. Any at all blocks the change outright.
    - `pendingSubscriptionInvoiceCount` integer, required: In-flight initial subscription charges. Block, like a settled subscription.
    - `oneTimePurchaseCount` integer, required: Distinct fans holding a settled one-off purchase. Needs acknowledging.
    - `pendingPurchaseCount` integer, required: In-flight one-off purchase attempts. Need acknowledging, like a settled purchase.

## Response `200`

The experience as it now stands

- object
  - `experience` AppExperience, required
    - `uuid` string, uuid, required
    - `appUuid` string, uuid, required
    - `creatorUuid` string, uuid, required
    - `externalExperienceId` string, required: Your own stable id for the experience, as you published it.
    - `title` string, required
    - `description` string, required
    - `imageUrl` string, nullable, required: Public URL of the cover Fanvue stored, or `null` when none was kept (none sent, or the one sent could not be fetched).
    - `accessMode` 'FREE' | 'SUBSCRIPTION' | 'PAID' | 'HIDDEN', required
    - `experienceType` 'LIVE_STREAM' | 'LIVE_AUDIO' | 'VIDEO' | 'AUDIO' | 'GAME' | 'CHALLENGE' | 'QUIZ' | 'EVENT' | 'OTHER', required: What kind of experience this is; `OTHER` when nothing declared one.
    - `deliveryMode` 'EMBEDDED' | 'EXTERNAL', required
    - `externalUrl` string, nullable, required: Where an `EXTERNAL` experience opens; `null` for `EMBEDDED`.
    - `hidden` boolean, required: Share-link only, never listed on the creator's profile. Always `true` for `HIDDEN`.
    - `priceCents` integer, nullable, required: Price in USD cents behind a `PAID` experience; `null` for every other mode.
    - `priceRecurring` boolean, required: Whether that price bills monthly as an app subscription rather than once.
    - `publishedAt` string, nullable, required: When it was published (ISO 8601); `null` while unpublished.
    - `suspendedAt` string, date-time, nullable, required: When Fanvue removed it for a policy reason (ISO 8601); `null` for a live or merely unpublished experience. A suspended experience is not listed, cannot be launched and refuses a publish or update with `experience_suspended` until Fanvue reinstates it; keep your record of it rather than deleting it.
    - `reviewStatus` 'pending_review' | 'approved' | 'rejected', required: Where the experience stands in Fanvue's review. Publishing submits it for review (`pending_review`); fans see it once `approved`, while it is also published and not suspended. Editing the title, description, cover, delivery mode or external link of an approved experience keeps the approved version live for fans and submits the edit for review, shown by `pendingReviewSubmittedAt`; price, access and visibility changes are not reviewed. A `rejected` experience is offline and goes back into review when you publish it again. Its creator, and Fanvue staff testing it, can open it in every state.
    - `reviewRejection` ExperienceReviewRejection, nullable, required: Why Fanvue rejected the experience; `null` unless `reviewStatus` is `rejected`.
      - `reasonCodes` string[], required: The listing requirement sections Fanvue cited, such as `7.3`; see the App Store listing requirements.
      - `message` string, required: Fanvue's explanation, written for the creator.
    - `pendingReviewSubmittedAt` string, date-time, nullable, required: When an edit to an approved experience was submitted for review (ISO 8601); `null` when no edit is waiting. Fans keep seeing the approved version until Fanvue decides; the fields returned here are the edited ones.
    - `isNsfw` boolean, required: Whether the experience is NSFW, because its creator's profile is not marked safe for work or the app is rated NSFW. Fans must pass age verification to open an NSFW experience, and a fan in safe mode is warned first.
    - `url` string, required: The share link fans land on: `/{handle}/experiences/{slug}` for a listed experience, keyed by the uuid instead when `hidden` so the link stays unguessable. Chat cards and link previews recognise it.

## Other responses

- `400`: Bad Request - API version not supported OR validation failed OR invalid UUID OR a field was refused by the platform (its message names the field)
- `401`: Unauthorized Response
- `403`: Three refusals, told apart by their shape. A named refusal the app can act on carries `error` and `message`: the creator is outside the fan-experiences rollout, has not installed the app, the app cannot carry experiences, or Fanvue has removed this experience (`experience_suspended`, lifted on reinstatement). The token lacking `write:experience` carries `error` alone (`Insufficient scopes`). The app named in `appUuid` not being the calling app carries `message` alone (`Forbidden`).
- `404`: Experience not found, or not your app's
- `409`: Fans have paid for access this change takes away. `paid_impact_acknowledgement_required` is retried with the acknowledgement fields; `blocked_active_subscriptions` cannot proceed from the API
- `410`: API version no longer supported (sunset)
- `429`: Too many requests - rate limit exceeded
- `502`: The write could not be completed against the upstream
- `503`: Developer API upstream is not configured

## Changes

- **2026-10-21** `966260af2770`: 1 info
  - endpoint added

[Operation history](https://skmtc.dev/fanvue/apis/fanvue-api/changes/experiences/:experienceUuid/patch.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/966260af2770?raw)
