> ## 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.

# App Subscriptions

> Read the pricing lifecycle of a Fanvue app and the current user’s entitlement to it, using the app subscription-status and subscription/me endpoints.

If you're building a Fanvue app with App Store pricing, you can use the app subscription endpoints to read:

* the pricing lifecycle for a developer-owned app
* the authenticated user's current subscription entitlement for that app

These are read-only endpoints designed for app dashboards, builder surfaces, and server-side feature gating.

<Info>Both endpoints require the `read:self` scope.</Info>

## Available endpoints

* `GET /apps/{appUuid}/subscription-status`
* `GET /apps/{appUuid}/subscription/me`

## Which endpoint should I use?

Use `GET /apps/{appUuid}/subscription-status` when you need to understand the lifecycle of an app's pricing plans as the app owner or developer.

Use `GET /apps/{appUuid}/subscription/me` when your app needs to know whether the currently authenticated user has an active, pending, cancelled, or absent subscription for that app.

## Get app pricing lifecycle

`GET /apps/{appUuid}/subscription-status` returns a lifecycle summary for the app and includes each pricing plan's status.

### Response fields

* `availability`: whether pricing lifecycle data is fully available
* `overallStatus`: one of `notConfigured`, `pendingSetup`, `active`, `withdrawn`, `mixed`, or `unavailable`
* `pricingPlans[]`: each plan's `uuid`, `name`, `billingType`, `interval`, `price`, `currencyCode`, and `status`

### Example request

```bash theme={null}
curl -X GET "https://api.fanvue.com/apps/00000000-0000-4000-8000-000000000001/subscription-status" \
  -H "Authorization: Bearer ACCESS_TOKEN" \
  -H "X-Fanvue-API-Version: 2025-06-26"
```

### Example response

```json theme={null}
{
  "appUuid": "00000000-0000-4000-8000-000000000001",
  "appName": "Example App",
  "availability": "complete",
  "overallStatus": "pendingSetup",
  "pricingPlans": [
    {
      "uuid": "00000000-0000-4000-8000-000000000002",
      "name": "Monthly",
      "billingType": "recurring",
      "interval": "monthly",
      "price": 999,
      "currencyCode": "USD",
      "status": "pending_setup"
    }
  ]
}
```

### Error behavior

* `403`: the authenticated user does not have access to this app
* `404`: the app could not be found for the authenticated user
* `503`: the environment is not configured to serve developer app subscription data

## Get current user subscription for an app

`GET /apps/{appUuid}/subscription/me` returns the authenticated user's entitlement for the app, plus a `managedCreators` array describing per-creator entitlements for any creators the user is assigned to manage (relevant only for agency team members).

<Note>
  The access token must belong to the same Fanvue app identified by `appUuid`. In practice, that means the OAuth client used to mint the token must match the app's OAuth client.
</Note>

### Response fields

Top-level fields describe the **authenticated OAuth user's own** subscription state:

* `userUuid`: the OAuth user's UUID. This may be a creator **or** an agency team member, do not assume it is always a creator.
* `hasActiveSubscription`: whether the current subscription is active
* `status`: one of `active`, `pending`, `cancelled`, or `none`
* `planUuid` / `planName`: the matched pricing plan, if one exists
* `currentPeriodEnd`: the current billing period end, if available
* `cancelAtPeriodEnd`: whether the subscription is set to end after the current period
* `managedCreators`: per-creator subscription records for creators this user is explicitly assigned to manage (agency team members only). Always present in the response, `[]` for non-agency users.

