BetterFans Link: the OnlyFans APIBetterFans Link

Content

How mass messages, posts, tracking links and vault media perform.

How mass messages, posts, tracking links and vault media perform. Every route can also return the authentication errors, rate_limited and internal_error.

RouteMethod and path
Mass messagesGET /v1/accounts/{accountId}/mass-messages
Top contentGET /v1/accounts/{accountId}/posts
Tracking linksGET /v1/accounts/{accountId}/links
VaultGET /v1/accounts/{accountId}/vault

Mass messages

GET /v1/accounts/{accountId}/mass-messages

Mass messages with how many fans got, opened and bought each one, and what each earned.

Needs the read scope. Reads synced data.

A mass message's numbers are totals for the whole send. Never add them to per-fan message numbers: each fan's copy of a mass message is part of the same total.

revenue comes from OnlyFans' own mass message stats, not from transactions, so net is 80% of gross.

Path parameters

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

Query parameters

NameTypeDefaultDescription
fromdate or timestamp30 days agoStart, ISO 8601 date or timestamp (UTC).
todate or timestampnowEnd, ISO 8601 date or timestamp (UTC).
sortenumrecentrecent = newest first. One of recent or revenue.
cursorstringNonenextCursor from the previous page. Leave out for the first page.
limitinteger25Page size, 1 to 100.

Returns

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

Example request

curl "https://app.betterfans.link/v1/accounts/412345678/mass-messages?limit=10" \
  -H "Authorization: Bearer $BFL_KEY"

Example response

{
  "data": [
    {
      "id": "118823004",
      "sentAt": "2026-09-26T18:00:00Z",
      "text": "Weekend special: the full beach video is in your inbox",
      "price": {
        "amount": 1200,
        "currency": "USD"
      },
      "media": [
        {
          "id": "3399120045",
          "type": "video",
          "thumbnailUrl": null,
          "durationSeconds": 94
        }
      ],
      "sentCount": 1742,
      "viewedCount": 903,
      "purchasedCount": 128,
      "revenue": {
        "gross": {
          "amount": 153600,
          "currency": "USD"
        },
        "net": {
          "amount": 122880,
          "currency": "USD"
        }
      },
      "state": "sent"
    }
  ],
  "hasMore": false,
  "nextCursor": null,
  "meta": {
    "source": "synced",
    "asOf": "2026-09-28T13:58:40Z",
    "requestId": "req_7Hq2LmX9pRt4VbN8cKe3WzYa"
  }
}

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.
invalid_parameter400A query parameter has a value this route does not accept, or a required one is missing. error.param names it.
invalid_cursor400cursor is not a nextCursor this list returned.

Top content

GET /v1/accounts/{accountId}/posts

Posts with price, likes and comments, sorted by recent or likes. tips and revenue are null: OnlyFans does not say which post a payment was for.

Needs the read scope. Reads synced data.

Path parameters

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

Query parameters

NameTypeDefaultDescription
fromdate or timestamp30 days agoStart, ISO 8601 date or timestamp (UTC).
todate or timestampnowEnd, ISO 8601 date or timestamp (UTC).
sortenumrecentrecent = newest first, likes = most liked first. One of recent or likes.
cursorstringNonenextCursor from the previous page. Leave out for the first page.
limitinteger25Page size, 1 to 100.

Returns

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

Example request

curl "https://app.betterfans.link/v1/accounts/412345678/posts?sort=likes&limit=10" \
  -H "Authorization: Bearer $BFL_KEY"

Example response

{
  "data": [
    {
      "id": "1788201934",
      "postedAt": "2026-09-20T17:30:00Z",
      "text": "Golden hour at the beach",
      "price": null,
      "media": [
        {
          "id": "3399120101",
          "type": "photo",
          "thumbnailUrl": null,
          "durationSeconds": null
        }
      ],
      "likes": 412,
      "comments": 38,
      "tips": null,
      "revenue": null,
      "url": "https://onlyfans.com/1788201934/jessrivers"
    }
  ],
  "hasMore": false,
  "nextCursor": null,
  "meta": {
    "source": "synced",
    "asOf": "2026-09-28T13:58:40Z",
    "requestId": "req_7Hq2LmX9pRt4VbN8cKe3WzYa"
  }
}

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.
invalid_parameter400A query parameter has a value this route does not accept, or a required one is missing. error.param names it.
invalid_cursor400cursor is not a nextCursor this list returned.

GET /v1/accounts/{accountId}/links

Tracking and free trial links with clicks, subscribers and revenue.

Needs the read scope. Reads synced data.

Path parameters

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

Query parameters

NameTypeDefaultDescription
sortenumrevenuerevenue = most earned first. One of revenue, subscribers or recent.
cursorstringNonenextCursor from the previous page. Leave out for the first page.
limitinteger25Page size, 1 to 100.

Returns

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

Example request

curl "https://app.betterfans.link/v1/accounts/412345678/links?sort=subscribers" \
  -H "Authorization: Bearer $BFL_KEY"

