Approvals for agents
What an agent sees when it asks for a write over MCP, how a person approves it, and how the agent learns the outcome.
An agent can read on its own, but it cannot change anything on OnlyFans by itself. The write tools send_message, send_mass_message, unsend_message and label_fan each create a pending action. Nothing is sent until a person approves that action in BetterFans Link. The rules are the same as for the REST API. See writes and approvals.
The flow
- The agent calls a write tool, for example
send_messagewith the fan, the text and a price. - BetterFans Link checks the request and creates a pending action.
- The tool returns the action with an approval link.
- The agent shares the link. A person opens it, reads what will happen and approves or rejects it.
- On approval the write runs on OnlyFans. The agent checks the result with
get_action.
| Tool | Action it creates |
|---|---|
send_message | send_message |
send_mass_message | send_mass_message |
unsend_message | unsend_message |
label_fan | add_fan_to_list or remove_fan_from_list |
What the agent gets back
The text result has:
- The action's summary, in the words the approver will see.
- The action id, which starts with
act_, and its status. - The approval link, and when the action expires. A pending action expires after 24 hours.
- For a mass message, the estimated number of fans it will reach.
- In test mode, a line that says nothing is sent to OnlyFans.
structuredContent holds the full Action. The approval link is approvalUrl.
The agent should share the link and say plainly that nothing has been sent yet. It must not tell anyone a message was sent until get_action returns executed.
Clients that open the link for you
Clients on MCP protocol 2026-07-28 that support URL elicitation get more than a link. The tool asks the client to open the approval page. The client shows the action's summary, then "Open this page to approve or reject it in BetterFans Link. Nothing is sent until a person approves."
If you accept, the client opens the approval page in your browser. Opening it does not approve anything: you still approve or reject on the page. The tool then returns the action with its current status. If you decline, the action stays pending until it expires, and anyone who can approve can still find it on the Approvals page.
Older clients show the link in the tool result instead.
Who can approve
Owners and admins of the workspace can approve. Developers and read only members can see pending actions but cannot decide them. The approver signs in to BetterFans Link, so an agent can never approve its own request.
The approval page shows the account, the fan or lists, the full text, the price, any media, and who asked. For an MCP request, that is the client name and the tool. The approver can approve or reject. They cannot edit the text, so the agent should draft it exactly as it should be sent.
Approvers also see every pending action on the Approvals page, and the action.pending webhook can alert them.
Waiting for the outcome
Call get_action with the action id.
| 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. |
A person may take minutes or hours to decide. Do not call get_action in a tight loop. Tell the user the link, then check again when they say they decided, or every minute or so if the agent has to wait. Stop when the status is executed, rejected, expired or failed.
Asking twice
When the same client calls the same write tool with the same arguments again within the same 10 minute window, it gets the first pending action back instead of a second one. An agent that retries after a timeout does not queue duplicates. A change to any argument creates a new action.
When a write is refused
A refused write returns a tool error with a code and a hint, and creates no action.
| Code | Why | What to do |
|---|---|---|
missing_scope | The key has no write scope. | Add the scope to the key. |
writes_disabled | API writes are off for the account. They start off. | An owner or admin turns on API writes on the account's Settings page. |
invalid_parameter | An argument is missing or not valid. | Fix the argument that param names. |
An OAuth client without the write scope gets a 403 with insufficient_scope before the tool runs. The client can ask you to approve write access.
Test mode
With a test key, or an OAuth grant made in test mode, the flow is the same. Approving runs nothing on OnlyFans: the action ends as executed with result.simulated set to true. Use it to see how your agent words its requests before it works on live accounts.
Draft first
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. It sends nothing and needs no approval. A good agent drafts, shows you the text, and calls send_message only once you agree with it.