BetterFans Link: the OnlyFans APIBetterFans Link

Errors

Every error code, what it means and what to do about it.

Errors come back with an HTTP status and a JSON body. Branch on error.code: it is stable. error.message is for people and can be more specific than the default shown here, so never match on it.

The error body

FieldTypeDescription
errorobjectThe error.
error.typeenumError category. It decides the HTTP status, except for method_not_allowed, which is 405. One of invalid_request, authentication, permission, not_found, conflict, account_unavailable, rate_limited, upstream or internal.
error.codeenumStable code to branch on. One of the 31 codes under all codes.
error.messagestringA sentence for people. It can be more specific than the default, so never match on it.
error.hintstringOptional. What to do next.
error.paramstringOptional. The parameter that failed validation.
error.permissionstringOptional. The permission that was missing.
error.accountStatusstringOptional. The account's status, sent with account_unavailable.
error.docsUrlstringLink to this code on the errors page.
requestIdstringThe request id. Send it to support when you ask about a request.
{
  "error": {
    "type": "account_unavailable",
    "code": "account_unavailable",
    "message": "OnlyFans is not accepting calls for this account right now.",
    "hint": "See error.accountStatus. Reads without fresh=true still work.",
    "accountStatus": "needs_relink",
    "docsUrl": "https://app.betterfans.link/docs/errors#account-unavailable"
  },
  "requestId": "req_7Hq2LmX9pRt4VbN8cKe3WzYa"
}

Retrying

ErrorWhat to do
429 rate_limitedWait the number of seconds in Retry-After, then retry.
502 onlyfans_error and onlyfans_timeoutRetry after a short wait, or read synced data without fresh=true.
500 or 503 internal_errorRetry with a growing delay.
409 account_unavailableDo not retry until the account status changes.
Any other 4xxFix the request first. Sending it again unchanged fails the same way.
Any error on an actionRetry with the same Idempotency-Key, so the action is created once.

All codes

Codes marked dashboard come from the dashboard and the hosted link page, never from the REST API or MCP.

CodeStatusType
invalid_parameter400invalid_request
invalid_cursor400invalid_request
idempotency_key_required400invalid_request
method_not_allowed405invalid_request
missing_api_key401authentication
invalid_api_key401authentication
revoked_api_key401authentication
expired_api_key401authentication
not_signed_in (dashboard)401authentication
missing_scope403permission
writes_disabled403permission
missing_permission403permission
dashboard_key_only403permission
account_not_found404not_found
fan_not_found404not_found
chat_not_found404not_found
action_not_found404not_found
link_not_found404not_found
route_not_found404not_found
workspace_not_found (dashboard)404not_found
resource_not_found404not_found
idempotency_conflict409conflict
action_not_pending409conflict
action_expired409conflict
link_not_ready (dashboard)409conflict
last_owner (dashboard)409conflict
account_unavailable409account_unavailable
rate_limited429rate_limited
onlyfans_error502upstream
onlyfans_timeout502upstream
internal_error500internal

Invalid request

invalid_parameter

StatusTypeMessageHint
400invalid_requestA parameter is missing or not valid.Check error.param and the endpoint reference.

A query parameter has a value the route does not accept, a required one is missing, or the body does not match. error.param names the parameter. Fix the value and send the request again. Unknown query parameters are ignored, so a misspelled name has no effect instead of failing.

invalid_cursor

StatusTypeMessageHint
400invalid_requestThe cursor is not valid for this list.Pass nextCursor exactly as the previous page returned it.

A cursor belongs to one list with one set of filters. Pass nextCursor back unchanged with the same parameters, or leave cursor out to start again from the first page.

idempotency_key_required

StatusTypeMessageHint
400invalid_requestWrites need an Idempotency-Key header.Send a unique value per intended action, for example a UUID.

Every POST /v1/accounts/{accountId}/actions needs an Idempotency-Key header. Generate a UUID for each action you intend and send the same value when you retry that action.

method_not_allowed

StatusTypeMessageHint
405invalid_requestThis endpoint only accepts GET.Use POST /v1/accounts/{accountId}/actions to change anything on OnlyFans.

Call OnlyFans only reads. To send, take back or change anything, create an action instead; a person approves it before it runs.

Authentication

missing_api_key

StatusTypeMessageHint
401authenticationNo API key was sent.Send Authorization: Bearer <your key>.

Send the key as Authorization: Bearer <key> or in the x-api-key header.

invalid_api_key

StatusTypeMessageHint
401authenticationThis API key is not valid.Check for typos or create a new key in the dashboard.

No key matches. Check that the whole key was copied and that nothing was added around it. Keys are shown once, so a lost key has to be replaced with a new one.

revoked_api_key

StatusTypeMessageHint
401authenticationThis API key was revoked.Create a new key in the dashboard.

Someone revoked this key in the dashboard, or it was rolled and the old key stopped working. Create a new key.

expired_api_key

StatusTypeMessageHint
401authenticationThis API key has expired.Create a new key in the dashboard.

The key passed the expiry date set when it was created. Create a new key.

not_signed_in

StatusTypeMessageHint
401authenticationYou are not signed in.Sign in again.

Dashboard only. The dashboard session ended. Sign in again.

Permission

missing_scope

StatusTypeMessageHint
403permissionThis key does not have the scope this call needs.Create a key with the write scope.