Each entry in `managedCreators` mirrors the top-level shape, scoped to a single managed creator: `userUuid` (the creator's UUID), `hasActiveSubscription`, `status`, `planUuid`, `planName`, `currentPeriodEnd`, `cancelAtPeriodEnd`.

### Example request

```bash theme={null}
curl -X GET "https://api.fanvue.com/apps/00000000-0000-4000-8000-000000000001/subscription/me" \
  -H "Authorization: Bearer ACCESS_TOKEN" \
  -H "X-Fanvue-API-Version: 2025-06-26"
```

### Example response, non-agency creator with an active subscription

```json theme={null}
{
  "appUuid": "00000000-0000-4000-8000-000000000001",
  "userUuid": "00000000-0000-4000-8000-000000000003",
  "hasActiveSubscription": true,
  "status": "active",
  "planUuid": "00000000-0000-4000-8000-000000000002",
  "planName": "Pro Monthly",
  "currentPeriodEnd": "2026-05-01T00:00:00.000Z",
  "cancelAtPeriodEnd": false,
  "managedCreators": []
}
```

### Example response, agency team member with two managed creators

```json theme={null}
{
  "appUuid": "00000000-0000-4000-8000-000000000001",
  "userUuid": "00000000-0000-4000-8000-000000000010",
  "hasActiveSubscription": false,
  "status": "none",
  "planUuid": null,
  "planName": null,
  "currentPeriodEnd": null,
  "cancelAtPeriodEnd": false,
  "managedCreators": [
    {
      "userUuid": "00000000-0000-4000-8000-000000000011",
      "hasActiveSubscription": true,
      "status": "active",
      "planUuid": "00000000-0000-4000-8000-000000000002",
      "planName": "Pro Monthly",
      "currentPeriodEnd": "2026-05-01T00:00:00.000Z",
      "cancelAtPeriodEnd": false
    },
    {
      "userUuid": "00000000-0000-4000-8000-000000000012",
      "hasActiveSubscription": false,
      "status": "none",
      "planUuid": null,
      "planName": null,
      "currentPeriodEnd": null,
      "cancelAtPeriodEnd": false
    }
  ]
}
```

### Agency team members

Agency team members (Fanvue users that belong to one or more agencies and manage a set of creators) never install third-party apps themselves, only creators do. Two things follow from that:

1. **Top-level fields describe the team member's own subscription**, which is always empty (`status: "none"`, `hasActiveSubscription: false`, `planUuid: null`, ...). Render entitlement off `managedCreators`, not the top level, when you detect an agency context.
2. **No 404 for agency users.** Where a non-agency user with no subscription would receive `404`, an agency team member receives `200` with the empty top-level shape plus their `managedCreators` array.

A team member only sees creators they are explicitly assigned to manage via the agency's team-member-to-creator mapping, chatters see only their assigned subset; admins typically see all of the agency's creators.

For agency team members, the `read:self` scope continues to gate this endpoint and now also surfaces basic subscription state for each creator the team member is assigned to manage. No additional scope is required.

### Iterating over `managedCreators`

For agency-aware app surfaces, branch on `managedCreators` rather than the top-level subscription:

```typescript theme={null}
type SubscriptionRecord = {
  userUuid: string;
  hasActiveSubscription: boolean;
  status: "active" | "pending" | "cancelled" | "none";
  planUuid: string | null;
  planName: string | null;
  currentPeriodEnd: string | null;
  cancelAtPeriodEnd: boolean;
};

type AppSubscriptionMeResponse = SubscriptionRecord & {
  appUuid: string;
  managedCreators: SubscriptionRecord[];
};

async function renderEntitlements(appUuid: string, accessToken: string) {
  const res = await fetch(
    `https://api.fanvue.com/apps/${appUuid}/subscription/me`,
    {
      headers: {
        Authorization: `Bearer ${accessToken}`,
        "X-Fanvue-API-Version": "2025-06-26",
      },
    },
  );

  if (res.status === 404) {
    return { self: null, managed: [] };
  }
  if (!res.ok) throw new Error(`subscription/me failed: ${res.status}`);

  const body = (await res.json()) as AppSubscriptionMeResponse;

  const self: SubscriptionRecord | null = body.hasActiveSubscription
    ? {
        userUuid: body.userUuid,
        hasActiveSubscription: body.hasActiveSubscription,
        status: body.status,
        planUuid: body.planUuid,
        planName: body.planName,
        currentPeriodEnd: body.currentPeriodEnd,
        cancelAtPeriodEnd: body.cancelAtPeriodEnd,
      }
    : null;

  const managed = body.managedCreators.map((c) => ({
    creatorUuid: c.userUuid,
    isPaid: c.hasActiveSubscription,
    plan: c.planName,
    renewsOrEndsAt: c.currentPeriodEnd,
  }));

  return { self, managed };
}
```

<Warning>
  At most 100 managed-creator records are returned. Agencies with more than 100 assigned creators will see the list truncated; pagination will be added if real usage exceeds this.

  A managed-creator lookup that fails upstream is silently dropped from the array rather than failing the whole call. Treat the absence of a creator from `managedCreators` as "no information" rather than "no subscription".
</Warning>

### Error behavior

* `400`: `appUuid` is not a valid UUID
* `401`: bearer token is missing or invalid
* `403`: the OAuth token has insufficient scope, or `appUuid` does not belong to the OAuth client that issued the token
* `404`: non-agency user has no subscription record for this app. Agency team members no longer hit this, they receive `200` with an empty self-subscription and a populated `managedCreators` array
* `410`: API version sunset
* `502`: the upstream developer/app-integration service returned an error
* `503`: the environment is not configured to serve developer app subscription data (typically only in non-production environments)

## Typical usage pattern

1. Create and configure your Fanvue app in the Developer area.
2. Authenticate a user with OAuth and request `read:self`.
3. Use `subscription-status` in owner-facing or builder experiences to show pricing lifecycle.
4. Use `subscription/me` in your server-side app logic to gate paid features for the current user. For agency-aware experiences, also iterate `managedCreators` to render per-creator entitlements.

For local and staged testing guidance, see [Testing Your App](/docs/introduction/testing-your-app). For App Store policy and pricing constraints, see [App Store Listing Requirements](/docs/app-store/listing-requirements).

## Getting notified instead of polling

These endpoints are for reading current state. To be told about your app's sales
as they happen (purchases, subscription activations, refunds, disputes),
subscribe to the `app.*` webhooks:

<Card title="App Webhooks" icon="puzzle-piece" href="/docs/app-store/webhooks" horizontal>
  `app.payment.*`, `app.subscription.*`, `app.refund.created`, and
  `app.dispute.*` for your app's own sales. Gated on `read:self`.
</Card>
