Writes and approvals
Nothing changes on OnlyFans until a person approves it. How actions work, from request to result.
BetterFans Link never writes to OnlyFans on its own. Your code or your agent asks for a write, a person on your team approves or rejects it, and only then does it run. This holds for every key, every MCP client and test mode alike.
The loop
- You create an action with Create action, or an MCP write tool such as
send_message. BetterFans Link checks the params, writes a one linesummarysuch as "Send a $12 message to @jess" and returns202with the action inpendingstatus and itsapprovalUrl. - A person opens the
approvalUrl, or the Approvals page in the dashboard, reads the summary and the details, and approves or rejects it. They can add a note of up to 280 characters. - An approved action runs on OnlyFans and ends as
executed, withresult, orfailed, witherror. - You find out through webhooks or by calling Get action.
A pending action that nobody decides within 24 hours becomes expired. Nothing is sent. No webhook event is sent for an expired action, so if you track actions yourself, treat expiresAt as the deadline or read the action again after it.
What you need
| Requirement | Without it |
|---|---|
A key with the write scope, or an MCP client given write access. | 403 missing_scope |
| Writes turned on for the account. An owner or admin does this on the account's Settings page. They start off. | 403 writes_disabled |
An Idempotency-Key header on the request. | 400 idempotency_key_required |
| Someone who can approve. Owners and admins can; developers and read only members cannot. | The action waits, then expires. |
Action types
| Type | What it does | Params |
|---|---|---|
send_message | Sends a message to one fan. Add priceCents to make it a paid message and mediaIds to attach vault media. | Send message |
send_mass_message | Sends one message to fan lists or a set of fans. The action shows an estimate of how many fans it will reach. | Send mass message |
unsend_message | Takes back a message. Pass a massMessageId to take back every copy of a mass message. | Unsend message |
add_fan_to_list | Adds a fan to one of the fan lists. | Add fan to list |
remove_fan_from_list | Removes a fan from one of the fan lists. | Remove fan from list |
Action statuses
| Status | Label | Meaning |
|---|---|---|
pending | Waiting for approval | Waiting for a person to approve or reject it. It expires after 24 hours. |
approved | Approved | A person approved it and it is about to run. |
rejected | Rejected | A person rejected it. Nothing was sent. |
expired | Expired | Nobody decided within 24 hours. Nothing was sent. |
executing | Running | Running on OnlyFans. |
executed | Done | Done. result holds what the write returned. |
failed | Failed | It ran and did not succeed. error says why. |
Retrying safely
Create one new Idempotency-Key for each write you intend, such as a UUID, and store it with your own record of the request. If the request times out or you are not sure it arrived, send it again with the same key.
- The same key with the same body returns the original action. Nothing is created twice.
- The same key with a different body is
409idempotency_conflict. - A key is unique across your whole workspace, in both modes, and never expires. Reusing one for another account, the other mode, another type or other params is also
idempotency_conflict. Use a new UUID for every write you intend.
What the approver sees
The approval page shows the summary, the account, the fan, the full text and price, any media, and who asked: the key name, or the MCP client and the tool it used. For a mass message it also shows estimatedRecipients. Write your text as you want it sent. The approver can approve or reject it, not edit it.
Following the outcome
Prefer webhooks. action.pending tells approvers there is something to decide. action.executed, action.rejected and action.failed tell your code how it ended.
If you poll Get action instead, wait a few seconds between calls and stop when the status is executed, rejected, expired or failed. A person may take hours to decide, so do not hold a request open waiting for one.
Test mode
In test mode the loop is the same, but an approved action never calls OnlyFans. It ends as executed, and its result is only {"simulated": true}. See test mode.
Drafts are not writes
The MCP tool draft_message gathers what a reply needs: the chat so far, what the fan has spent and bought, and paid messages they have not bought yet. The agent writes the reply from that. It never creates an action and nobody needs to approve it. An agent can draft a reply, show it to you, and then ask to send it with send_message. See approvals over MCP.