> ## 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 OnlyFans webhook events (/webhooks/available-events)

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

Looking for Fansly? See the [available Fansly webhook events](/webhooks/fansly-events).

## Accounts

### `accounts.connected`

A new OnlyFans account was connected.

<Callout>
  Please note that `payload.client_reference_id` can be null - it's only
  included if you provided us with `client_reference_id` while [Creating Client
  Session](/api-reference/client-sessions/create-client-session)
</Callout>

```json title="Example payload"
{
  "event": "accounts.connected",
  "account_id": "acct_123",
  "payload": {
    "client_reference_id": "my_crm_model_12345", // Optional - Value you provided while creating Client Session - otherwise null
    "state": "authenticated",
    "progress": "started",
    "latestAuthAttempt": {
      "started_at": "2025-05-13T20:26:56.000000Z",
      "completed_at": null,
      "success": false,
      "error_message": null,
      "needs_otp": false,
      "needs_face_otp": false,
      "otp_phone_ending": null
    }
  }
}
```

### `accounts.reconnected`

An OnlyFans account was reconnected.

```json title="Example payload"
{
  "event": "accounts.reconnected",
  "account_id": "acct_123",
  "payload": {
    "state": "authenticated",
    "progress": "started",
    "latestAuthAttempt": {
      "started_at": "2025-05-13T20:26:56.000000Z",
      "completed_at": null,
      "success": false,
      "error_message": null,
      "needs_otp": false,
      "needs_face_otp": false,
      "otp_phone_ending": null
    }
  }
}
```

### `accounts.disconnected`

