> ## Documentation Index
> Fetch the complete documentation index at: https://api.fanvue.com/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Pricing plans

> Set up to five monthly pricing plans for your Fanvue app, share their checkout URLs, and handle activation, plan changes and the events each charge emits.

Pricing plans are the monthly subscriptions creators buy to access your app. By the end of this page you'll have a plan configured, know how creators reach its checkout, and know which events tell you they've paid. You need an app you'll list on the App Store, since plans stay in **Pending setup** until the app is approved.

Fanvue runs checkout and renewals, emits [`app.*` events](/docs/webhooks/app/overview) for every charge, and [pays you 80% of each charge](/docs/payments/app-billing/overview). Prices are integers in USD minor units (cents).

## Create a plan

In the Developer Area, open your app, go to **Store listing**, then **Pricing**, and click **Add plan**.

| Field | Constraints |
| - | - |
| Plan name | Up to 20 characters, for example "Pro Monthly" |
| Tagline | Up to 40 characters, shown on the plan's card |
| Highlights | Up to 5 feature bullets, each up to 40 characters, shown on the plan's card |
| Access | **Free** or **Paid** |
| Price | \$3.99 to \$500.00 for paid plans |
| Billing period | **Monthly**. The API returns `interval` as `monthly` or `yearly` |

An app holds at most 5 plans that are not withdrawn. Once a plan is active its price, currency, interval and plan type are locked, while the name and description stay editable.

<Warning>
  Highlights appear on your public listing, so saving a change to a plan's highlights starts or updates a listing submission, and the change goes live only after review. Saving the name, tagline or price doesn't touch the submission. Batch highlight edits with your other listing edits to avoid extra review rounds; see [Submit your app for review](/docs/app-store/publishing-your-app).
</Warning>

## Plan lifecycle

| Status | Meaning |
| - | - |
| **Pending setup** | Configured and waiting; activates when your app is approved |
| **Active** | Live on your listing and purchasable. Only active plans can be [deeplinked](/docs/payments/app-billing/deeplinks) |
| **Withdrawn** | Taken down; not purchasable |

`GET /apps/{appUuid}/subscription-status` returns the same lifecycle as each plan's `status` (`pending_setup`, `active`, `withdrawn`), plus an app-level `overallStatus`. [Read a creator's app subscription](/docs/payments/app-billing/subscription-status) has the response.

## Plan IDs

Every plan has a UUID, shown in the **Plan ID** column of the pricing table. Click it to copy the value. You'll use the UUID in three places:

* **Deeplinks.** `?plan=<planUuid>` preselects the plan on your listing, and `&action=checkout` skips the picker. See [App Store deeplinks](/docs/payments/app-billing/deeplinks).
* **Webhooks.** The plan arrives as `item.uuid` on `app.payment.*` and as `plan.uuid` on `app.subscription.*` events.
* **Entitlement.** `GET /apps/{appUuid}/subscription/me` returns the buyer's `planUuid`, which you compare against your feature tiers.

## Checkout URL

Every active paid plan has a Fanvue-hosted checkout URL of the form `https://www.fanvue.com/checkout/app_<id>`, where `<id>` is derived from the plan UUID. Read it as `checkoutUrl` on each plan in `GET /apps/{appUuid}/subscription-status` rather than copying it from the Developer Area. `checkoutUrl` is `null` for free, pending setup and withdrawn plans, and for a plan whose link you have disabled.

**Disable link** on a plan's row closes its public checkout URL without withdrawing the plan. Only the shared URL stops working, and the plan stays purchasable from your listing and through deeplinks.

## How buyers subscribe

A creator reaches checkout for a plan in one of three ways:

1. The plan picker on your listing.
2. A [deeplink](/docs/payments/app-billing/deeplinks#behaviour-by-viewer-state) with the plan preselected, or straight into checkout.
3. The plan's `checkoutUrl`. The buyer must be signed in to Fanvue.

## Change plan

A subscribed creator can move between your plans with **Change plan**. Fanvue classifies the move by monthly price and handles it as follows:

| Move | Behaviour |
| - | - |
| Upgrade to a higher monthly price | Immediate. Fanvue charges a prorated amount under an `appupg_` purchase reference and emits `app.payment.succeeded` with `billing_reason: subscription_update` |
| Upgrade during a free trial | Immediate, with no charge. The new price bills at the first renewal after the trial |
| Downgrade to a lower monthly price | Scheduled. The current plan runs to the period end, then the subscription switches |
| Either direction on a subscription set to cancel at period end | The cancellation is cleared and the subscription renews on the new plan |

A yearly plan is compared at its monthly equivalent, so a yearly plan can rank as a downgrade from a dearer monthly one.

## What fires when someone subscribes

Money and access arrive as separate events.

| Moment | Events |
| - | - |
| Initial purchase | `app.payment.succeeded` (`billing_reason: subscription_initial`) and `app.subscription.activated` |
| Monthly renewal | `app.payment.succeeded` (`billing_reason: subscription_renewal`) |
| Upgrade proration | `app.payment.succeeded` (`billing_reason: subscription_update`) |
| Failed renewal charge | `app.payment.failed` with a decline `reason` |
| Buyer turns off auto-renew | `app.subscription.cancel_at_period_end_changed`; the buyer keeps access until the period ends |

Branch on `cancel_at_period_end` to learn that access ends at the period end, and read live state from `GET /apps/{appUuid}/subscription/me` (`hasActiveSubscription`, `currentPeriodEnd`, `cancelAtPeriodEnd`). Payload fields are in [App events: subscriptions](/docs/webhooks/app/subscriptions).

## Tracking revenue

Subscriber counts appear in the pricing table, and earnings on your app's **Revenue** tab. To reconcile in code, read `GET /apps/{appUuid}/payments`. The invoice number on each payment matches `data.id` on the `app.payment.*` event.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.