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

# Available Fansly webhook events (/webhooks/fansly-events)

<Callout title="Looking for a specific event?">
  Please reach out to us, we can add it!
</Callout>

All Fansly events are prefixed with `fansly.` so they never collide with the [OnlyFans events](/webhooks/available-events). Delivery is driven by our Fansly websocket relay rather than polling, so events arrive in near real-time.

Fansly events only appear in the event picker once your team has a [connected Fansly account](/api-reference/fansly/connect-fansly-account/start-authentication). If you don't see them when [subscribing to a webhook](/webhooks/subscribing-to-webhooks), connect an account first.

## Payload conventions

Fansly events use the same envelope as the OnlyFans events: an `event` name, the `account_id` of the connected account, and a platform-native `payload`:

```json title="Envelope"
{
  "event": "fansly.<category>.<name>",
  "account_id": "fansly_acct_123",
  "payload": { }
}
```

Within `payload`, Fansly's own conventions apply:

<Callout type="warn" title="Money is in thousandths of a dollar">
  Unlike the OnlyFans events, Fansly amounts are **not** dollars and **not** cents. `15000` means `$15.00`. Divide by `1000` before displaying or storing an amount.
</Callout>

* **IDs are snowflake strings**, not integers. Keep them as strings, because they exceed the safe integer range in JavaScript and other 53-bit float languages.
* **Timestamps are Unix epoch**, in seconds *or* milliseconds depending on the upstream field (e.g. `createdAt` is seconds on `fansly.posts.created`, but milliseconds on `fansly.subscriptions.new`). Check the magnitude before parsing.
* **`type` fields are Fansly enums**, not strings. Their meaning is specific to each event.

## Coming from the OnlyFans events?

The catalogs are not identical. If you're porting an existing OnlyFans integration:

