---
title: "Get fan insights"
method: GET
path: "/insights/fans/{userUuid}"
---

# Get fan insights

`GET /insights/fans/{userUuid}`

Returns detailed insights about a specific fan for the authenticated creator, including spending statistics, subscription status, and fan engagement metrics.

Each money field comes as a gross value and a net one, net meaning refunded and charged-back purchases removed: `total` and `netTotal`, `count` and `netCount`, `average` and `netAverage`. `spending.total.total` has always been net of reversals, so the gross per-source figures can add up to more than it and the gap is exactly the reversals, which are not returned as a source of their own; the per-source `netTotal` values add up to `spending.total.netTotal`. `spending.maxSinglePayment` drops reversed purchases entirely, which is why it carries no net variant.

A reversal is normally a separate invoice for the full original amount: there are no partial refunds, and the original payment is never rewritten, so the original still appears on `/insights/earnings`. Pair the two through `reversedTransactionOrderId` on the `refund`/`chargeback` rows of that endpoint. A payment marked refunded or charged back without a linked reversal invoice is the exception: there is no negative row for `spending.total.total` to subtract so it does not come down, while every net figure drops the purchase. That is why the net total is aggregated over the surviving purchases rather than derived from the gross one.

Every figure here is computed on each request with no caching — the spending fields from live invoice data, `status` and the `subscription` block from the subscription, follow and payment-method records — so two reads seconds apart can legitimately differ.

## Path parameters

- `userUuid` string, uuid, required — Fan's UUID

## Headers

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

## Response `200`

Fan insights data

- object
  - `status` 'subscriber' | 'expired' | 'follower' | 'not_contactable', required — Current fan status
  - `spending` object, required
    - `lastPurchaseAt` string, date-time, nullable, required — When this fan last paid this creator (ISO 8601), or null if they never have. Fan-initiated payments only, so an automatic subscription renewal never moves it, and App Store purchases do not count as a purchase here. Reversed purchases are NOT skipped: a purchase later refunded or charged back still counts as the last purchase, because the fan did reach for their wallet at that moment, which makes this recency of intent rather than recency of valid spend. Use `lastValidPurchaseAt` for the latter.
    - `lastValidPurchaseAt` string, date-time, nullable, required — Same as `lastPurchaseAt` but skipping purchases later refunded or charged back, so this is recency of valid spend. Null when every self-initiated purchase was reversed.
    - `total` object, required
      - `gross` number, required — DEPRECATED: use `total`. Total amount this fan paid across all transactions, in USD cents. Same value as `total`, and net of reversals despite the field name.
      - `total` number, required — Total amount this fan paid across all transactions, in USD cents. Excludes App Store purchases, which record a creator buying an app from its developer rather than a fan paying this creator. Net of reversals: a refund or chargeback is a separate invoice for the full original amount and is subtracted here, so this is normally lower than the sum of the gross `sources` figures and can be negative. Reversals are selected by their own type rather than by what they reverse, so a clawed-back creator reward the fan never paid for is subtracted here too, and this can fall below what the fan actually paid. It is not the same as `netTotal`, which is aggregated over the surviving purchases instead; the two differ for a purchase reversed without a reversal invoice, which has no negative row for this figure to subtract.
      - `netTotal` number, required — Total this fan paid with refunded and charged-back purchases removed, in USD cents. Aggregated over the surviving purchases themselves, so it and the per-source `netTotal` values describe one set of purchases and add up. It usually equals `total`, which subtracts reversals by counting their negative rows; the two part company only for a reversal recorded on the original purchase without a row of its own, which `total` cannot see.
    - `maxSinglePayment` object, required
      - `gross` number, required — DEPRECATED: use `total`. Largest single payment this fan made, in USD cents. Same value as `total`, and excludes reversed purchases.
      - `total` number, required — Largest single payment this fan made, in USD cents. Excludes App Store purchases, as `total` does. Excludes reversed purchases: a payment later refunded or charged back is not eligible, so this can be lower than the largest amount the fan ever paid. Reversal invoices themselves are never counted. This has been the behaviour since July 2025. A refund or chargeback marker on the payment counts as a reversal in its own right when no reversal invoice is linked, so a purchase reversed that way is excluded too; a purchase whose reversal was created and then failed stays eligible, because that reversal never settled.
    - `sources` object, required — Breakdown of this fan's spend by source, keyed by the same source names /insights/earnings uses (so `renewal` is a catch-all for every recurring charge after the first payment). `appStore` is never present: an App Store invoice records a creator buying an app from its developer, not a fan paying this creator. `fanExperience` is fan-to-creator spend and is included. Refunds and chargebacks are never a source entry of their own. Each entry carries both treatments: `total`, `count` and `average` are gross of reversals, so the `total` values do not sum to `total.total` and the difference is exactly the reversals, while `netTotal`, `netCount` and `netAverage` drop the reversed purchases and the `netTotal` values do sum to `total.netTotal`.
  - `subscription` object, required
    - `createdAt` string, date-time, nullable, required — Date subscription was created (ISO 8601) or null if no subscription
    - `renewsAt` string, date-time, nullable, required — Date subscription renews (ISO 8601) or null if no active subscription
    - `autoRenewalEnabled` boolean, required — Whether fan has active recurring subscription

## Other responses

- `400` — Bad Request - API version not supported OR validation failed (dates, sources, cursor, pagination)
- `401` — Unauthorized Response
- `403` — Unauthorized Response
- `404` — Not Found Response
- `410` — API version no longer supported (sunset)
- `429` — Too many requests - rate limit exceeded

## Changes

- **2026-08-30** `dce5621fe589` — 7 info
  - added the required property `spending/lastValidPurchaseAt` to the response with the `200` status
  - added the required property `spending/sources/additionalProperties/average` to the response with the `200` status
  - added the required property `spending/sources/additionalProperties/count` to the response with the `200` status
  - added the required property `spending/sources/additionalProperties/netAverage` to the response with the `200` status
  - …3 more

[Change history](https://skmtc.dev/fanvue/apis/fanvue-api/changes/insights/fans/:userUuid/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)
