# Whales and churn

Find the fans who spend most, see what they buy, and spot the ones who are slipping away.

## Calls

| Step | MCP tool | REST route |
| --- | --- | --- |
| Top spenders | `find_fans` | `GET /v1/accounts/{accountId}/fans?sort=spend&status=all` |
| Spend by type, lists, notes | `get_fan` | `GET /v1/accounts/{accountId}/fans/{fanId}` |
| Recent purchases | `list_transactions` | `GET /v1/accounts/{accountId}/transactions?fanId=` |
| How the last chat ended | `get_chat` | `GET /v1/accounts/{accountId}/chats/{fanId}/messages` |

## Steps

1. Call `list_accounts` and pick the accounts to cover.
2. For each account, call `find_fans` with `sort=spend`, `status=all` and `limit=25`. `status=all` keeps fans whose subscription ran out, which is where churn shows. These are the whales, ranked by lifetime gross spend (`spend.total`).
3. For the top ten, call `get_fan`. Note:
   - `spend` split into `subscriptions`, `tips`, `messages` (paid messages), `posts` and `other`. The largest one is what they mostly buy.
   - `subscription.status`, `subscription.expiresAt` and `subscription.renews`.
   - `lastPurchaseAt` and `lastMessageAt`.
   - `lists` and the creator's `notes`.
4. For the same fans, call `list_transactions` with `fanId`, `from` set to 90 days ago and `limit=50`. Add up `gross` for their spend in the last 90 days. If `hasMore` is true, page on with `cursor` before you add.
5. Mark a whale as at risk when any of these is true:
   - `lastPurchaseAt` is more than 14 days ago, or null.
   - `subscription.status` is `expired`.
   - `subscription.renews` is `false`.
   - Their 90 day spend is far below their usual pace, for example under a quarter of lifetime spend divided by months subscribed.
6. For each at risk whale, call `get_chat` with `limit=10` to see how the last conversation ended. Look for an unanswered question, a skipped paid message or a complaint.
7. Suggest one next step per at risk whale. If it is a message, draft it with `draft_message` and show it. Ask for `send_message` only when the user says to send it.

## Output

A table per account, then the at risk list.

```text
Fan              Lifetime   Last 90 days  Mostly buys     Last purchase  Subscription
Mike (@mike88)   $2,310.00  $640.00       paid messages   2 days ago     active, renews
Ana (@ana_k)     $1,980.00  $0.00         tips            41 days ago    expired
```

```text
At risk
Ana (@ana_k): no purchase in 41 days, subscription expired. Last chat ended with her question about a custom set, unanswered.
Suggested: a free message that answers the question, no price.
```

The numbers above are an example of the layout, not real data.

## Pitfalls

- `spend.total` is gross. `spend.net` is the creator's share. Label which one you show.
- Fan spend is part of account revenue. Never add the two.
- Presence is a guess. Do not call a fan "gone" because they are not online.
- A fan who never subscribed (`subscription.status` is `never`) can still buy paid messages. Do not count them as churned.
- Re-offering a paid message the fan already skipped at the same price rarely works. Check `purchased` on paid messages in the chat first.