An OnlyFans account was disconnected, either from the [dashboard](https://app.onlyfansapi.com) or with the [Disconnect Account](/api-reference/account/disconnect-account) endpoint.

Every request for that `acct_` ID from this point on returns a `404` with [`account_not_found`](/introduction/essentials/response-structure#account_not_found), so stop polling it when this arrives.

<Callout type="warn" title="Reconnecting gives you a new acct_ ID">
  The disconnected `acct_` ID is never reused. If the creator reconnects later,
  they come back as a new account, so key your own records on `onlyfans_id` (the
  OnlyFans user ID, stable across reconnects) rather than on the `acct_` ID.
</Callout>

```json title="Example payload"
{
  "event": "accounts.disconnected",
  "account_id": "acct_123",
  "payload": {
    "account_id": "acct_123",
    "onlyfans_id": "123456789",
    "onlyfans_username": "janedoe",
    "disconnected_at": "2025-05-13T20:26:56+00:00"
  }
}
```

<Callout title="Not the same as a broken session">
  This event only fires when the account is deliberately disconnected. A
  connection that breaks on its own gives you
  [`accounts.session_expired`](#accountssession_expired) or
  [`accounts.authentication_failed`](#accountsauthentication_failed) instead, and
  the account stays connected and usable in both of those cases.
</Callout>

### `accounts.session_expired`

OnlyFans account connection has expired, but we automatically re-connected it using our system - you don't need to do anything.

```json title="Example payload"
{
  "event": "accounts.session_expired",
  "account_id": "acct_123",
  "payload": {
    "state": "authenticated",
    "progress": "started",
    "latestAuthAttempt": {
      "started_at": "2025-05-13T20:26:56.000000Z",
      "completed_at": null,
      "success": false,
      "error_message": null,
      "needs_otp": false,
      "needs_face_otp": false,
      "otp_phone_ending": null
    }
  }
}
```

### `accounts.authentication_failed`

OnlyFans account connection has expired, and we couldn't automatically re-connect it using our system. You need to reconnect with our [/authenticate](/api-reference/connect-onlyfans-account/start-authentication) endpoint or manually in our [dashboard](https://app.onlyfansapi.com).

```json title="Example payload"
{
  "event": "accounts.authentication_failed",
  "account_id": "acct_123",
  "payload": {
    "state": "authenticated",
    "progress": "started",
    "latestAuthAttempt": {
      "started_at": "2025-05-13T20:26:56.000000Z",
      "completed_at": null,
      "success": false,
      "error_message": null,
      "needs_otp": false,
      "needs_face_otp": false,
      "otp_phone_ending": null
    }
  }
}
```

### `accounts.otp_code_required`

A two-factor authentication code is required to connect one of your OnlyFans accounts.

```json title="Example payload"
{
  "event": "accounts.otp_code_required",
  "account_id": "acct_123",
  "payload": {
    "state": "authenticated",
    "progress": "started",
    "latestAuthAttempt": {
      "started_at": "2025-05-13T20:26:56.000000Z",
      "completed_at": null,
      "success": false,
      "error_message": null,
      "needs_otp": false,
      "needs_face_otp": false,
      "otp_phone_ending": null
    }
  }
}
```

### `accounts.face_otp_required`

Face verification is required to connect one of your OnlyFans accounts.

```json title="Example payload"
{
  "event": "accounts.face_otp_required",
  "account_id": "acct_123",
  "payload": {
    "state": "authenticated",
    "progress": "started",
    "face_otp_verification_url": "https://id.onlyfans.com/s?123",
    "latestAuthAttempt": {
      "started_at": "2025-05-13T20:26:56.000000Z",
      "completed_at": null,
      "success": false,
      "error_message": null,
      "needs_otp": false,
      "needs_face_otp": false,
      "otp_phone_ending": null
    }
  }
}
```

## Transactions

### `transactions.new`

A new transaction has been received from a fan (eg. a subscription, a tip, a post, etc.).

<Callout type="info">
  Please note that this event may be delayed by up to 3 minutes.
</Callout>

| Supported `payload.type` values | Description                          |        |
| ------------------------------- | ------------------------------------ | ------ |
| `message`                       | A message has been sent to you       |        |
| `post`                          | Payment for a post                   | `post` |
| `tip`                           | Payment for a tip                    | `tip`  |
| `new_subscription`              | Payment for a new subscription       |        |
| `recurring_subscription`        | Payment for a recurring subscription |        |
| `stream`                        | Payment for a stream                 |        |
| `other`                         | Another type of transaction          |        |

```json title="Example payload"
{
  "event": "transactions.new",
  "account_id": "acct_123",
  "payload": {
    "id": "abc123",
    "created_at": "2026-01-01 00:00:00",
    "type": "message",
    "tips_source": null,
    "amount": 10,
    "vat_amount": 0,
    "tax_amount": 0,
    "net_amount": 8,
    "fee_amount": 2,
    "currency": "USD",
    "description": "Payment for message from \"<a href=\"https://onlyfans.com/johndoe\">John Doe</a>\"",
    "status": "loading",
    "fan": {
      "id": "123",
      "username": "johndoe",
      "name": "John Doe",
      "display_name": "",
      "avatar": null
    },
    "fanData": {
      "available": true,
      "last_updated_at": "2026-01-01T00:00:00.000000Z",
      "spending": {
        "total": 6.6,
        "messages": 10,
        "subscribes": 2.6,
        "posts": 0,
        "tips": 4,
        "streams": 0
      },
      "previous_reply_at": null
    }
  }
}
```

## Messages

### `messages.received`

New message received from a fan.

```json title="Example payload"
{
  "event": "messages.received",
  "account_id": "acct_123",
  "payload": {
    "responseType": "message",
    "text": "<p>Text</p>",
    "giphyId": null,
    "lockedText": false,
    "isFree": true,
    "price": 0,
    "isMediaReady": true,
    "mediaCount": 0,
    "media": [],
    "previews": [],
    "isTip": false,
    "isReportedByMe": false,
    "isCouplePeopleMedia": false,
    "queueId": 123,
    "isMarkdownDisabled": true,
    "fanData": {
      "available": true,
      "last_updated_at": "2025-10-23 00:52:34",
      "spending": {
        "total": 50,
        "messages": 30,
        "subscribes": 10,
        "posts": 0,
        "tips": 20,
        "streams": 0
      }
    },
    "fromUser": {
      "view": "s",
      "avatar": "https://example.com",
      "avatarThumbs": {
        "c50": "https://example.com",
        "c144": "https://example.com"
      },
      "header": null,
      "headerSize": null,
      "headerThumbs": null,
      "id": 123,
      "name": "Name",
      "username": "username",
      "canLookStory": true,
      "canCommentStory": true,
      "hasNotViewedStory": false,
      "isVerified": false,
      "canPayInternal": true,
      "hasScheduledStream": false,
      "hasStream": false,
      "hasStories": false,
      "tipsEnabled": false,
      "tipsTextEnabled": true,
      "tipsMin": 5,
      "tipsMinInternal": 1,
      "tipsMax": 200,
      "canEarn": false,
      "canAddSubscriber": false,
      "subscribePrice": 0,
      "displayName": "",
      "notice": "",
      "isRestricted": false,
      "canRestrict": true,
      "subscribedBy": true,
      "subscribedByExpire": false,
      "subscribedByExpireDate": "2034-12-22T00:38:29+00:00",
      "subscribedByAutoprolong": true,
      "subscribedIsExpiredNow": false,
      "currentSubscribePrice": 0,
      "subscribedOn": true,
      "subscribedOnExpiredNow": false,
      "subscribedOnDuration": "4 months",
      "listsStates": [
        {
          "id": "fans",
          "type": "fans",
          "name": "Fans",
          "hasUser": true,
          "canAddUser": false,
          "cannotAddUserReason": "ALREADY_EXISTS"
        },
        {
          "id": "following",
          "type": "following",
          "name": "Following",
          "hasUser": true,
          "canAddUser": false,
          "cannotAddUserReason": "ALREADY_EXISTS"
        },
        {
          "id": "recent",
          "type": "recent",
          "name": "Recent (last 24 hours)",
          "hasUser": false,
          "canAddUser": false,
          "cannotAddUserReason": "SYSTEM_LIST"
        },
        {
          "id": "muted",
          "type": "muted",
          "name": "Muted",
          "hasUser": false,
          "canAddUser": true,
          "cannotAddUserReason": null
        },
        {
          "id": "tagged",
          "type": "tagged",
          "name": "Tagged",
          "hasUser": false,
          "canAddUser": false,
          "cannotAddUserReason": "SYSTEM_LIST"
        },
        {
          "id": "friends",
          "type": "friends",
          "name": "Friends",
          "hasUser": false,
          "canAddUser": false,
          "cannotAddUserReason": "USER_NOT_PERFORMER"
        }
      ],
      "showMediaCount": true,
      "lastSeen": "2025-05-16T00:26:49+00:00",
      "canReport": true
    },
    "isFromQueue": false,
    "id": 123,
    "isOpened": false,
    "isNew": true,
    "createdAt": "2025-05-16T00:27:25+00:00",
    "changedAt": "2025-05-16T00:27:25+00:00",
    "cancelSeconds": 120,
    "isLiked": false,
    "canPurchase": false,
    "canPurchaseReason": "free",
    "canReport": true,
    "canBePinned": true,
    "isPinned": false,
    "replyToMessage": {
      "responseType": "message",
      "text": "<p>Text</p>",
      "giphyId": null,
      "lockedText": false,
      "isFree": true,
      "price": 0,
      "isMediaReady": true,
      "mediaCount": 0,
      "media": [],
      "previews": [],
      "isTip": false,
      "isReportedByMe": false,
      "isCouplePeopleMedia": false,
      "queueId": 123,
      "isMarkdownDisabled": true,
      "releaseForms": [],
      "fromUser": {
        "view": "s",
        "avatar": "https://example.com",
        "avatarThumbs": {
          "c50": "https://example.com",
          "c144": "https://example.com"
        },
        "header": "https://example.com",
        "headerSize": {
          "width": 4800,
          "height": 1440
        },
        "headerThumbs": {
          "w480": "https://example.com",
          "w760": "https://example.com"
        },
        "id": 123,
        "name": "Name",
        "username": "username",
        "canLookStory": true,
        "canCommentStory": true,
        "hasNotViewedStory": false,
        "isVerified": true,
        "canPayInternal": true,
        "hasScheduledStream": false,
        "hasStream": false,
        "hasStories": true,
        "tipsEnabled": true,
        "tipsTextEnabled": true,
        "tipsMin": 5,
        "tipsMinInternal": 1,
        "tipsMax": 200,
        "canEarn": true,
        "canAddSubscriber": false,
        "subscribePrice": 0,
        "hasStripe": false,
        "isStripeExist": false,
        "subscriptionBundles": [],
        "canSendChatToAll": true,
        "creditsMin": 10,
        "creditsMax": 200,
        "isPaywallPassed": true,
        "creditsMinAlternatives": 5,
        "canCreateLists": true,
        "showMediaCount": true,
        "lastSeen": "2025-05-16T00:24:06+00:00",
        "canReport": false,
        "subscribedOn": null
      },
      "isFromQueue": true,
      "canUnsendQueue": true,
      "unsendSecondsQueue": 1000000,
      "id": 123,
      "isOpened": false,
      "isNew": false,
      "createdAt": "2025-05-15T22:53:57+00:00",
      "changedAt": "2025-05-15T22:53:57+00:00",
      "cancelSeconds": 80792,
      "isLiked": false,
      "canPurchase": false,
      "canPurchaseReason": "free",
      "canReport": false,
      "canBePinned": true,
      "isPinned": false
    }
  }
}
```

### `messages.sent`

A new message has been sent from one of your OnlyFans accounts to a fan.

```json title="Example payload"
{
  "event": "messages.sent",
  "account_id": "acct_123",
  "payload": {
    "responseType": "message",
    "text": "<p>Text</p>",
    "giphyId": null,
    "lockedText": false,
    "isFree": true,
    "price": 0,
    "isMediaReady": true,
    "mediaCount": 1,
    "media": [
      {
        "id": 123,
        "type": "photo",
        "convertedToVideo": false,
        "canView": true,
        "hasError": false,
        "createdAt": "2025-04-05T06:19:31+00:00",
        "isReady": true,
        "files": {
          "full": {
            "url": "https://example.com",
            "width": 3840,
            "height": 5215,
            "size": 0,
            "sources": []
          },
          "thumb": {
            "url": "https://example.com",
            "width": 300,
            "height": 300,
            "size": 0
          },
          "preview": {
            "url": "https://example.com",
            "width": 960,
            "height": 1304,
            "size": 0
          },
          "squarePreview": {
            "url": "https://example.com",
            "width": 960,
            "height": 960,
            "size": 0
          }
        },
        "duration": 0,
        "releaseForms": [],
        "hasCustomPreview": false,
        "videoSources": {
          "240": null,
          "720": null
        }
      }
    ],
    "previews": [],
    "isTip": false,
    "isReportedByMe": false,
    "isCouplePeopleMedia": false,
    "queueId": 123,
    "isMarkdownDisabled": true,
    "releaseForms": [],
    "isFromQueue": false,
    "id": 123,
    "isOpened": false,
    "isNew": true,
    "createdAt": "2025-05-15T23:37:24+00:00",
    "changedAt": "2025-05-15T23:37:24+00:00",
    "cancelSeconds": 86400,
    "isLiked": false,
    "canPurchase": false,
    "canPurchaseReason": "free",
    "canReport": false,
    "canBePinned": true,
    "isPinned": false,
    "toUser": {
      "view": "s",
      "avatar": null,
      "avatarThumbs": null,
      "header": null,
      "headerSize": null,
      "headerThumbs": null,
      "id": 123,
      "name": "Name",
      "username": "username",
      "canLookStory": false,
      "canCommentStory": false,
      "hasNotViewedStory": false,
      "isVerified": false,
      "canPayInternal": true,
      "hasScheduledStream": false,
      "hasStream": false,
      "hasStories": false,
      "tipsEnabled": false,
      "tipsTextEnabled": true,
      "tipsMin": 5,
      "tipsMinInternal": 1,
      "tipsMax": 200,
      "canEarn": false,
      "canAddSubscriber": true,
      "subscribePrice": 0,
      "displayName": "",
      "notice": "",
      "isRestricted": false,
      "canRestrict": true,
      "subscribedBy": false,
      "subscribedByExpire": null,
      "subscribedByExpireDate": null,
      "subscribedByAutoprolong": null,
      "subscribedIsExpiredNow": null,
      "currentSubscribePrice": null,
      "subscribedOn": true,
      "subscribedOnExpiredNow": false,
      "subscribedOnDuration": "",
      "listsStates": [
        {
          "id": "fans",
          "type": "fans",
          "name": "Fans",
          "hasUser": true,
          "canAddUser": false,
          "cannotAddUserReason": "ALREADY_EXISTS"
        },
        {
          "id": "following",
          "type": "following",
          "name": "Following",
          "hasUser": false,
          "canAddUser": false,
          "cannotAddUserReason": "SYSTEM_LIST"
        },
        {
          "id": "recent",
          "type": "recent",
          "name": "Recent (last 24 hours)",
          "hasUser": true,
          "canAddUser": false,
          "cannotAddUserReason": "ALREADY_EXISTS"
        },
        {
          "id": "muted",
          "type": "muted",
          "name": "Muted",
          "hasUser": false,
          "canAddUser": true,
          "cannotAddUserReason": null
        },
        {
          "id": "tagged",
          "type": "tagged",
          "name": "Tagged",
          "hasUser": false,
          "canAddUser": false,
          "cannotAddUserReason": "SYSTEM_LIST"
        },
        {
          "id": "friends",
          "type": "friends",
          "name": "Friends",
          "hasUser": false,
          "canAddUser": false,
          "cannotAddUserReason": "USER_NOT_PERFORMER"
        }
      ],
      "showMediaCount": true,
      "lastSeen": "2025-05-15T23:37:03+00:00",
      "canReport": false
    }
  }
}
```

### `messages.ppv.unlocked`

A PPV message that you sent has been purchased by a fan.

```json title="Example payload"
{
  "event": "messages.ppv.unlocked",
  "account_id": "acct_123",
  "payload": {
    "id": "123",
    "type": "paided_message",
    "createdAt": "2025-05-05T22:18:00+00:00",
    "text": "has purchased your <a href='https://onlyfans.com/my/chats/chat/123?firstId=123'>message</a> for $5.00!",
    "replacePairs": {
      "{NAME}": "Name",
      "{MESSAGE_LINK}": "<a href='https://onlyfans.com/my/chats/chat/123?firstId=123'>message</a>",
      "{AMOUNT}": "$5.00"
    },
    "subType": "subscriber_pay_for_chat_message",
    "user_id": "123",
    "isRead": false,
    "canGoToProfile": true,
    "fanData": {
      "available": true,
      "last_updated_at": "2026-01-02 17:12:00",
      "spending": {
        "total": 6.6,
        "messages": 4,
        "subscribes": 2.6,
        "posts": 0,
        "tips": 4,
        "streams": 0
      }
    },
    "user": {
      "avatar": null,
      "avatarThumbs": null,
      "header": null,
      "headerSize": null,
      "headerThumbs": null,
      "id": 123,
      "name": "Name",
      "username": "username",
      "canLookStory": false,
      "canCommentStory": false,
      "hasNotViewedStory": false,
      "isVerified": false,
      "canPayInternal": false,
      "hasScheduledStream": false,
      "hasStream": false,
      "hasStories": false,
      "tipsEnabled": false,
      "tipsTextEnabled": true,
      "tipsMin": 5,
      "tipsMinInternal": 1,
      "tipsMax": 200,
      "canEarn": false,
      "canAddSubscriber": false,
      "subscribePrice": 0,
      "subscribedBy": false,
      "subscribedOn": false,
      "canReceiveChatMessage": false,
      "hideChat": false,
      "lastSeen": "2025-05-05T22:17:29+00:00",
      "isPerformer": false,
      "isRealPerformer": false,
      "view": "mn",
      "canReport": true,
      "subscribedByData": null,
      "subscribedOnData": null,
      "isBlocked": false
    }
  }
}
```

### `messages.deleted`

A chat message was deleted.

```json title="Example payload"
{
    "event": "messages.deleted",
    "account_id": "acct_123",
    "payload": {
        "id": "123"
    }
}
```

## Chat Queue

### `chat_queue.updated`

A queued message batch has been updated (e.g. progress change).

```json title="Example payload"
{
    "event": "chat_queue.updated",
    "account_id": "acct_123",
    "payload": {
        "id": 123,
        "date": "2025-01-01T00:00:00+00:00",
        "canUnsend": true,
        "hasError": false,
        "isCanceled": false,
        "isCouplePeopleMedia": false,
        "isDone": false,
        "isReady": true,
        "pending": 6,
        "total": 7,
        "unsendSeconds": 1000000
    }
}
```

### `chat_queue.finished`

A queued message batch has finished sending.

```json title="Example payload"
{
    "event": "chat_queue.finished",
    "account_id": "acct_123",
    "payload": {
        "id": 123,
        "date": "2025-01-01T00:00:00+00:00",
        "canUnsend": false,
        "hasError": false,
        "isCanceled": true,
        "isCouplePeopleMedia": false,
        "isDone": true,
        "isReady": true,
        "pending": 0,
        "total": 7,
        "unsendSeconds": 0
    }
}
```

## Tips

### `tips.received`

A new tip has been received from a fan.

```json title="Example payload"
{
    "event": "tips.received",
    "account_id": "acct_123",
    "payload": {
        "amountGross": 5,
        "amountNet": 4,
        "fanData": {
            "available": true,
            "last_updated_at": "2026-01-02 17:12:00",
            "spending": {
                "total": 6.6,
                "messages": 0,
                "subscribes": 2.6,
                "posts": 0,
                "tips": 4,
                "streams": 0
            }
        },
        "id": "123123123123",
        "type": "tip",
        "createdAt": "2026-01-02T17:12:00+00:00",
        "text": "paid you a tip of $5.00",
        "replacePairs": {
            "{SUBSCRIBER_LINK}": "<a href='https:\/\/onlyfans.com\/xxxxxxxx'>John Doe<\/a>",
            "{AMOUNT}": "$5.00",
            "{POST_BLOCK}": "",
            "{POST_DATA}": ""
        },
        "subType": "new_tips",
        "user_id": "9999999999",
        "isRead": false,
        "canGoToProfile": true,
        "user": {
            "avatar": "https:\/\/public.onlyfans.com\/files\/u\/uf\/ufs\/ufsXXXXXXXXXXXXX\/111111111\/avatar.jpg",
            "avatarThumbs": {
                "c50": "https:\/\/thumbs.onlyfans.com\/public\/files\/thumbs\/c50\/u\/uf\/ufs\/ufsXXXXXXXXXXXXX\/111111111\/avatar.jpg",
                "c144": "https:\/\/thumbs.onlyfans.com\/public\/files\/thumbs\/c144\/u\/uf\/ufs\/ufsXXXXXXXXXXXXX\/111111111\/avatar.jpg"
            },
            "header": "https:\/\/public.onlyfans.com\/files\/g\/g2\/g2e\/g2eXXXXXXXXXXXXXXX\/111111111\/header_image.jpg",
            "headerSize": {
                "width": 3362,
                "height": 1780
            },
            "headerThumbs": {
                "w480": "https:\/\/thumbs.onlyfans.com\/public\/files\/thumbs\/w480\/g\/g2\/g2e\/g2eXXXXXXXXXXXXXXX\/111111111\/header_image.jpg",
                "w760": "https:\/\/thumbs.onlyfans.com\/public\/files\/thumbs\/w760\/g\/g2\/g2e\/g2eXXXXXXXXXXXXXXX\/111111111\/header_image.jpg"
            },
            "id": 111111111,
            "name": "John Doe",
            "username": "johndoe",
            "canLookStory": false,
            "canCommentStory": false,
            "hasNotViewedStory": false,
            "isVerified": false,
            "canPayInternal": false,
            "hasScheduledStream": false,
            "hasStream": false,
            "hasStories": false,
            "tipsEnabled": false,
            "tipsTextEnabled": true,
            "tipsMin": 5,
            "tipsMinInternal": 1,
            "tipsMax": 200,
            "canEarn": false,
            "canAddSubscriber": false,
            "subscribePrice": 0,
            "subscribedBy": false,
            "subscribedOn": false,
            "canReceiveChatMessage": false,
            "hideChat": false,
            "lastSeen": "2026-01-02T17:09:46+00:00",
            "isPerformer": false,
            "isRealPerformer": false,
            "view": "mn",
            "canReport": true,
            "subscribedByData": null,
            "subscribedOnData": null,
            "isBlocked": false
        }
    }
}
```

## Subscriptions

### `subscriptions.new`

A new fan has subscribed.

```json title="Example payload"
{
  "event": "subscriptions.new",
  "account_id": "acct_123",
  "payload": {
    "id": "123",
    "type": "subscribed",
    "createdAt": "2025-05-05T21:27:00+00:00",
    "text": "subscribed to your profile!",
    "replacePairs": {
      "{SUBSCRIBER_LINK}": "<a href='https://onlyfans.com/username'>Name</a>",
      "{PRICE}": "free"
    },
    "subType": "new_subscriber",
    "user_id": "123",
    "isRead": false,
    "canGoToProfile": true,
    "fanData": {
      "available": true,
      "last_updated_at": "2026-01-02 17:12:00",
      "spending": {
        "total": 6.6,
        "messages": 0,
        "subscribes": 2.6,
        "posts": 0,
        "tips": 4,
        "streams": 0
      }
    },
    "user": {
      "avatar": "https://example.com",
      "avatarThumbs": {
        "c50": "https://example.com",
        "c144": "https://example.com"
      },
      "header": "https://example.com",
      "headerSize": {
        "width": 767,
        "height": 1152
      },
      "headerThumbs": {
        "w480": "https://example.com",
        "w760": "https://example.com"
      },
      "id": 123,
      "name": "Name",
      "username": "username",
      "canLookStory": false,
      "canCommentStory": false,
      "hasNotViewedStory": false,
      "isVerified": true,
      "canPayInternal": false,
      "hasScheduledStream": false,
      "hasStream": false,
      "hasStories": false,
      "tipsEnabled": true,
      "tipsTextEnabled": true,
      "tipsMin": 5,
      "tipsMinInternal": 1,
      "tipsMax": 200,
      "canEarn": true,
      "canAddSubscriber": false,
      "subscribePrice": 0,
      "subscribedBy": false,
      "subscribedOn": false,
      "canReceiveChatMessage": false,
      "hideChat": false,
      "lastSeen": "2025-05-05T21:26:04+00:00",
      "isPerformer": true,
      "isRealPerformer": true,
      "view": "mn",
      "canReport": true,
      "subscribedByData": null,
      "subscribedOnData": null,
      "isBlocked": false
    }
  }
}
```

### `subscriptions.renewed`

A fan has renewed their subscription.

```json title="Example data"
{
  "event": "subscriptions.renewed",
  "account_id": "acct_123",
  "payload": {
    "id": "123",
    "type": "subscribed",
    "createdAt": "2025-05-05T21:27:00+00:00",
    "text": "Good news! <a href='https://onlyfans.com/u34547118'>u34547118</a> has Just restarted their monthly subscription to your OnlyFans profile!",
    "replacePairs": {
      "{SUBSCRIBER_LINK}": "<a href='https://onlyfans.com/u34547118'>u34547118</a>",
      "{PRICE}": "$4.00"
    },
    "subType": "returning_subscriber",
    "user_id": "34547118",
    "isRead": false,
    "canGoToProfile": true,
    "fanData": {
      "available": true,
      "last_updated_at": "2026-01-02 17:12:00",
      "spending": {
        "total": 6.6,
        "messages": 0,
        "subscribes": 2.6,
        "posts": 0,
        "tips": 4,
        "streams": 0
      }
    },
    "user": {
      "avatar": "https://example.com",
      "avatarThumbs": {
        "c50": "https://example.com",
        "c144": "https://example.com"
      },
      "header": "https://example.com",
      "headerSize": {
        "width": 767,
        "height": 1152
      },
      "headerThumbs": {
        "w480": "https://example.com",
        "w760": "https://example.com"
      },
      "id": 34547118,
      "name": "Name",
      "username": "username",
      "canLookStory": false,
      "canCommentStory": false,
      "hasNotViewedStory": false,
      "isVerified": true,
      "canPayInternal": false,
      "hasScheduledStream": false,
      "hasStream": false,
      "hasStories": false,
      "tipsEnabled": true,
      "tipsTextEnabled": true,
      "tipsMin": 5,
      "tipsMinInternal": 1,
      "tipsMax": 200,
      "canEarn": true,
      "canAddSubscriber": false,
      "subscribePrice": 0,
      "subscribedBy": false,
      "subscribedOn": false,
      "canReceiveChatMessage": false,
      "hideChat": false,
      "lastSeen": "2025-05-05T21:26:04+00:00",
      "isPerformer": true,
      "isRealPerformer": true,
      "view": "mn",
      "canReport": true,
      "subscribedByData": null,
      "subscribedOnData": null,
      "isBlocked": false
    }
  }
}
```

### `subscriptions.expired`

A fan's subscription has expired.

Unlike `subscriptions.new` and `subscriptions.renewed`, this event is **derived**. OnlyFans
emits no expiry signal, so we track the subscription end date it reports for each of your
subscribers, notice when one passes, and confirm the lapse against OnlyFans before delivering
it. Expect delivery within about 15 minutes of the subscription lapsing.

Four things worth planning for:

* Subscriptions that had already lapsed before you enabled this event are **not** backfilled —
  you only receive lapses that happen from the moment you subscribe onwards. If another webhook
  on your team already watched that creator, you may receive lapses from shortly before you
  subscribed. The same bound applies after any interruption on our side: we resume from the last
  48 hours rather than replaying further back.
* Use `expiredAt` rather than the delivery time to decide when a subscription actually ended.
  It is the value OnlyFans reports, and it is fixed at the moment we detect the lapse, so it
  stays correct even if the fan resubscribes before the webhook reaches you.
* A fan who renews instead of lapsing produces no event. We check with OnlyFans immediately
  before sending, so a renewal that lands first is never reported as a lapse. If they later
  lapse for real, the event fires then.
* Coverage follows the subscribers we hold a current end date for. Every subscription that can
  later lapse was first created or renewed, and both carry that date, so in practice this is
  your whole active base. A subscription we have never observed — one that started before the
  account was connected and has not renewed since — can be missed.

```json title="Example payload"
{
  "event": "subscriptions.expired",
  "account_id": "acct_123",
  "payload": {
    "id": "34547118:2025-05-05T21:27:00+00:00",
    "type": "subscription_expired",
    "subType": "expired_subscriber",
    "createdAt": "2025-05-05T21:34:12+00:00",
    "expiredAt": "2025-05-05T21:27:00+00:00",
    "user_id": "34547118",
    "user": {
      "avatar": "https://example.com",
      "avatarThumbs": {
        "c50": "https://example.com",
        "c144": "https://example.com"
      },
      "header": "https://example.com",
      "headerSize": {
        "width": 767,
        "height": 1152
      },
      "headerThumbs": {
        "w480": "https://example.com",
        "w760": "https://example.com"
      },
      "id": 34547118,
      "name": "Name",
      "username": "username",
      "canLookStory": false,
      "canCommentStory": false,
      "hasNotViewedStory": false,
      "isVerified": true,
      "canPayInternal": false,
      "hasScheduledStream": false,
      "hasStream": false,
      "hasStories": false,
      "tipsEnabled": true,
      "tipsTextEnabled": true,
      "tipsMin": 5,
      "tipsMinInternal": 1,
      "tipsMax": 200,
      "canEarn": true,
      "canAddSubscriber": false,
      "subscribePrice": 12.99,
      "subscribedBy": false,
      "subscribedOn": false,
      "canReceiveChatMessage": false,
      "hideChat": false,
      "lastSeen": "2025-05-04T09:12:31+00:00",
      "isPerformer": true,
      "isRealPerformer": true,
      "view": "f",
      "canReport": true,
      "subscribedByData": null,
      "subscribedOnData": {
        "price": 12.99,
        "newPrice": 12.99,
        "regularPrice": 12.99,
        "subscribePrice": 12.99,
        "discountPercent": 0,
        "discountPeriod": 1,
        "subscribeAt": "2025-04-05T21:27:00+00:00",
        "expiredAt": "2025-05-05T21:27:00+00:00",
        "renewedAt": null,
        "discountFinishedAt": null,
        "discountStartedAt": null,
        "status": null,
        "isMuted": false,
        "unsubscribeReason": "Redacted",
        "duration": "1 month",
        "tipsSumm": 15,
        "subscribesSumm": 12.99,
        "messagesSumm": 40.5,
        "postsSumm": 0,
        "streamsSumm": 0,
        "totalSumm": 68.49,
        "subscribes": [],
        "hasActivePaidSubscriptions": false
      },
      "isBlocked": false
    },
    "fanData": {
      "available": true,
      "last_updated_at": "2025-05-05T21:34:11.000000Z",
      "spending": {
        "total": 68.49,
        "messages": 40.5,
        "subscribes": 12.99,
        "posts": 0,
        "tips": 15,
        "streams": 0
      },
      "previous_reply_at": "2025-04-29T14:02:55.000000Z"
    }
  }
}
```

## Posts

### `posts.liked`

A fan has liked one of your posts.

```json title="Example payload"
{
  "event": "posts.liked",
  "account_id": "acct_123",
  "payload": {
    "id": "123",
    "type": "favorited",
    "createdAt": "2025-05-05T22:22:00+00:00",
    "text": "liked your <a href='https://onlyfans.com/123/username'>post</a>",
    "replacePairs": {
      "{POST_LINK}": "<a href='https://onlyfans.com/123/username'>post</a>"
    },
    "subType": "new_favorite",
    "user_id": "123",
    "isRead": false,
    "canGoToProfile": true,
    "user": {
      "avatar": null,
      "avatarThumbs": null,
      "header": null,
      "headerSize": null,
      "headerThumbs": null,
      "id": 123,
      "name": "Name",
      "username": "username",
      "canLookStory": false,
      "canCommentStory": false,
      "hasNotViewedStory": false,
      "isVerified": false,
      "canPayInternal": false,
      "hasScheduledStream": false,
      "hasStream": false,
      "hasStories": false,
      "tipsEnabled": false,
      "tipsTextEnabled": true,
      "tipsMin": 5,
      "tipsMinInternal": 1,
      "tipsMax": 200,
      "canEarn": false,
      "canAddSubscriber": false,
      "subscribePrice": 0,
      "subscribedBy": false,
      "subscribedOn": false,
      "canReceiveChatMessage": false,
      "hideChat": false,
      "lastSeen": null,
      "isPerformer": false,
      "isRealPerformer": false,
      "view": "mn",
      "canReport": true,
      "subscribedByData": null,
      "subscribedOnData": null,
      "isBlocked": false
    }
  }
}
```

## Users

### `users.typing`

A fan is typing a message.

```json title="Example payload"
{
  "event": "users.typing",
  "account_id": "acct_123",
  "payload": {
    "id": 1910197
  }
}
```

### `users.online`

A fan was detected as online.

```json title="Example payload"
{
  "event": "users.online",
  "account_id": "acct_123",
  "payload": {
    "fan": {
      "id": "123",
      "username": "johndoe",
      "name": "John Doe",
      "display_name": "John Doe",
      "spending": {
        "messages": 10,
        "subscribes": 2.6,
        "posts": 0,
        "tips": 4,
        "streams": 0,
        "total": 16.6
      }
    },
    "observed_at": "2026-01-02T17:12:00.000000Z",
    "status_changed_at": "2026-01-02T17:12:00.000000Z",
    "last_seen_online_at": "2026-01-02T17:12:00.000000Z"
  }
}
```

### `users.offline`

A fan that was previously detected as online was detected as offline.

```json title="Example payload"
{
  "event": "users.offline",
  "account_id": "acct_123",
  "payload": {
    "fan": {
      "id": "123",
      "username": "johndoe",
      "name": "John Doe",
      "display_name": "John Doe",
      "spending": {
        "messages": 10,
        "subscribes": 2.6,
        "posts": 0,
        "tips": 4,
        "streams": 0,
        "total": 16.6
      }
    },
    "observed_at": "2026-01-02T17:42:00.000000Z",
    "status_changed_at": "2026-01-02T17:42:00.000000Z",
    "last_seen_online_at": "2026-01-02T17:12:00.000000Z"
  }
}
```

These events are detected by periodic online-status polling, so delivery is not instant. `users.online` is emitted when a tracked fan transitions from unknown/offline to online. `users.offline` is emitted when a fan that was previously detected online is no longer present in a successful online-status check.

## Data Exports

<Callout type="info">
  Data export webhook events are team-level events and do not include an `account_id` at the top level. Instead, the `account_ids` array is included in the payload.
</Callout>

### `data_exports.calculating_credits`

Credit calculation has started for a data export.

```json title="Example payload"
{
  "event": "data_exports.calculating_credits",
  "payload": {
    "id": "data_export_abc123",
    "type": "transactions",
    "status": "calculating_credits",
    "file_type": "csv",
    "credit_cost": null,
    "start_date": "2025-01-01T00:00:00+00:00",
    "end_date": "2025-01-31T23:59:59+00:00",
    "account_ids": ["acct_123", "acct_456"],
    "created_at": "2025-05-13T20:26:56+00:00"
  }
}
```

### `data_exports.calculating_credits_completed`

Credit calculation has completed successfully for a data export.

```json title="Example payload"
{
  "event": "data_exports.calculating_credits_completed",
  "payload": {
    "id": "data_export_abc123",
    "type": "transactions",
    "status": "calculating_credits_completed",
    "file_type": "csv",
    "credit_cost": 150,
    "start_date": "2025-01-01T00:00:00+00:00",
    "end_date": "2025-01-31T23:59:59+00:00",
    "account_ids": ["acct_123", "acct_456"],
    "created_at": "2025-05-13T20:26:56+00:00"
  }
}
```

### `data_exports.calculating_credits_failed`

Credit calculation has failed for a data export.

```json title="Example payload"
{
  "event": "data_exports.calculating_credits_failed",
  "payload": {
    "id": "data_export_abc123",
    "type": "transactions",
    "status": "calculating_credits_failed",
    "file_type": "csv",
    "credit_cost": null,
    "start_date": "2025-01-01T00:00:00+00:00",
    "end_date": "2025-01-31T23:59:59+00:00",
    "account_ids": ["acct_123", "acct_456"],
    "created_at": "2025-05-13T20:26:56+00:00"
  }
}
```

### `data_exports.in_progress`

A data export is now in progress.

```json title="Example payload"
{
  "event": "data_exports.in_progress",
  "payload": {
    "id": "data_export_abc123",
    "type": "transactions",
    "status": "in_progress",
    "file_type": "csv",
    "credit_cost": 150,
    "start_date": "2025-01-01T00:00:00+00:00",
    "end_date": "2025-01-31T23:59:59+00:00",
    "account_ids": ["acct_123", "acct_456"],
    "created_at": "2025-05-13T20:26:56+00:00"
  }
}
```

### `data_exports.completed`

A data export has completed successfully. The payload includes a temporary download URL that expires after 1 hour.

```json title="Example payload"
{
  "event": "data_exports.completed",
  "payload": {
    "id": "data_export_abc123",
    "type": "transactions",
    "status": "completed",
    "file_type": "csv",
    "credit_cost": 150,
    "start_date": "2025-01-01T00:00:00+00:00",
    "end_date": "2025-01-31T23:59:59+00:00",
    "account_ids": ["acct_123", "acct_456"],
    "created_at": "2025-05-13T20:26:56+00:00",
    "download_url": "https://example-bucket.s3.amazonaws.com/data-exports/team-slug/data_export_abc123xyz789.csv?X-Amz-Signature=...",
    "download_url_expires_at": "2025-05-13T21:26:56+00:00"
  }
}
```

### `data_exports.failed`

A data export has failed. The `failed_reason` field is only included when the failure was due to insufficient credits.

```json title="Example payload"
{
  "event": "data_exports.failed",
  "payload": {
    "id": "data_export_abc123",
    "type": "transactions",
    "status": "failed",
    "file_type": "csv",
    "credit_cost": 150,
    "start_date": "2025-01-01T00:00:00+00:00",
    "end_date": "2025-01-31T23:59:59+00:00",
    "account_ids": ["acct_123", "acct_456"],
    "created_at": "2025-05-13T20:26:56+00:00",
    "failed_reason": "Insufficient credits: 150 required"
  }
}
```

### `data_exports.cancelled`

A data export was cancelled.

```json title="Example payload"
{
  "event": "data_exports.cancelled",
  "payload": {
    "id": "data_export_abc123",
    "type": "transactions",
    "status": "cancelled",
    "file_type": "csv",
    "credit_cost": 150,
    "start_date": "2025-01-01T00:00:00+00:00",
    "end_date": "2025-01-31T23:59:59+00:00",
    "account_ids": ["acct_123", "acct_456"],
    "created_at": "2025-05-13T20:26:56+00:00"
  }
}
```

## Fan Summary

### `fan_summary.completed`

An AI Fan Profile Summary has finished generating. This event fires for both new summaries and regenerations, and is dispatched after the summary completes successfully.

```json title="Example payload"
{
  "event": "fan_summary.completed",
  "data": {
    "fan": {
      "onlyfans_id": 123456789,
      "username": "example_fan"
    },
    "summary": {
      "status": "completed",
      "summary_data": {
        "name": "Jane Doe",
        "preferred_name": "Jane",
        "family_pets": "Has a golden retriever named Max",
        "travel_plans": "Planning a trip to Bali",
        "kinks": "",
        "hobbies": "Yoga, photography",
        "content_preferences": "Behind the scenes content",
        "themes": "",
        "requests": "",
        "interests": "Fitness, travel",
        "other_notes": ""
      },
      "analyzed_message_count": 504,
      "last_analyzed_at": "2026-03-19T12:00:00+00:00"
    }
  }
}
```

## Media Uploads

<Callout type="info">
  These events only fire for **asynchronous** uploads (`async=true`). A synchronous upload returns its result in the response body, so there is nothing left to notify you about.
</Callout>

### `media_uploads.completed`

An async media upload finished successfully. Fires for both [Upload Media to OnlyFans CDN](/api-reference/media/upload-media-to-the-only-fans-cdn) and [Upload Media to Vault](/api-reference/media-vault/upload-media-to-vault).

The payload carries the same fields as [Get Upload Status](/api-reference/media/get-upload-status), so you can subscribe to this event instead of polling the `polling_url` you got back from the `202` response.

```json title="Example payload (vault upload)"
{
  "event": "media_uploads.completed",
  "account_id": "acct_123",
  "payload": {
    "id": "ofapi_media_abc123def456abc123def456abc123de",
    "prefixed_id": "ofapi_media_abc123def456abc123def456abc123de",
    "account_id": "acct_123",
    "status": "completed",
    "file_name": "photo.jpg",
    "created_at": "2026-04-03T16:17:58+00:00",
    "media_id": 1234567890,
    "media": {
      "id": 1234567890,
      "type": "photo",
      "convertedToVideo": false,
      "canView": true,
      "hasError": false,
      "createdAt": "2026-04-03T16:18:05+00:00",
      "isReady": false,
      "files": {
        "full": { "url": null, "width": 0, "height": 0, "size": 0, "sources": [] },
        "thumb": null,
        "preview": null,
        "squarePreview": null
      },
      "duration": 0,
      "releaseForms": [],
      "hasCustomPreview": false
    },
    "credits_used": 3,
    "completed_at": "2026-04-03T16:18:05+00:00"
  }
}
```

Vault uploads carry the OnlyFans media ID in `media_id`. CDN uploads do not have one yet — they are referenced by `prefixed_id` (or `media.processId`) until you attach them to a post or message — so `media_id` is `null` there:

```json title="Example payload (CDN upload)"
{
  "event": "media_uploads.completed",
  "account_id": "acct_123",
  "payload": {
    "id": "ofapi_media_abc123def456abc123def456abc123de",
    "prefixed_id": "ofapi_media_abc123def456abc123def456abc123de",
    "account_id": "acct_123",
    "status": "completed",
    "file_name": "photo.jpg",
    "created_at": "2026-04-03T16:17:58+00:00",
    "media_id": null,
    "media": {
      "prefixed_id": "ofapi_media_abc123def456abc123def456abc123de",
      "file_name": "photo.jpg",
      "processId": "abc123def456abc123de",
      "host": "convert3.onlyfans.com",
      "sourceUrl": "https://of2transcoder.s3.amazonaws.com/upload/00000000-0000-0000-0000-000000000000/000000000000/photo.jpg",
      "extra": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx...",
      "additional": { "user": "123456789" },
      "thumbs": [
        {
          "id": 1,
          "url": "https://cdn2.onlyfans.com/files/0/00/00000000000000000000000000000000/300x544_00000000000000000000000000000000.jpg"
        }
      ]
    },
    "credits_used": 3,
    "completed_at": "2026-04-03T16:18:05+00:00"
  }
}
```

<Callout type="warn">
  The `prefixed_id` can only be used **once**. After you include it in a post or message it is no longer valid, and you must upload the file again to get a new one.
</Callout>

### `media_uploads.failed`

An async media upload failed. The `error` field carries the reason, and no credits are charged for the upload itself.

```json title="Example payload"
{
  "event": "media_uploads.failed",
  "account_id": "acct_123",
  "payload": {
    "id": "ofapi_media_abc123def456abc123def456abc123de",
    "prefixed_id": "ofapi_media_abc123def456abc123def456abc123de",
    "account_id": "acct_123",
    "status": "failed",
    "file_name": "photo.jpg",
    "created_at": "2026-04-03T16:17:58+00:00",
    "error": "Failed to download file from the provided URL.",
    "failed_at": "2026-04-03T16:18:05+00:00"
  }
}
```

Common `error` values include a failed download from your `file_url`, a file larger than your subscription's upload limit, not enough credits to cover the upload, and `Async upload staging expired before processing completed. Please retry.` for an upload that sat unprocessed for more than 24 hours.