BetterFans Link: the OnlyFans APIBetterFans Link

Accounts and hosted links

OnlyFans and Fansly accounts API: list the creator accounts your key can use, check each one's status, and link new creators with a hosted link.

Product page: OnlyFans agency API

Start here. Most other routes take an accountId, and List accounts gives you each one with its platform and status. Every route can also return the authentication errors, rate_limited and internal_error.

RouteMethod and pathPlatforms
List accountsGET /v1/accountsOnlyFans and Fansly
Create linkPOST /v1/linksOnlyFans and Fansly
Get linkGET /v1/links/{linkId}OnlyFans and Fansly
Get accountGET /v1/accounts/{accountId}OnlyFans and Fansly

List accounts

GET /v1/accounts

The OnlyFans and Fansly accounts your key can use, with their platform and status. A key limited to some accounts sees only those. platform=fansly or platform=onlyfans lists one platform. In test mode this lists the sandbox creators.

Needs the read scope.

Query parameters

NameTypeDefaultDescription
platformenumallOnly accounts on this platform. One of all, onlyfans or fansly.

Returns

200 with a list of Account objects in data. See pagination.

Example request

curl "https://betterfans.link/v1/accounts" \
  -H "Authorization: Bearer $BFL_KEY"

Example response

{
  "data": [
    {
      "id": "412345678",
      "platform": "onlyfans",
      "username": "jessrivers",
      "name": "Jess Rivers",
      "avatarUrl": null,
      "status": "healthy",
      "statusReason": null,
      "writesEnabled": true,
      "linkedAt": "2026-08-14T16:02:11Z",
      "lastSyncedAt": "2026-09-28T13:58:40Z"
    },
    {
      "id": "398776120",
      "platform": "onlyfans",
      "username": "mayablue",
      "name": "Maya Blue",
      "avatarUrl": null,
      "status": "needs_relink",
      "statusReason": "The OnlyFans session expired. Link the account again to resume syncing and live reads.",
      "writesEnabled": false,
      "linkedAt": "2026-07-02T10:15:00Z",
      "lastSyncedAt": "2026-09-26T21:40:12Z"
    },
    {
      "id": "583912047736512512",
      "platform": "fansly",
      "username": "raevale",
      "name": "Rae Vale",
      "avatarUrl": null,
      "status": "healthy",
      "statusReason": null,
      "writesEnabled": true,
      "linkedAt": "2026-09-21T11:30:42Z",
      "lastSyncedAt": "2026-09-28T13:45:03Z"
    }
  ],
  "hasMore": false,
  "nextCursor": null,
  "meta": {
    "source": "synced",
    "asOf": "2026-09-28T13:58:40Z",
    "requestId": "req_7Hq2LmX9pRt4VbN8cKe3WzYa"
  }
}

Errors

CodeStatusWhen
invalid_parameter400A query parameter has a value this route does not accept, or a required one is missing. error.param names it.

POST /v1/links

Creates a hosted link. Send its url to the creator: they open it, sign in to OnlyFans or Fansly and the account is linked to your workspace. The link works for 24 hours.

Needs the read scope.

Set platform to onlyfans or fansly to choose for the creator. Leave it out and the creator picks on the link page; the link's platform is null until they do.

Nothing is linked until the creator finishes. Check progress with Get link, or listen for the account.connected and link.failed webhook events.

Request body

FieldTypeDescription
notestringOptional. Shown in the dashboard next to the link, for example the creator's name. Up to 200 characters.
platformenumOptional. onlyfans or fansly. Leave out to let the creator pick on the link page.

Returns

201 with a HostedLink object in data.

Example request

curl -X POST "https://betterfans.link/v1/links" \
  -H "Authorization: Bearer $BFL_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "note": "Jess Rivers"
}'

Example response

{
  "data": {
    "id": "link_9QwE4rTy6UiO2pAs8DfG1hJk",
    "platform": null,
    "status": "waiting",
    "step": "Waiting for the creator",
    "url": "https://betterfans.link/link/x7Hq2LmX9pRt4VbN8cKe3WzYaQ5sD1fG6jK0lZ2cV4b",
    "accountId": null,
    "note": "Jess Rivers",
    "createdAt": "2026-09-28T14:00:00Z",
    "expiresAt": "2026-09-29T14:00:00Z"
  },
  "meta": {
    "source": "synced",
    "asOf": null,
    "requestId": "req_7Hq2LmX9pRt4VbN8cKe3WzYa"
  }
}

Errors

CodeStatusWhen
invalid_parameter400platform is not onlyfans or fansly, or note is longer than 200 characters.

GET /v1/links/{linkId}

The progress of a hosted link, with the current step in plain words. Once status is connected, accountId holds the new account.

Needs the read scope.

Path parameters

NameDescription
linkIdThe link_ id from POST /v1/links.

Returns

200 with a HostedLink object in data.

Example request

curl "https://betterfans.link/v1/links/link_9QwE4rTy6UiO2pAs8DfG1hJk" \
  -H "Authorization: Bearer $BFL_KEY"

Example response

