curl --request PATCH \
--url https://api.fanvue.com/v1/experiences/{experienceUuid} \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--header 'X-Fanvue-API-Version: <x-fanvue-api-version>' \
--data '
{
"appUuid": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"priceCents": 1500
}
'import requests
url = "https://api.fanvue.com/v1/experiences/{experienceUuid}"
payload = {
"appUuid": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"priceCents": 1500
}
headers = {
"X-Fanvue-API-Version": "<x-fanvue-api-version>",
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.patch(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'PATCH',
headers: {
'X-Fanvue-API-Version': '<x-fanvue-api-version>',
Authorization: 'Bearer <token>',
'Content-Type': 'application/json'
},
body: JSON.stringify({appUuid: '3c90c3cc-0d44-4b50-8888-8dd25736052a', priceCents: 1500})
};
fetch('https://api.fanvue.com/v1/experiences/{experienceUuid}', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));{
"experience": {
"uuid": "00000000-0000-4000-8000-000000000010",
"appUuid": "00000000-0000-4000-8000-000000000001",
"creatorUuid": "00000000-0000-4000-8000-000000000002",
"externalExperienceId": "course-photography-101",
"title": "Photography 101",
"description": "Six lessons, shot on film.",
"imageUrl": "https://cdn.fanvue.com/app-experiences/00000000-0000-4000-8000-000000000002/3f2a9c1d8e7b6a50.webp",
"accessMode": "PAID",
"experienceType": "VIDEO",
"deliveryMode": "EMBEDDED",
"externalUrl": null,
"hidden": false,
"priceCents": 1500,
"priceRecurring": false,
"publishedAt": "2026-10-07T10:00:00.000Z",
"suspendedAt": null,
"reviewStatus": "approved",
"reviewRejection": null,
"pendingReviewSubmittedAt": null,
"isNsfw": false,
"url": "https://www.fanvue.com/ava/experiences/photography-101"
}
}{
"error": "<string>",
"message": "<string>"
}{
"error": "<string>"
}{
"error": "fan_experiences_not_enabled",
"message": "<string>"
}{
"message": "<string>"
}{
"error": "paid_impact_acknowledgement_required",
"message": "Fans have paid for access this would take away; acknowledge the paid impact to proceed.",
"impact": {
"affectedFanCount": 3,
"activeSubscriptionCount": 0,
"pendingSubscriptionInvoiceCount": 0,
"oneTimePurchaseCount": 3,
"pendingPurchaseCount": 0
}
}{
"error": "<string>",
"message": "<string>",
"nextVersion": "<string>"
}{
"error": "<string>"
}{
"message": "<string>"
}{
"message": "<string>"
}Update one of your experiences for this creator
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.
curl --request PATCH \
--url https://api.fanvue.com/v1/experiences/{experienceUuid} \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--header 'X-Fanvue-API-Version: <x-fanvue-api-version>' \
--data '
{
"appUuid": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"priceCents": 1500
}
'import requests
url = "https://api.fanvue.com/v1/experiences/{experienceUuid}"
payload = {
"appUuid": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"priceCents": 1500
}
headers = {
"X-Fanvue-API-Version": "<x-fanvue-api-version>",
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.patch(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'PATCH',
headers: {
'X-Fanvue-API-Version': '<x-fanvue-api-version>',
Authorization: 'Bearer <token>',
'Content-Type': 'application/json'
},
body: JSON.stringify({appUuid: '3c90c3cc-0d44-4b50-8888-8dd25736052a', priceCents: 1500})
};
fetch('https://api.fanvue.com/v1/experiences/{experienceUuid}', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));{
"experience": {
"uuid": "00000000-0000-4000-8000-000000000010",
"appUuid": "00000000-0000-4000-8000-000000000001",
"creatorUuid": "00000000-0000-4000-8000-000000000002",
"externalExperienceId": "course-photography-101",
"title": "Photography 101",
"description": "Six lessons, shot on film.",
"imageUrl": "https://cdn.fanvue.com/app-experiences/00000000-0000-4000-8000-000000000002/3f2a9c1d8e7b6a50.webp",
"accessMode": "PAID",
"experienceType": "VIDEO",
"deliveryMode": "EMBEDDED",
"externalUrl": null,
"hidden": false,
"priceCents": 1500,
"priceRecurring": false,
"publishedAt": "2026-10-07T10:00:00.000Z",
"suspendedAt": null,
"reviewStatus": "approved",
"reviewRejection": null,
"pendingReviewSubmittedAt": null,
"isNsfw": false,
"url": "https://www.fanvue.com/ava/experiences/photography-101"
}
}{
"error": "<string>",
"message": "<string>"
}{
"error": "<string>"
}{
"error": "fan_experiences_not_enabled",
"message": "<string>"
}{
"message": "<string>"
}{
"error": "paid_impact_acknowledgement_required",
"message": "Fans have paid for access this would take away; acknowledge the paid impact to proceed.",
"impact": {
"affectedFanCount": 3,
"activeSubscriptionCount": 0,
"pendingSubscriptionInvoiceCount": 0,
"oneTimePurchaseCount": 3,
"pendingPurchaseCount": 0
}
}{
"error": "<string>",
"message": "<string>",
"nextVersion": "<string>"
}{
"error": "<string>"
}{
"message": "<string>"
}{
"message": "<string>"
}write:experience— Request that the creator publish or unpublish a fan-facing experience. The app mints a request token; the creator confirms and Fanvue performs the change.
Authorizations
OAuth 2.0 access token, presented as a JWT bearer token in the Authorization header. Obtain a token via the authorization-code flow; the scopes granted to the token determine which operations it may call.
Headers
API version to use for the request
"2025-06-26"
Path Parameters
"00000000-0000-4000-8000-000000000010"
Body
Your app's UUID.
1 - 100500Replaces the cover. null clears it; omit to leave it alone. One that cannot be fetched leaves the current cover in place.
2048"https://example.com/covers/photography-101.jpg"
Moving an experience that is not PAID to PAID requires priceCents; an experience that is PAID already keeps its price unless re-priced.
FREE, SUBSCRIPTION, PAID, HIDDEN EMBEDDED, EXTERNAL 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.
2048"https://example.com/experiences/photography-101"
Keep the experience off the creator's profile. Ignored when accessMode is HIDDEN, which always hides.
Re-prices a PAID experience (send accessMode: "PAID" alongside). Fans who already paid keep what they bought.
300 <= x <= 500001500
With priceCents: bill monthly as an app subscription instead of a one-off unlock. Omitted, the experience keeps the cadence of its current price.
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.
LIVE_STREAM, LIVE_AUDIO, VIDEO, AUDIO, GAME, CHALLENGE, QUIZ, EVENT, OTHER "GAME"
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.
10Show child attributes
Show child attributes
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.
true
The impact the previous 409 reported, echoed back verbatim.
Show child attributes
Show child attributes
Response
The experience as it now stands
Show child attributes
Show child attributes
Was this page helpful?