<!-- Generated by scripts/gen-docs.ts from @bfl/contract. Do not edit. -->

# Errors

Branch on `error.code`, never on `error.message`. Full list: https://app.betterfans.link/docs/errors

| Code | Status | What to do |
| --- | --- | --- |
| `invalid_parameter` | 400 | 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` | 400 | 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` | 400 | 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` | 405 | Call OnlyFans only reads. To send, take back or change anything, create an action instead; a person approves it before it runs. |
| `missing_api_key` | 401 | Send the key as `Authorization: Bearer <key>` or in the `x-api-key` header. |
| `invalid_api_key` | 401 | 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` | 401 | Someone revoked this key in the dashboard, or it was rolled and the old key stopped working. Create a new key. |
| `expired_api_key` | 401 | The key passed the expiry date set when it was created. Create a new key. |
| `missing_scope` | 403 | 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` | 403 | 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` | 403 | 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` | 403 | Only the dashboard runs an action, after a person approves it. API and OAuth keys create actions and read their status. |
| `account_not_found` | 404 | 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` | 404 | 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` | 404 | A chat id is the fan's id. Use a fan id from List fans or List chats. |
| `action_not_found` | 404 | Check the id, or list actions with `GET /v1/actions`. |
| `link_not_found` | 404 | Check the id, or create a new link with `POST /v1/links`. |
| `route_not_found` | 404 | The method and path match no route. Paths start with `/v1`. Compare yours with the API reference. |
| `resource_not_found` | 404 | Something the request refers to does not exist. Check every id in the path. |
| `idempotency_conflict` | 409 | 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` | 409 | The action was already approved, rejected, run or it failed. Read its status with `GET /v1/actions/{actionId}`. |
| `action_expired` | 409 | Pending actions expire after 24 hours without a decision. Create the action again with a new `Idempotency-Key`. |
| `account_unavailable` | 409 | 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` | 429 | 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. |
| `onlyfans_error` | 502 | 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` | 502 | OnlyFans did not answer in time. Retry later, or leave out `fresh=true` to read synced data. |
| `internal_error` | 500 | 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. |