{
  "data": {
    "id": "link_9QwE4rTy6UiO2pAs8DfG1hJk",
    "platform": "onlyfans",
    "status": "in_progress",
    "step": "Waiting for 2FA code",
    "url": "https://betterfans.link/link/x7Hq2LmX9pRt4VbN8cKe3WzYaQ5sD1fG6jK0lZ2cV4b",
    "accountId": null,
    "note": "Jess Rivers",
    "createdAt": "2026-09-28T14:00:00Z",
    "expiresAt": "2026-09-29T14:00:00Z"
  },
  "meta": {
    "source": "synced",
    "asOf": null,
    "requestId": "req_7Hq2LmX9pRt4VbN8cKe3WzYa"
  }
}

Errors

CodeStatusWhen
link_not_found404No link with this id in your workspace.

Get account

GET /v1/accounts/{accountId}

One account with its counts, 30 day revenue and last sync. Read it before a long task, or after a call fails with account_unavailable.

Needs the read scope. Reads synced data. Works for OnlyFans and Fansly accounts.

Path parameters

NameDescription
accountIdThe account's id, which is the creator's user id on its platform. Get it from GET /v1/accounts.

Returns

200 with an AccountDetail object in data.

Example request

curl "https://betterfans.link/v1/accounts/412345678" \
  -H "Authorization: Bearer $BFL_KEY"

Example response

{
  "data": {
    "id": "412345678",
    "platform": "onlyfans",
    "username": "jessrivers",
    "name": "Jess Rivers",
    "avatarUrl": null,
    "status": "healthy",
    "statusReason": null,
    "writesEnabled": true,
    "linkedAt": "2026-08-14T16:02:11Z",
    "lastSyncedAt": "2026-09-28T13:58:40Z",
    "counts": {
      "activeFans": 1842,
      "expiredFans": 5310,
      "chats": 6120,
      "posts": 486,
      "vaultItems": 2210
    },
    "revenue30d": {
      "gross": {
        "amount": 2184050,
        "currency": "USD"
      },
      "net": {
        "amount": 1747240,
        "currency": "USD"
      }
    },
    "subscriptionPrice": {
      "amount": 999,
      "currency": "USD"
    }
  },
  "meta": {
    "source": "synced",
    "asOf": "2026-09-28T13:58:40Z",
    "requestId": "req_7Hq2LmX9pRt4VbN8cKe3WzYa",
    "platform": "onlyfans"
  }
}

Errors

CodeStatusWhen
account_not_found404The account is not linked to your workspace, your key's account list leaves it out, or, with a test key, it is not a sandbox creator.

The Account object

A creator account your workspace can use, on OnlyFans or Fansly. Its id is the creator's user id on that platform.

FieldTypeDescription
idstringThe creator's user id on its platform. Every account route takes it as accountId.
platformenumThe platform the account lives on: onlyfans or fansly.
usernamestringUsername on its platform, without the @.
namestring or nullDisplay name on its platform.
avatarUrlstring or nullProfile picture URL.
statusenumPlain account status. See account status. One of healthy, syncing, needs_relink, awaiting_2fa, awaiting_selfie, restricted or disconnected.
statusReasonstring or nullPlain sentence explaining a non-healthy status.
writesEnabledbooleanWhether actions can be created for this account. An owner or admin switches it in the dashboard.
linkedAttimestamp or nullWhen the account was linked to this workspace.
lastSyncedAttimestamp or nullWhen this account last synced.

The AccountDetail object

An account with counts, 30 day revenue and the subscription price.

FieldTypeDescription
idstringThe creator's user id on its platform. Every account route takes it as accountId.
platformenumThe platform the account lives on: onlyfans or fansly.
usernamestringUsername on its platform, without the @.
namestring or nullDisplay name on its platform.
avatarUrlstring or nullProfile picture URL.
statusenumPlain account status. See account status. One of healthy, syncing, needs_relink, awaiting_2fa, awaiting_selfie, restricted or disconnected.
statusReasonstring or nullPlain sentence explaining a non-healthy status.
writesEnabledbooleanWhether actions can be created for this account. An owner or admin switches it in the dashboard.
linkedAttimestamp or nullWhen the account was linked to this workspace.
lastSyncedAttimestamp or nullWhen this account last synced.
countsobjectTotals from synced data.
counts.activeFansintegerFans with an active subscription.
counts.expiredFansintegerFans whose subscription ended.
counts.chatsintegerChats on the account.
counts.postsintegerPosts on the account.
counts.vaultItemsintegerMedia items in the vault.
revenue30dobjectRevenue over the last 30 days.
revenue30d.grossMoneyWhat fans paid.
revenue30d.netMoneyWhat the creator keeps after the platform fee.
subscriptionPriceMoney or nullCurrent subscription price.

A page a creator opens to connect their OnlyFans or Fansly account.

FieldTypeDescription
idstringlink_ id.
platformenum or nullnull until the creator picks a platform on the link page. One of onlyfans or fansly.
statusenumwaiting until the creator starts, in_progress while they sign in, then connected, failed, expired or cancelled.
stepstring or nullPlain words for the current step, for example: Waiting for 2FA code.
urlstringSend this to the creator. Valid for 24 hours.
accountIdstring or nullSet once connected.
notestring or nullThe note sent when the link was created.
createdAttimestampWhen the link was created.
expiresAttimestampWhen the link stops working, 24 hours after it was created.

On this page