# Build an OnlyFans AI Chatbot with the API: Webhook, LLM, Send Message

> Learn to build an OnlyFans AI chatbot by connecting the messages.received webhook to an LLM and the OnlyFansAPI for scalable, event-driven automated responses.

**TL;DR**

- Listen for the `messages.received` webhook (Basic plan and up) to trigger an automated reply whenever a fan sends a message.
- Return a 200 OK HTTP status immediately to prevent webhook timeouts, then process the LLM request in a background job queue.
- Subscribe to `users.typing` events and add a 5 to 10 second debounce delay to prevent interrupting fans before they finish typing.
- Attach a unique `Idempotency-Key` header when sending the final message to prevent duplicate deliveries during network retries.
- Send paywalled messages by setting the `price` between 3 and 200 and including `mediaFiles` unless `lockedText` is true.

Building an AI chatbot for OnlyFans requires setting up a webhook (Basic plan and up) to receive fan messages in near real-time, routing the text to a Large Language Model (LLM) for processing, and dispatching the generated reply via a REST API. Developers connect this automated pipeline by subscribing to the `messages.received` webhook and sending responses back through the `POST /api/{account}/chats/{chat_id}/messages` endpoint using [OnlyFansAPI](https://www.fansapi.com).

**Key Takeaways**

- Listen for the `messages.received` webhook (Basic plan and up) to trigger an automated reply whenever a fan sends a message.
- Return a 200 OK HTTP status immediately to prevent webhook timeouts, then process the LLM request in a background job queue.
- Subscribe to `users.typing` events and add a 5 to 10 second debounce delay to prevent interrupting fans before they finish typing.
- Attach a unique `Idempotency-Key` header when sending the final message to prevent duplicate deliveries during network retries.
- Send paywalled messages by setting the `price` between 3 and 200 and including `mediaFiles` unless `lockedText` is true.

## How to build an AI chatbot for OnlyFans

To build an AI chatbot for OnlyFans, developers must connect an inbound `messages.received` webhook to a background queue, generate a context-aware response using an LLM, and send the reply via the `POST /api/{account}/chats/{chat_id}/messages` API endpoint. This event-driven architecture handles inbound traffic in near real-time and gives the LLM enough time to generate a contextual response. Our docs walk through the same pipeline in the [AI chatbot guide](https://docs.fansapi.com/onlyfans-ai/build-ai-chatbot-for-onlyfans). For every event you can subscribe to, see the [OnlyFans webhooks guide](/blog/onlyfans-webhooks-guide).

[OnlyFansAPI pricing](https://www.fansapi.com/pricing) tiers starting at Basic ($69/month) provide the production-ready infrastructure to power this pipeline. The Basic plan includes access to 320+ endpoints, webhooks, and one dedicated mobile IP proxy per connected account in the US or UK. OnlyFansAPI maintains 99.98% uptime, has handled 300M+ requests, is used by 1,100+ companies, and has zero account bans in 5+ years.

### How do webhooks capture messages in near real-time?

Webhooks push data to your server in near real-time after a fan takes action. Open the webhooks dashboard and subscribe your HTTPS endpoint to the `messages.received` event. This event carries the fan's message text and their identifier. The webhook client calculates a signature using the HMAC SHA256 algorithm with your signing secret as the key. Your endpoint must verify this signature and return a 200 OK status within the 10-second request timeout. Push the payload into a background queue before generating the AI response.

### Debouncing fan typing streams

Fans often send multiple short messages in a row. Replying instantly to the first message can interrupt their thought process. To solve this, subscribe to the `users.typing` webhook. When a `messages.received` event arrives, schedule the background AI job to wait 5 to 10 seconds. If another `users.typing` event fires for that chat, reset the timer. This debounce period groups short bursts of text into a single prompt for your LLM.

### Simulating typing indicators

Once the LLM begins generating a response, signal to the fan that a reply is incoming. Call the [Start Typing Indicator endpoint](https://docs.fansapi.com/api-reference/chats/start-typing-indicator) via `POST https://app.fansapi.com/api/{account}/chats/{chat_id}/typing`. The fan sees a "Model is typing..." note for about 4 seconds; call the endpoint again if your LLM is still working.

### Sending the AI chat message

When the LLM finishes drafting the reply, dispatch it back to the fan. Make a request to the [Send Message endpoint](https://docs.fansapi.com/api-reference/chat-messages/send-message) at `POST https://app.fansapi.com/api/{account}/chats/{chat_id}/messages`. Include your API key in the `Authorization: Bearer YOUR_API_KEY` header, and use your account ID, which starts with `acct_`.

If the message includes paywalled content, set the `price` between 3 and 200. Setting a non-zero price requires `mediaFiles` to lock the media behind a paywall, unless `lockedText` is true.

### Automating post-purchase follow-ups

When a fan purchases the paywalled content, the `messages.ppv.unlocked` webhook event fires. Extract the purchase amount and user ID from the payload, then prompt the LLM to send a natural thank-you message. This loop keeps fans engaged after a purchase.

## Node.js webhook and messaging implementation

This TypeScript code demonstrates how to verify webhook signatures, trigger a typing indicator, and send an AI-generated text response. Webhooks need the Basic plan and up. The code reads the `acct_` account ID from each event's `account_id` field.

```typescript
import express, { Request, Response } from 'express';
import crypto from 'crypto';

const app = express();
app.use(express.json({ verify: (req: any, _res, buf) => { req.rawBody = buf; } }));

const OFAPI_KEY = process.env.ONLYFANS_API_KEY!;
const SIGNING_SECRET = process.env.OFAPI_WEBHOOK_SECRET!;
const API_BASE = 'https://app.fansapi.com/api';

app.post('/api/webhooks/onlyfans', async (req: Request, res: Response) => {
  const signature = req.headers['signature'] as string;
  if (!signature) {
    return res.status(401).send('Invalid signature');
  }

  const hmac = crypto.createHmac('sha256', SIGNING_SECRET);
  const digest = hmac.update((req as any).rawBody).digest('hex');
  if (signature.length !== digest.length || !crypto.timingSafeEqual(Buffer.from(signature), Buffer.from(digest))) {
    return res.status(401).send('Invalid signature');
  }

  const { event, account_id, payload } = req.body;

  // Return 200 OK immediately to prevent timeouts
  res.status(200).json({ received: true });

  if (event === 'messages.received') {
    const { fromUser, text, id: messageId } = payload;

    try {
      // Start the typing indicator
      await fetch(`${API_BASE}/${account_id}/chats/${fromUser.id}/typing`, {
        method: 'POST',
        headers: {
          'Authorization': `Bearer ${OFAPI_KEY}`,
          'Content-Type': 'application/json',
        },
      });

      // Simulate LLM generation time
      await new Promise((resolve) => setTimeout(resolve, 3000));

      const aiReply = `Hey ${fromUser.name}, thanks for the message!`;

      // Dispatch the response
      await fetch(`${API_BASE}/${account_id}/chats/${fromUser.id}/messages`, {
        method: 'POST',
        headers: {
          'Authorization': `Bearer ${OFAPI_KEY}`,
          'Content-Type': 'application/json',
          'Idempotency-Key': `reply_${messageId}`,
        },
        body: JSON.stringify({ text: aiReply }),
      });
    } catch (error) {
      console.error('Error sending reply:', error);
    }
  }
});

app.listen(3000, () => console.log('Webhook server running'));
```

## What safeguards manage automated chat systems?

Automated chat systems require technical safeguards to prevent duplicate messages and manage high-value relationships. Always include an `Idempotency-Key` header on every `POST` request to send a message. This header prevents duplicate deliveries if a network timeout causes you to retry the same request.

For VIP fans with high lifetime spend, agencies route messages to a human review queue instead of sending the LLM output directly. You can read the fan's lifetime spend from the webhook payload (`fanData.spending.total`) or the List Chats endpoint (`GET /api/{account}/chats`, `subscribedOnData.totalSumm`) to decide when to stop automated replies and notify a human chatter.

## Agency automation alternatives

Agencies wanting AI operations without writing custom API code can deploy [FansBot](https://www.fansapi.com/fansbot) directly into Telegram, Slack, or Discord. FansBot is an AI employee for OnlyFans agencies. It does not impersonate creators, automate fan conversations, or send fan messages. Instead, it handles back-office tasks like daily earnings recaps, chatter shift QA audits, and payroll split preparation. FansBot connects to 3,000+ apps out of the box and offers $69 in free credits to start.

For a comparison of OnlyFans bot types, from fan-facing chatbots to AI coworkers like FansBot, see our guide on [OnlyFans AI bot tools](/blog/onlyfans-bot-ai-tools).

---

Note: Fans API is independent and not affiliated with or approved by OnlyFans. The tools described here act only on accounts you own or are authorised to manage. The OnlyFans Terms of Service (October 2026, §8(g)) restrict automated data collection and the use of platform content to train AI, and AI-generated content must be labelled #ai. You are responsible for how you use these tools. See our [Terms of Service](https://www.fansapi.com/terms-of-service).

AI-generated or AI-altered posts, media and voice messages must clearly feature the verified creator and be labelled #ai, as the OnlyFans Terms require. Review AI drafts before they are sent.
