{"pages":[{"slug":"index","title":"BetterFans Link","description":"One API and one MCP server for OnlyFans creator data, with a person approving every write.","url":"https://app.betterfans.link/docs","headings":["How it works","Rules worth knowing first","For agents"]},{"slug":"get-started/quickstart-api","title":"API quickstart","description":"Create a test key, make your first call, read the response envelope and page through a list.","url":"https://app.betterfans.link/docs/get-started/quickstart-api","headings":["Create a test key","Make your first call","List the sandbox creators","Read the envelope","Page through a list","Handle errors","Next steps"]},{"slug":"get-started/quickstart-mcp","title":"MCP quickstart","description":"Connect an AI client to the BetterFans Link MCP server with OAuth or an API key, then ask it about your accounts.","url":"https://app.betterfans.link/docs/get-started/quickstart-mcp","headings":["The server URL","Choose how to sign in","Connect Claude Code","Ask your first question","Ask for a write","Teach the agent the rules"]},{"slug":"get-started/test-mode","title":"Test mode","description":"Build and test against sandbox creators with a test key. Test reads and writes never reach OnlyFans.","url":"https://app.betterfans.link/docs/get-started/test-mode","headings":["Turn it on","The sandbox creators","Writes in test mode","Webhooks in test mode","What test mode does not do"]},{"slug":"get-started/going-live","title":"Going live","description":"Link a real creator with a hosted link, understand grants, and switch your code to a live key.","url":"https://app.betterfans.link/docs/get-started/going-live","headings":["Link a creator","Grants","The first sync","Switch to a live key","Turn on writes","Checklist"]},{"slug":"concepts/entities","title":"Entities and ids","description":"How workspaces, accounts, fans, chats and money fit together, and which id to pass where.","url":"https://app.betterfans.link/docs/concepts/entities","headings":["The model","OnlyFans ids","BetterFans Link ids","Fan-written text"]},{"slug":"concepts/money","title":"Money","description":"Every amount is an object with integer cents. Gross and net are different numbers; never add them together.","url":"https://app.betterfans.link/docs/concepts/money","headings":["The Money object","Gross, net and fee","Where the numbers come from","Totals you must not add","Paid messages"]},{"slug":"concepts/freshness","title":"Synced and live reads","description":"Reads come from synced data by default. Use fresh=true on the three routes that support it when the answer must be current.","url":"https://app.betterfans.link/docs/concepts/freshness","headings":["How old is the data","Reading live with fresh=true","Chats stay unread","Presence","Calling OnlyFans directly","A newly linked account"]},{"slug":"concepts/account-status","title":"Account status","description":"The seven account statuses, which ones stop live calls, and what to do about each.","url":"https://app.betterfans.link/docs/concepts/account-status","headings":["The statuses","When live calls stop","Fixing a status","Watching for changes"]},{"slug":"concepts/writes-and-approvals","title":"Writes and approvals","description":"Nothing changes on OnlyFans until a person approves it. How actions work, from request to result.","url":"https://app.betterfans.link/docs/concepts/writes-and-approvals","headings":["The loop","What you need","Action types","Action statuses","Retrying safely","What the approver sees","Following the outcome","Test mode","Drafts are not writes"]},{"slug":"concepts/keys-and-scopes","title":"Keys and scopes","description":"Key types, the read and write scopes, account allow-lists, rotation and revocation.","url":"https://app.betterfans.link/docs/concepts/keys-and-scopes","headings":["Key types","Sending a key","Creating a key","Scopes","Account allow-lists","Changing, rolling and revoking","MCP clients","Roles","Keeping keys safe"]},{"slug":"concepts/rate-limits","title":"Rate limits","description":"Limits are per key. Read the RateLimit headers, and on 429 wait for Retry-After.","url":"https://app.betterfans.link/docs/concepts/rate-limits","headings":["The limits","Headers","When you hit the limit","Staying under it"]},{"slug":"concepts/requests-and-logs","title":"Requests and logs","description":"Request ids, the headers worth sending, and the request log in the dashboard.","url":"https://app.betterfans.link/docs/concepts/requests-and-logs","headings":["Request ids","Naming your app","The request log","The audit log"]},{"slug":"webhooks","title":"Set up webhooks","description":"Get a signed HTTPS request when a fan messages, a sale lands, an account changes status or an action is decided.","url":"https://app.betterfans.link/docs/webhooks","headings":["Add an endpoint","Event types","Receive an event","Send a test event","The signing secret","Deliveries","Events without an endpoint"]},{"slug":"concepts/security","title":"Security","description":"What BetterFans Link protects for you, what you are responsible for, and how to handle fan-written text safely.","url":"https://app.betterfans.link/docs/concepts/security","headings":["What BetterFans Link does","What you are responsible for","Fan-written text","Vault file URLs","MCP and OAuth","If a key leaks","Reporting a problem"]},{"slug":"api","title":"API overview","description":"Base URL, authentication, responses, pagination and every route.","url":"https://app.betterfans.link/docs/api","headings":["Base URL","Authentication","Responses","Meta","Lists","Pagination","Conventions","Errors","Routes","[Workspace](https://app.betterfans.link/docs/api/workspace)","[Accounts](https://app.betterfans.link/docs/api/accounts)","[Fans](https://app.betterfans.link/docs/api/fans)","[Chats](https://app.betterfans.link/docs/api/chats)","[Money](https://app.betterfans.link/docs/api/money)","[Content](https://app.betterfans.link/docs/api/content)","[Call OnlyFans](https://app.betterfans.link/docs/api/onlyfans)","[Actions](https://app.betterfans.link/docs/api/actions)"]},{"slug":"api/workspace","title":"Workspace","description":"Check which workspace, key and rate limit a request runs as.","url":"https://app.betterfans.link/docs/api/workspace","headings":["Who am I","Returns","Example request","Example response","The Me object"]},{"slug":"api/accounts","title":"Accounts","description":"List the creator accounts your key can use, check their health and link new ones.","url":"https://app.betterfans.link/docs/api/accounts","headings":["List accounts","Returns","Example request","Example response","Create link","Request body","Returns","Example request","Example response","Errors","Get link","Path parameters","Returns","Example request","Example response","Errors","Get account","Path parameters","Returns","Example request","Example response","Errors","The Account object","The AccountDetail object","The HostedLink object"]},{"slug":"api/fans","title":"Fans","description":"Find and rank fans, read one fan in full, list fan lists and see who is online.","url":"https://app.betterfans.link/docs/api/fans","headings":["List fans","Path parameters","Query parameters","Returns","Example request","Example response","Errors","Get fan","Path parameters","Query parameters","Returns","Example request","Example response","Errors","Fan lists","Path parameters","Query parameters","Returns","Example request","Example response","Errors","Online fans","Path parameters","Query parameters","Returns","Example request","Example response","Errors","The Fan object","The FanDetail object","The FanSummary object","The FanList object","The OnlineFans object"]},{"slug":"api/chats","title":"Chats","description":"Read chats and messages and search message text.","url":"https://app.betterfans.link/docs/api/chats","headings":["List chats","Path parameters","Query parameters","Returns","Example request","Example response","Errors","List messages","Path parameters","Query parameters","Returns","Example request","Example response","Errors","Search messages","Path parameters","Query parameters","Returns","Example request","Example response","Errors","The Chat object","The Message object","The Media object"]},{"slug":"api/money","title":"Money","description":"Revenue summaries and single transactions.","url":"https://app.betterfans.link/docs/api/money","headings":["Revenue summary","Path parameters","Query parameters","Returns","Example request","Example response","Errors","List transactions","Path parameters","Query parameters","Returns","Example request","Example response","Errors","The RevenueSummary object","The Transaction object"]},{"slug":"api/content","title":"Content","description":"How mass messages, posts, tracking links and vault media perform.","url":"https://app.betterfans.link/docs/api/content","headings":["Mass messages","Path parameters","Query parameters","Returns","Example request","Example response","Errors","Top content","Path parameters","Query parameters","Returns","Example request","Example response","Errors","Tracking links","Path parameters","Query parameters","Returns","Example request","Example response","Errors","Vault","Path parameters","Query parameters","Returns","Example request","Example response","Errors","The MassMessage object","The Post object","The TrackingLink object","The VaultItem object"]},{"slug":"api/onlyfans","title":"Call OnlyFans","description":"Read any OnlyFans API endpoint for a linked account.","url":"https://app.betterfans.link/docs/api/onlyfans","headings":["Call OnlyFans","Path parameters","Returns","Example request","Example response","Errors"]},{"slug":"api/actions","title":"Actions","description":"Ask for writes and follow them through approval.","url":"https://app.betterfans.link/docs/api/actions","headings":["Create action","Path parameters","Request body","send_message","send_mass_message","unsend_message","add_fan_to_list","remove_fan_from_list","Returns","Example request","Example response","Errors","Get action","Path parameters","Returns","Example request","Example response","Errors","List actions","Query parameters","Returns","Example request","Example response","Errors","The Action object","Action statuses","Results"]},{"slug":"errors","title":"Errors","description":"Every error code, what it means and what to do about it.","url":"https://app.betterfans.link/docs/errors","headings":["The error body","Retrying","All codes","Invalid request","invalid_parameter","invalid_cursor","idempotency_key_required","method_not_allowed","Authentication","missing_api_key","invalid_api_key","revoked_api_key","expired_api_key","not_signed_in","Permission","missing_scope","writes_disabled","missing_permission","dashboard_key_only","Not found","account_not_found","fan_not_found","chat_not_found","action_not_found","link_not_found","route_not_found","workspace_not_found","resource_not_found","Conflict","idempotency_conflict","action_not_pending","action_expired","link_not_ready","last_owner","Account unavailable","account_unavailable","Rate limited","rate_limited","Upstream","onlyfans_error","onlyfans_timeout","Internal","internal_error"]},{"slug":"webhooks/events","title":"Events","description":"Every webhook event type, its payload and an example.","url":"https://app.betterfans.link/docs/webhooks/events","headings":["Headers","The event object","Event types","account.connected","account.status_changed","account.removed","link.failed","message.received","transaction.created","subscriber.new","action.pending","action.executed","action.rejected","action.failed","Test mode","Test events","When events start"]},{"slug":"webhooks/verify","title":"Verify signatures","description":"Check that a webhook came from BetterFans Link before you act on it, with code for Node, Bun, Python and Go.","url":"https://app.betterfans.link/docs/webhooks/verify","headings":["How signing works","Node","Bun","Python","Go","Test vector","Sign a request yourself","When verification fails"]},{"slug":"webhooks/retries","title":"Retries and replay","description":"When BetterFans Link retries a webhook delivery, when it gives up and how to replay one.","url":"https://app.betterfans.link/docs/webhooks/retries","headings":["Schedule","Respond fast","Duplicates and order","Disabled endpoints","Replay"]},{"slug":"mcp","title":"MCP overview","description":"How the BetterFans Link MCP server works, how clients sign in to it, and what an agent gets from it.","url":"https://app.betterfans.link/docs/mcp","headings":["The server","Signing in","What an agent is told","Tool results","The OnlyFans API tools","Fan-written text","Resources","Prompts","Test mode"]},{"slug":"mcp/clients","title":"Client setup","description":"Connect Claude Code, Claude, ChatGPT, Cursor, VS Code, Windsurf, Codex or Gemini CLI to the BetterFans Link MCP server.","url":"https://app.betterfans.link/docs/mcp/clients","headings":["Claude Code","Claude.ai and Claude Desktop","ChatGPT","Cursor","VS Code","Windsurf","Codex","Gemini CLI","Other clients","Check the connection"]},{"slug":"mcp/tools","title":"Tools and prompts","description":"Every MCP tool, when to use it, and the prompts.","url":"https://app.betterfans.link/docs/mcp/tools","headings":["Accounts","list_accounts","account_health","link_account","get_link","Fans","find_fans","get_fan","list_fan_lists","online_fans","Chats","list_chats","get_chat","search_messages","draft_message","Money","revenue_summary","list_transactions","Content","mass_message_performance","top_content","link_performance","list_vault","OnlyFans API","search_api","describe_endpoint","call_api","Docs","search_docs","get_doc","Writes and approvals","send_message","send_mass_message","unsend_message","label_fan","get_action","Prompts"]},{"slug":"mcp/approvals","title":"Approvals for agents","description":"What an agent sees when it asks for a write over MCP, how a person approves it, and how the agent learns the outcome.","url":"https://app.betterfans.link/docs/mcp/approvals","headings":["The flow","What the agent gets back","Clients that open the link for you","Who can approve","Waiting for the outcome","Asking twice","When a write is refused","Test mode","Draft first"]},{"slug":"mcp/skills","title":"Agent skills","description":"Two skills that teach an agent how BetterFans Link works and how to run common agency jobs. Install them in Claude Code, Claude.ai or any agent that reads SKILL.md files.","url":"https://app.betterfans.link/docs/mcp/skills","headings":["The two skills","Claude Code","Claude.ai and Claude Desktop","Other agents","What the MCP server already says","Docs for agents"]},{"slug":"guides/link-a-creator","title":"Link a creator","description":"Send a creator a hosted link, follow their sign-in, handle a failure, and relink an account that needs it.","url":"https://app.betterfans.link/docs/guides/link-a-creator","headings":["Create the link","Send it to the creator","Follow progress","Link statuses","Steps the creator sees","When it connects","When it fails","Relink an account","In test mode"]},{"slug":"guides/daily-briefing","title":"Daily briefing","description":"A morning summary for every creator, with account problems, yesterday's revenue, top fans, chats worth answering and mass message results.","url":"https://app.betterfans.link/docs/guides/daily-briefing","headings":["With an agent","With the API","Reading the numbers","Next steps"]},{"slug":"guides/whales-and-churn","title":"Whales and churn","description":"Rank fans by lifetime spend, see what each one buys, and flag the big spenders who are slipping away before they are gone.","url":"https://app.betterfans.link/docs/guides/whales-and-churn","headings":["With an agent","With the API","What counts as at risk","Reading the numbers","Next steps"]},{"slug":"guides/reply-to-paying-fans","title":"Reply to unread paying fans","description":"Find the fans who have spent money and are waiting on a reply, write replies in the creator's voice, and send them after a person approves each one.","url":"https://app.betterfans.link/docs/guides/reply-to-paying-fans","headings":["Before you start","With an agent","With the API","Find who is waiting","Ask for the send","Follow the outcome","Writing replies that work"]},{"slug":"guides/moving-from-the-sdk","title":"Moving from the SDK","description":"How each part of the BetterFans Link SDK and the previous API maps to v1, what works differently, and what v1 does not have.","url":"https://app.betterfans.link/docs/guides/moving-from-the-sdk","headings":["What changed","Keys","How each part maps","A read, before and after","What is not in v1","Moving over"]}]}