Example response

{
  "data": [
    {
      "id": "2210044",
      "kind": "tracking",
      "name": "Instagram bio",
      "url": "https://onlyfans.com/jessrivers/c12",
      "createdAt": "2026-03-02T15:00:00Z",
      "clicks": 18244,
      "subscribers": 1310,
      "revenue": {
        "gross": {
          "amount": 486000,
          "currency": "USD"
        },
        "net": {
          "amount": 388800,
          "currency": "USD"
        }
      }
    }
  ],
  "hasMore": false,
  "nextCursor": null,
  "meta": {
    "source": "synced",
    "asOf": "2026-09-28T13:58:40Z",
    "requestId": "req_7Hq2LmX9pRt4VbN8cKe3WzYa"
  }
}

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.
invalid_parameter400A query parameter has a value this route does not accept, or a required one is missing. error.param names it.
invalid_cursor400cursor is not a nextCursor this list returned.

Vault

GET /v1/accounts/{accountId}/vault

Media in the account's vault, with the vault lists each item is in. Put a media id in mediaIds to attach it to a message.

Needs the read scope. Reads synced data.

timesSent and revenue are null for every item.

A url, when set, is a public link to the file that never expires. Anyone with the URL can fetch the file, so treat it like a secret link: never publish it or put it anywhere a fan or a stranger could see it.

Path parameters

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

Query parameters

NameTypeDefaultDescription
folderstringNoneVault list id. Leave out for all media.
typeenumallMedia type. One of all, photo, video, audio or gif.
cursorstringNonenextCursor from the previous page. Leave out for the first page.
limitinteger25Page size, 1 to 100.

Returns

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

Example request

curl "https://app.betterfans.link/v1/accounts/412345678/vault?type=video&limit=10" \
  -H "Authorization: Bearer $BFL_KEY"

Example response

{
  "data": [
    {
      "id": "3399120045",
      "type": "video",
      "createdAt": "2026-09-19T16:20:00Z",
      "folders": [
        {
          "id": "771203",
          "name": "Beach shoot"
        }
      ],
      "thumbnailUrl": null,
      "url": null,
      "durationSeconds": 94,
      "timesSent": null,
      "revenue": null
    }
  ],
  "hasMore": true,
  "nextCursor": "q8ZtR2vN5xWcL7mK4pBd",
  "meta": {
    "source": "synced",
    "asOf": "2026-09-28T13:58:40Z",
    "requestId": "req_7Hq2LmX9pRt4VbN8cKe3WzYa"
  }
}

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.
invalid_parameter400A query parameter has a value this route does not accept, or a required one is missing. error.param names it.
invalid_cursor400cursor is not a nextCursor this list returned.

The MassMessage object

One mass message and its totals.

FieldTypeDescription
idstringMass message (queue) id.
sentAttimestampWhen it was sent.
textstringMessage text.
priceMoney or nullSet when it is a paid message (PPV).
mediaarray of MediaMedia attached.
sentCountintegerFans it was sent to.
viewedCountinteger or nullFans who opened it.
purchasedCountinteger or nullFans who bought it.
revenueobjectWhat it earned, as totals for the whole mass message.
revenue.grossMoneyGross.
revenue.netMoneyNet.
stateenumunsent means the creator took it back. One of sent or unsent.

The Post object

One post.

FieldTypeDescription
idstringPost id.
postedAttimestampWhen it was posted.
textstringPost text.
priceMoney or nullSet for a paid post.
mediaarray of MediaMedia in the post.
likesintegerLikes.
commentsintegerComments.
tipsMoney or nullnull: OnlyFans does not say which post a tip was for.
revenueobject or nullnull: OnlyFans does not say which post a purchase was for.
revenue.grossMoneyGross.
revenue.netMoneyNet.
urlstring or nullLink to the post on OnlyFans.

A tracking or free trial link.

FieldTypeDescription
idstringLink id.
kindenumtracking links count clicks and subscribers, trial links give a free trial. One of tracking or trial.
namestringName the creator gave the link.
urlstringThe link fans open.
createdAttimestamp or nullWhen the link was made.
clicksinteger or nullClicks on the link.
subscribersintegerFans who subscribed through the link.
revenueobjectRevenue from fans who subscribed through the link.
revenue.grossMoneyGross.
revenue.netMoneyNet.

The VaultItem object

One media item in the vault.

FieldTypeDescription
idstringMedia id. Use it in mediaIds.
typeenumMedia type. One of photo, video, audio, gif or other.
createdAttimestamp or nullWhen it was added to the vault.
foldersarray of objectsVault lists the item is in.
folders[].idstringVault list id. Use it as the folder parameter.
folders[].namestringVault list name.
thumbnailUrlstring or nullPreview image URL.
urlstring or nullArchived copy; null until archived.
durationSecondsnumber or nullLength of a video or audio clip.
timesSentinteger or nullHow many times it was sent.
revenueMoney or nullWhat it earned.

On this page