BetterFans Link: the OnlyFans APIBetterFans Link

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

  1. You create an action with Create action, or an MCP write tool such as send_message. BetterFans Link checks the params, writes a one line summary such as "Send a $12 message to @jess" and returns 202 with the action in pending status and its approvalUrl.
  2. 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.
  3. An approved action runs on OnlyFans and ends as executed, with result, or failed, with error.
  4. 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

RequirementWithout 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

TypeWhat it doesParams
send_messageSends a message to one fan. Add priceCents to make it a paid message and mediaIds to attach vault media.Send message
send_mass_messageSends 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_messageTakes back a message. Pass a massMessageId to take back every copy of a mass message.Unsend message
add_fan_to_listAdds a fan to one of the fan lists.Add fan to list
remove_fan_from_listRemoves a fan from one of the fan lists.Remove fan from list

Action statuses

StatusLabelMeaning
pendingWaiting for approvalWaiting for a person to approve or reject it. It expires after 24 hours.
approvedApprovedA person approved it and it is about to run.
rejectedRejectedA person rejected it. Nothing was sent.
expiredExpiredNobody decided within 24 hours. Nothing was sent.
executingRunningRunning on OnlyFans.
executedDoneDone. result holds what the write returned.
failedFailedIt 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 409 idempotency_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.

On this page