| OnlyFans event                                                                                                                                  | Fansly equivalent                                                                                                                 |
| ----------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------- |
| [`subscriptions.new`](/webhooks/available-events#subscriptionsnew) + [`subscriptions.renewed`](/webhooks/available-events#subscriptionsrenewed) | [`fansly.subscriptions.new`](#fanslysubscriptionsnew) covers both new and returning subscribers                                   |
| [`messages.ppv.unlocked`](/webhooks/available-events#messagesppvunlocked)                                                                       | [`fansly.media.purchased`](#fanslymediapurchased)                                                                                 |
| [`users.online`](/webhooks/available-events#usersonline) / [`users.offline`](/webhooks/available-events#usersoffline)                           | Not available. Fansly exposes no fan presence signal                                                                              |
| `chat_queue.updated` / `chat_queue.finished`                                                                                                    | Not available                                                                                                                     |
| `accounts.reconnected`, `accounts.session_expired`                                                                                              | Folded into [`fansly.accounts.connected`](#fanslyaccountsconnected)                                                               |
| `accounts.otp_code_required`, `accounts.face_otp_required`                                                                                      | Not available. Poll [Poll Authentication Status](/api-reference/fansly/connect-fansly-account/poll-authentication-status) instead |
| (none)                                                                                                                                          | Fansly adds reactions, read receipts, wall post lifecycle, media likes, followers, payouts and story purchases                    |

## Accounts

### `fansly.accounts.connected`

A Fansly account was connected or re-authenticated. Fires for all of your Fansly accounts.

```json title="Example payload"
{
    "event": "fansly.accounts.connected",
    "account_id": "fansly_acct_123",
    "payload": {
        "status": "authenticated",
        "is_session_active": true,
        "last_authenticated_at": "2026-01-01T02:33:20+00:00",
        "last_error": null,
        "fansly_user": {
            "id": "100000000000000001",
            "username": "example_creator",
            "display_name": "Example Creator"
        }
    }
}
```

### `fansly.accounts.authentication_failed`

An account login attempt failed. Reconnect with our [/authenticate](/api-reference/fansly/connect-fansly-account/start-authentication) endpoint or manually in our [dashboard](https://app.onlyfansapi.com).

```json title="Example payload"
{
    "event": "fansly.accounts.authentication_failed",
    "account_id": "fansly_acct_123",
    "payload": {
        "status": "auth-failed",
        "is_session_active": false,
        "last_authenticated_at": null,
        "last_error": "Fansly login failed: invalid credentials",
        "fansly_user": null
    }
}
```

## Messages

### `fansly.messages.received`

A message was received from a fan. Includes the resolved sender identity in `senderData`.

```json title="Example payload"
{
    "event": "fansly.messages.received",
    "account_id": "fansly_acct_123",
    "payload": {
        "type": 1,
        "attachments": [],
        "content": "hey! loved your latest post",
        "groupId": "100000000000000001",
        "senderId": "200000000000000002",
        "inReplyTo": "",
        "interactions": [
            {
                "groupId": "100000000000000001",
                "userId": "300000000000000003",
                "readAt": 0,
                "deliveredAt": 0,
                "messageId": "400000000000000004"
            }
        ],
        "id": "400000000000000004",
        "createdAt": 1767230000.045,
        "embeds": [],
        "direction": "incoming",
        "senderData": {
            "available": true,
            "id": "200000000000000002",
            "username": "example_fan",
            "display_name": "Example Fan",
            "avatar": "https://cdn.fansly.example/avatars/200000000000000002.jpg"
        }
    }
}
```

### `fansly.messages.sent`

A message was sent from one of your Fansly accounts, from our API, the Fansly app, or any other tool.

```json title="Example payload"
{
    "event": "fansly.messages.sent",
    "account_id": "fansly_acct_123",
    "payload": {
        "type": 1,
        "attachments": [],
        "content": "thank you so much! 💕",
        "groupId": "100000000000000001",
        "senderId": "300000000000000003",
        "inReplyTo": "",
        "interactions": [
            {
                "groupId": "100000000000000001",
                "userId": "200000000000000002",
                "readAt": 0,
                "deliveredAt": 0,
                "messageId": "500000000000000005"
            }
        ],
        "id": "500000000000000005",
        "createdAt": 1767231000.421,
        "embeds": [],
        "direction": "outgoing"
    }
}
```

### `fansly.messages.deleted`

A chat message was deleted. The payload carries the last known message body, so you can reconcile without a lookup.

```json title="Example payload"
{
    "event": "fansly.messages.deleted",
    "account_id": "fansly_acct_123",
    "payload": {
        "id": "400000000000000004",
        "type": 1,
        "dataVersion": 1,
        "content": "hey! loved your latest post",
        "groupId": "100000000000000001",
        "senderId": "200000000000000002",
        "correlationId": "0",
        "inReplyTo": null,
        "inReplyToRoot": null,
        "createdAt": 1767230000,
        "attachments": [],
        "embeds": [],
        "interactions": [
            {
                "userId": "300000000000000003",
                "readAt": 0,
                "deliveredAt": 1767230004000
            }
        ],
        "likes": [],
        "deletedAt": 1767230009,
        "direction": "incoming"
    }
}
```

### `fansly.messages.read`

A read receipt for a conversation. `messageIds` lists the messages marked as read by `userId`.

```json title="Example payload"
{
    "event": "fansly.messages.read",
    "account_id": "fansly_acct_123",
    "payload": {
        "groupId": "100000000000000001",
        "messageIds": [
            "400000000000000004"
        ],
        "userId": "200000000000000002",
        "userReadReceiptsEnabled": true,
        "type": 1,
        "recipients": [
            {
                "userId": "300000000000000003",
                "readReceiptsEnabled": true
            },
            {
                "userId": "200000000000000002",
                "readReceiptsEnabled": true
            }
        ]
    }
}
```

### `fansly.messages.reaction_added`

A fan reacted to a chat message. `type` is the emoji reaction id.

```json title="Example payload"
{
    "event": "fansly.messages.reaction_added",
    "account_id": "fansly_acct_123",
    "payload": {
        "accountId": "200000000000000002",
        "messageId": "400000000000000004",
        "type": 5,
        "groupId": "100000000000000001",
        "id": "410000000000000041"
    }
}
```

### `fansly.messages.reaction_removed`

A reaction was removed from a chat message.

```json title="Example payload"
{
    "event": "fansly.messages.reaction_removed",
    "account_id": "fansly_acct_123",
    "payload": {
        "accountId": "200000000000000002",
        "messageId": "400000000000000004",
        "type": 5,
        "groupId": "100000000000000001",
        "id": "410000000000000042"
    }
}
```

## Posts

### `fansly.posts.created`

You published a new wall post. Fires once per wall the post lands on, so a post added to multiple walls produces multiple events with the same `postId`.

```json title="Example payload"
{
    "event": "fansly.posts.created",
    "account_id": "fansly_acct_123",
    "payload": {
        "postId": "500000000000000005",
        "wallId": "200000000000000010",
        "wall": {
            "id": "200000000000000010",
            "accountId": "100000000000000001",
            "pos": 0,
            "name": "Posts",
            "description": "",
            "private": 0,
            "metadata": ""
        },
        "post": {
            "id": "500000000000000005",
            "accountId": "100000000000000001",
            "content": "New set just dropped 🔥 #newpost",
            "fypFlags": 0,
            "inReplyTo": null,
            "inReplyToRoot": null,
            "createdAt": 1767230000,
            "expiresAt": null,
            "attachments": [
                {
                    "postId": "500000000000000005",
                    "pos": 0,
                    "contentType": 1,
                    "contentId": "600000000000000006",
                    "deletedAt": null
                }
            ]
        },
        "metadata": {
            "recentPost": true
        }
    }
}
```

### `fansly.posts.updated`

You edited a wall post.

```json title="Example payload"
{
    "event": "fansly.posts.updated",
    "account_id": "fansly_acct_123",
    "payload": {
        "id": "500000000000000005",
        "accountId": "100000000000000001",
        "content": "New set just dropped 🔥 (now with more pics) #newpost",
        "fypFlags": 0,
        "inReplyTo": null,
        "inReplyToRoot": null,
        "createdAt": 1767230000,
        "expiresAt": 0,
        "attachments": [
            {
                "contentType": 1,
                "contentId": "600000000000000006"
            }
        ],
        "likeCount": 12,
        "postReplyPermissionFlags": [],
        "wallIds": [
            "200000000000000010"
        ]
    }
}
```

### `fansly.posts.deleted`

A wall post was deleted.

```json title="Example payload"
{
    "event": "fansly.posts.deleted",
    "account_id": "fansly_acct_123",
    "payload": {
        "wallId": "200000000000000010",
        "postId": "500000000000000005",
        "wall": {
            "id": "200000000000000010",
            "accountId": "100000000000000001",
            "pos": 0,
            "name": "Posts",
            "description": "",
            "private": 1,
            "metadata": ""
        }
    }
}
```

### `fansly.posts.pinned`

A wall post was pinned.

```json title="Example payload"
{
    "event": "fansly.posts.pinned",
    "account_id": "fansly_acct_123",
    "payload": {
        "postId": "500000000000000005",
        "accountId": "100000000000000001",
        "pos": 0,
        "wallId": "200000000000000010"
    }
}
```

### `fansly.posts.liked`

A fan liked one of your posts. `correlationId` is the post, `correlationGroupId` is the fan who liked it.

```json title="Example payload"
{
    "event": "fansly.posts.liked",
    "account_id": "fansly_acct_123",
    "payload": {
        "id": "920000000000000021",
        "type": 1002,
        "accountId": "100000000000000001",
        "correlationId": "700000000000000070",
        "correlationGroupId": "200000000000000002",
        "lookups": [
            {
                "lookupId": "930000000000000030"
            }
        ]
    }
}
```

## Media

### `fansly.media.purchased`

A fan purchased a media item. This is the Fansly equivalent of an unlocked PPV. Bundles fire one event per item, so a single checkout can produce several events. `orderMetadata.accountMediaPrice` is in thousandths of a dollar.

```json title="Example payload"
{
    "event": "fansly.media.purchased",
    "account_id": "fansly_acct_123",
    "payload": {
        "orderId": "940000000000000040",
        "accountMediaId": "800000000000000080",
        "correlationAccountId": "100000000000000001",
        "accountId": "200000000000000002",
        "type": 1,
        "orderMetadata": {
            "accountMediaPrice": 15000
        }
    }
}
```

### `fansly.media.liked`

A fan liked a media item. `correlationId` is the media, `correlationGroupId` is the fan.

<Callout type="warn" title="High volume">
  Popular accounts can receive these continuously. Only subscribe if you actually process them, and make sure your endpoint can keep up.
</Callout>

```json title="Example payload"
{
    "event": "fansly.media.liked",
    "account_id": "fansly_acct_123",
    "payload": {
        "id": "920000000000000022",
        "type": 2002,
        "accountId": "100000000000000001",
        "correlationId": "800000000000000080",
        "correlationGroupId": "200000000000000002",
        "lookups": [
            {
                "lookupId": "930000000000000031"
            }
        ],
        "metadata": "{\"likeId\":\"930000000000000031\",\"accountMediaAccess\":true}"
    }
}
```

## Subscriptions

### `fansly.subscriptions.new`

A subscription became active. Unlike the OnlyFans events, this single event covers both new and returning subscribers, so there is no separate renewal event. `price` and `renewPrice` are in thousandths of a dollar, and the timestamps are epoch milliseconds.

```json title="Example payload"
{
    "event": "fansly.subscriptions.new",
    "account_id": "fansly_acct_123",
    "payload": {
        "id": "500000000000000005",
        "historyId": "510000000000000005",
        "accountId": "100000000000000001",
        "subscriberId": "200000000000000002",
        "subscriptionTierId": "600000000000000006",
        "subscriptionTierName": "Example Tier",
        "subscriptionTierColor": "#46A7F8",
        "planId": "610000000000000006",
        "promoId": "0",
        "giftCodeId": null,
        "paymentMethodId": "0",
        "status": 3,
        "price": 9990,
        "renewPrice": 9990,
        "renewCorrelationId": "510000000000000005",
        "autoRenew": 1,
        "version": 2,
        "billingCycle": 30,
        "duration": 30,
        "renewDate": 1767230000000,
        "createdAt": 1767230000000,
        "endsAt": 1769908400000,
        "promoDuration": null,
        "promoStartsAt": null,
        "promoEndsAt": null,
        "updatedAt": 1767230000998,
        "subscriptionStreak": 0,
        "subscriptionTotalDays": 0
    }
}
```

### `fansly.subscriptions.expired`

A fan's subscription expired. `correlationId` is the subscription, `correlationGroupId` is the fan.

```json title="Example payload"
{
    "event": "fansly.subscriptions.expired",
    "account_id": "fansly_acct_123",
    "payload": {
        "id": "920000000000000020",
        "type": 15007,
        "accountId": "100000000000000001",
        "correlationId": "500000000000000005",
        "correlationGroupId": "200000000000000002"
    }
}
```

## Followers

### `fansly.followers.new`

A fan followed your account.

```json title="Example payload"
{
    "event": "fansly.followers.new",
    "account_id": "fansly_acct_123",
    "payload": {
        "id": "910000000000000010",
        "followerId": "200000000000000002",
        "accountId": "100000000000000001",
        "accountSortOrder": 1
    }
}
```

### `fansly.followers.removed`

A fan unfollowed your account.

<Callout type="info">
  `createdAt` is the date of the **original follow**, not the unfollow. Use your own receive time if you need to know when the unfollow happened.
</Callout>

```json title="Example payload"
{
    "event": "fansly.followers.removed",
    "account_id": "fansly_acct_123",
    "payload": {
        "id": "910000000000000010",
        "followerId": "200000000000000002",
        "accountId": "100000000000000001",
        "createdAt": 1764547200000
    }
}
```

## Payouts

### `fansly.payouts.created`

A payout was requested. `amount` is in thousandths of a dollar, so `5000000` is `$5,000.00`.

```json title="Example payload"
{
    "event": "fansly.payouts.created",
    "account_id": "fansly_acct_123",
    "payload": {
        "id": "950000000000000050",
        "accountId": "100000000000000001",
        "amount": 5000000,
        "payoutMethodId": "960000000000000060",
        "status": 1,
        "version": 0
    }
}
```

### `fansly.payouts.updated`

A payout request changed status. Compare `version` to detect ordering if events arrive out of sequence.

```json title="Example payload"
{
    "event": "fansly.payouts.updated",
    "account_id": "fansly_acct_123",
    "payload": {
        "id": "950000000000000050",
        "accountId": "100000000000000001",
        "amount": 5000000,
        "payoutMethodId": "960000000000000060",
        "status": 2,
        "version": 1
    }
}
```

## Transactions & Tips

### `fansly.transactions.new`

A new earning: a subscription, tip, PPV purchase, and so on. Payouts are excluded; use the [payout events](#fanslypayoutscreated) for those.

`amount` is the gross amount, `destinationTax` the platform cut, and `destinationAmount` what you actually receive. All three are in thousandths of a dollar.

```json title="Example payload"
{
    "event": "fansly.transactions.new",
    "account_id": "fansly_acct_123",
    "payload": {
        "id": "700000000000000007",
        "type": 2110,
        "correlationId": "800000000000000008",
        "walletId": "900000000000000009",
        "destinationWalletId": "900000000000000009",
        "accountId": "200000000000000002",
        "amount": 15000,
        "destinationTax": 2000,
        "destinationAmount": 12000,
        "senderId": "200000000000000002",
        "receiverId": "100000000000000001",
        "status": 1,
        "createdAt": 1767230000000,
        "updatedAt": 1767230000000
    }
}
```

### `fansly.tips.received`

You received a tip from a fan. This is the same transaction shape as above with a `type` in the tip range, so a tip that you subscribe to both events for will arrive twice: once as `fansly.tips.received` and once as `fansly.transactions.new`.

```json title="Example payload"
{
    "event": "fansly.tips.received",
    "account_id": "fansly_acct_123",
    "payload": {
        "id": "700000000000000007",
        "type": 7101,
        "correlationId": "800000000000000008",
        "walletId": "900000000000000009",
        "destinationWalletId": "900000000000000009",
        "accountId": "200000000000000002",
        "amount": 5000,
        "destinationTax": 2000,
        "destinationAmount": 4000,
        "senderId": "200000000000000002",
        "receiverId": "100000000000000001",
        "status": 1,
        "createdAt": 1767230000000,
        "updatedAt": 1767230000000
    }
}
```

## Stories

### `fansly.stories.purchased`

A fan purchased one of your paid stories. This event is keyed on `transactionId`. There is no `orderId` like on [`fansly.media.purchased`](#fanslymediapurchased).

```json title="Example payload"
{
    "event": "fansly.stories.purchased",
    "account_id": "fansly_acct_123",
    "payload": {
        "accountId": "200000000000000002",
        "storyId": "810000000000000081",
        "transactionId": "820000000000000082",
        "price": 15000,
        "type": 1,
        "correlationAccountId": "100000000000000001"
    }
}
```

## Users

### `fansly.users.typing`

A fan is typing in a conversation.

<Callout type="warn" title="High volume">
  Typing indicators fire repeatedly for a single message being composed. Debounce on your side, and don't subscribe unless you're rendering a live inbox.
</Callout>

```json title="Example payload"
{
    "event": "fansly.users.typing",
    "account_id": "fansly_acct_123",
    "payload": {
        "accountId": "200000000000000002",
        "groupId": "100000000000000001",
        "lastAnnounce": 1767229990129
    }
}
```

<Callout type="info" title="No presence events">
  Fansly does not expose fan online/offline presence, so there is no equivalent of the OnlyFans [`users.online`](/webhooks/available-events#usersonline) and [`users.offline`](/webhooks/available-events#usersoffline) events.
</Callout>