The key has only the read scope and the call needs write. Create a key with the write scope for code that asks for writes.

writes_disabled

StatusTypeMessageHint
403permissionWrites are turned off for this account.An admin can turn writes on in the account's settings.

Writes are switched off for this account. An owner or admin can switch them on in the account's settings in the dashboard. Reads keep working.

missing_permission

StatusTypeMessageHint
403permissionYour role does not allow this.Ask a workspace admin.

In the dashboard: your workspace role does not allow this. error.permission names the permission. Ask an owner or admin. Over MCP, search_api and describe_endpoint return it to a test key or to a workspace with no linked account: connect with a live key and link an account first.

dashboard_key_only

StatusTypeMessageHint
403permissionOnly the dashboard can run this.Approve the action in the dashboard.

Only the dashboard runs an action, after a person approves it. API and OAuth keys create actions and read their status.

Not found

account_not_found

StatusTypeMessageHint
404not_foundNo account with this id is linked to your workspace.List your accounts with GET /v1/accounts.

The account id is not linked to your workspace, your key is limited to other accounts, or a test key asked for an account that is not a sandbox creator. BetterFans Link answers 404, never 403, so it never reveals whether an account exists. List the accounts your key can use with GET /v1/accounts.

fan_not_found

StatusTypeMessageHint
404not_foundNo fan with this id on this account.Search with GET /v1/accounts/{accountId}/fans?search=.

Fan ids are OnlyFans user ids. Find the fan with GET /v1/accounts/{accountId}/fans?search= and use the id it returns.

chat_not_found

StatusTypeMessageHint
404not_foundNo chat with this fan.A chat id is the fan's id.

A chat id is the fan's id. Use a fan id from List fans or List chats.

action_not_found

StatusTypeMessageHint
404not_foundNo action with this id.List actions with GET /v1/actions.

Check the id, or list actions with GET /v1/actions.

StatusTypeMessageHint
404not_foundNo link with this id.Create one with POST /v1/links.

Check the id, or create a new link with POST /v1/links.

route_not_found

StatusTypeMessageHint
404not_foundThis endpoint does not exist.See the API reference.

The method and path match no route. Paths start with /v1. Compare yours with the API reference.

workspace_not_found

StatusTypeMessageHint
404not_foundWorkspace not found.Pick a workspace you belong to.

Dashboard only. The workspace does not exist or you are not a member. Pick a workspace you belong to.

resource_not_found

StatusTypeMessageHint
404not_foundNot found.None

Something the request refers to does not exist. Check every id in the path.

Conflict

idempotency_conflict

StatusTypeMessageHint
409conflictThis Idempotency-Key was already used with a different request.Use a new key for a different action.

You reused an Idempotency-Key with a different body. One key stands for one intended action: use a new key for a new action. The same key with the same body returns the original action, so retries are safe.

action_not_pending

StatusTypeMessageHint
409conflictThis action was already decided.Check its status with GET /v1/actions/{actionId}.

The action was already approved, rejected, run or it failed. Read its status with GET /v1/actions/{actionId}.

action_expired

StatusTypeMessageHint
409conflictThis action expired before anyone approved it.Create it again.

Pending actions expire after 24 hours without a decision. Create the action again with a new Idempotency-Key.

StatusTypeMessageHint
409conflictThis link is not waiting for that step.None

Dashboard only. The link is not at the step this request is for, for example a 2FA code sent before OnlyFans asked for one. Reload the link's state and follow the step it shows.

last_owner

StatusTypeMessageHint
409conflictA workspace needs at least one owner.Make someone else an owner first.

Dashboard only. A workspace always keeps at least one owner. Make another member an owner before you remove or demote this one.

Account unavailable

account_unavailable

StatusTypeMessageHint
409account_unavailableOnlyFans is not accepting calls for this account right now.See error.accountStatus. Reads without fresh=true still work.

OnlyFans is not accepting calls for this account. error.accountStatus is one of needs_relink, awaiting_2fa, awaiting_selfie, restricted or disconnected. Live reads and Call OnlyFans stop until the account is healthy again, and approved actions cannot run. Reads without fresh=true keep working. Do not retry until the status changes: see account status for what fixes each one.

Rate limited

rate_limited

StatusTypeMessageHint
429rate_limitedToo many requests.Wait for Retry-After seconds.

The key sent more requests than its rate limit allows. Wait the number of seconds in the Retry-After header, then retry. See rate limits.

Upstream

onlyfans_error

StatusTypeMessageHint
502upstreamOnlyFans returned an error.Retry later. If it keeps failing, check the account's status.

OnlyFans answered a live read with an error. Retry after a short wait. If it keeps failing, read the account with GET /v1/accounts/{accountId}: its status may have changed.

onlyfans_timeout

StatusTypeMessageHint
502upstreamOnlyFans did not answer in time.Retry later, or read without fresh=true to get synced data.

OnlyFans did not answer in time. Retry later, or leave out fresh=true to read synced data.

Internal

internal_error

StatusTypeMessageHint
500internalSomething went wrong on our side.Retry. If it keeps happening, send us the requestId.

Something failed inside BetterFans Link. In test mode it comes back as 503 while the sandbox is briefly unavailable. Retry with a growing delay. If it keeps happening, send the requestId to hello@betterfans.link.

On this page