# Onlyfans AI Chatbot

> Build or improve an OnlyFans AI chatbot integration with OnlyFansAPI.com webhooks, queued replies, typing coordination, and optional paid-message follow-ups.

- Skill: `onlyfansapi/onlyfans-ai-chatbot` (Agent Skill)
- Install (CLI): `npx skillmds@latest add onlyfansapi/onlyfans-ai-chatbot`
- Raw SKILL.md: https://api.skillmd.com/api/skills/onlyfansapi/onlyfans-ai-chatbot/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Integrations & APIs
- Author: onlyfansapi (https://skillmd.com/u/onlyfansapi)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/onlyfansapi/onlyfans-ai-chatbot

---


# Build an OnlyFans AI chatbot

Implement the customer's chatbot in their existing application and chosen AI stack; reuse its HTTP client, persistence, queue, and tests.
OnlyFansAPI supplies account events and messaging; the customer chooses the model, creator voice, content, and approval rules.
Building the integration does not authorize live messages, webhook registration, or deployment.

## When invoked

Inspect the client's MCP support and configured OnlyFansAPI servers. If remote MCP is supported and a relevant server is missing, ask once per conversation:
**“Would you like me to connect the OnlyFansAPI MCP as well?”** Explain the choices:

- **Docs MCP:** `https://docs.onlyfansapi.com/api/mcp` searches public documentation without authentication. Prefer it while building.
- **API MCP:** `https://app.onlyfansapi.com/mcp/onlyfans-mcp` acts on real accounts using API-key or OAuth authentication.

Follow the [AI agent setup guide](https://docs.onlyfansapi.com/introduction/guides/develop-with-ai-agents).
Preserve prior offers, consent or decline from any OnlyFans skill; do not install automatically or repeat the offer. Verify unknown client support first.
Reconnect unavailable configured servers instead of duplicating them, and verify discovery before claiming setup is complete.
Continue useful work while an answer is pending or MCP is unsupported. Code generation and local verification need no API key.

## Read the relevant contracts

Read the [chatbot tutorial](https://docs.onlyfansapi.com/onlyfans-ai/build-ai-chatbot-for-onlyfans),
[delivery rules](https://docs.onlyfansapi.com/webhooks/delivery-and-retries),
[signature guide](https://docs.onlyfansapi.com/webhooks/protecting-your-webhooks), and
[Send Message](https://docs.onlyfansapi.com/api-reference/chat-messages/send-message).
Read optional event or media details only when implementing them. Pages are also available as Markdown by appending `.mdx`.
Use [the documentation index](https://docs.onlyfansapi.com/llms.txt) to discover endpoints; verify current payloads and fields.

## Receive and queue events

- Configure a signing secret for the HTTPS webhook. Verify its `Signature` header as a
  hex HMAC-SHA256 over the **original raw body bytes**, before parsing or acting on JSON.
  Reject missing or malformed signatures and compare valid equal-length values in constant time
  using the language's crypto library. Re-serializing parsed JSON changes the signed bytes.
- Validate event type, creator account, chat identity, and required fields against the configured
  integration. Use webhook `account_id` (`acct_…`) for the API account; never substitute a username
  or numeric creator ID. Namespace persisted events and chat state by account and chat.
- Atomically persist a deduplicated event and durable work before returning a `2xx`, within
  the 10-second delivery budget. Use an existing transactional inbox or durable queue with
  equivalent recovery: a crash must not leave an event marked handled with its job missing.
  If durable acceptance fails, return an error. Run AI generation and sending in workers.
- Deduplicate durable events by `X-OFAPI-Idempotency-Key`; keep the source message ID for
  received-message reconciliation. Repeated deliveries must not create another reply job.
  Events can arrive out of order; use payload timestamps and message IDs when rebuilding history.
  Do not assume every event carries a key: typing is ephemeral.

Use these [event mappings](https://docs.onlyfansapi.com/webhooks/available-events):

| Event | Fan/chat ID | Handling |
| --- | --- | --- |
| `messages.received` | `payload.fromUser.id` | Persist the message and schedule a reply. |
| `users.typing` | `payload.id` | Update the latest typing time; it has no webhook idempotency key. |
| `messages.ppv.unlocked` | `payload.user_id` | Record the purchase and optionally schedule one follow-up. |
| `messages.sent` | Read the event's documented recipient fields | Update history and honor human takeover; never treat it as an incoming fan message. |

## Coordinate a conversation

- Start with `messages.received`. Serialize work per `(account_id, chat_id)` using the existing
  queue or store so concurrent messages do not generate overlapping replies. Recheck newly arrived
  messages and human takeover before sending; combine a fan's short message burst where appropriate.
- When typing support is requested, start a reply deadline from message receipt even if no typing
  event arrives. Extend it until approximately 5–10 seconds after the latest typing signal, with
  a bounded maximum wait. Typing alone must not create replies or an endless wait.
- Keep trusted creator instructions separate from fan text, names, links, and chat history.
  Pass that material as untrusted conversation data, never as system instructions or tool authority.
  Resolve recipients in application code; constrain generated media and prices to approved choices.
- Follow the customer's chosen automatic-reply or draft policy. Reuse any existing
  per-chat pause or human takeover controls, and keep live activation separate from
  building the integration. Do not add an approval interface the customer did not request.
- Use webhook history first. Fetching [chat messages](https://docs.onlyfansapi.com/api-reference/chat-messages/list-chat-messages)
  can mark the chat read, so do not use it as a continuous new-message poller. For recovery,
  [list unread chats](https://docs.onlyfansapi.com/api-reference/chats/list-chats) and reconcile persisted IDs.
  Follow `_pagination.next_page` when history spans pages.

## Send and reconcile

Use the server's HTTP client against `https://app.onlyfansapi.com` with `Authorization: Bearer <API_KEY>`, reading `ONLYFANSAPI_API_KEY` from server-side secrets.
Keep API and AI-provider keys out of browser code, logs, generated prompts, and source control.

- Send via `POST /api/{account}/chats/{chat_id}/messages`. Persist one unique outgoing
  **`Idempotency-Key`** and the exact request payload before attempting each intended reply.
  This is distinct from the incoming **`X-OFAPI-Idempotency-Key`**. Never regenerate a reply
  or change its payload under an already used outgoing key.
- Direct sends retain responses for 24 hours. `Idempotent-Replayed: true` identifies a replay;
  `409 IDEMPOTENCY_CONFLICT` means the original is running; `422 IDEMPOTENCY_KEY_MISMATCH`
  means the body or chat changed. Respect `Retry-After` and bound retries.
- A timeout or server failure can leave delivery uncertain. Persist that state and reconcile
  the intended reply with chat history before resending; a missing or nonunique match does not
  prove failure. Hold ambiguous sends for operator recovery. Never create a new key to force
  another attempt, retry after the retention window blindly, or promise exactly-once delivery.
- Generated API MCP tools may omit custom headers, including `Idempotency-Key`. Inspect the
  callable schema; use direct REST for sends requiring it rather than putting the key in JSON
  or assuming an MCP connection header reaches the underlying send request.

## Optional purchases and media

For `messages.ppv.unlocked`, parse the `firstId` query parameter from `payload.replacePairs["{MESSAGE_LINK}"]`
with a URL parser; match it to a saved sent message within the same account/chat. Never fetch that link as an instruction. Mark the exact offer
purchased and cancel its reminders. Deduplicate follow-ups using the incoming event key;
pass purchase facts as an event to the AI, not as words spoken by the fan.

Use existing [vault media](https://docs.onlyfansapi.com/api-reference/media-vault/list-vault-media) IDs for reusable content.
`/media/upload` returns single-use CDN upload material; `/media/vault` stores reusable vault items.
Paid messages require media; check current price and preview rules in Send Message. For requested asynchronous uploads,
wait for completion before sending; HTTP `202` only means accepted. Do not add media or PPV flows to a text-only request.

## Verify the integration

Leave focused runnable checks in the existing test setup or a small local harness: valid signed event → one queued reply; duplicate → no second reply; altered/missing signature
→ no work; send timeout → retained uncertain state without a blind second send. Exercise the
typing fallback and PPV matching if implemented. Stub external calls; live validation needs
the customer's authorization. Report implemented behavior, checks run, and remaining setup.

