Money
Revenue summaries and single transactions.
Revenue summaries and single transactions. Amounts are integer cents; read money before you add anything up. Every route can also return the authentication errors, rate_limited and internal_error.
| Route | Method and path |
|---|---|
| Revenue summary | GET /v1/accounts/{accountId}/revenue |
| List transactions | GET /v1/accounts/{accountId}/transactions |
Revenue summary
GET /v1/accounts/{accountId}/revenue
Gross and net revenue for a period, split by type and as a time series, with the top fans and the previous period for comparison.
Needs the read scope. Reads synced data.
Gross is what fans paid. Net is what the creator keeps, about 80% of gross. Never add them together. See money.
Path parameters
| Name | Description |
|---|---|
accountId | The account's id, which is the creator's OnlyFans user id. Get it from GET /v1/accounts. |
Query parameters
| Name | Type | Default | Description |
|---|---|---|---|
from | date or timestamp | 30 days ago | Start, ISO 8601 date or timestamp (UTC). |
to | date or timestamp | now | End, ISO 8601 date or timestamp (UTC). |
interval | enum | day | Bucket size for the series. One of day, week or month. |
Returns
200 with a RevenueSummary object in data.
Example request
curl "https://app.betterfans.link/v1/accounts/412345678/revenue?from=2026-09-01&to=2026-09-28&interval=week" \
-H "Authorization: Bearer $BFL_KEY"Example response
{
"data": {
"from": "2026-09-01T00:00:00Z",
"to": "2026-09-28T00:00:00Z",
"interval": "week",
"gross": {
"amount": 2045000,
"currency": "USD"
},
"net": {
"amount": 1636000,
"currency": "USD"
},
"byType": {
"subscription": {
"gross": {
"amount": 612000,
"currency": "USD"
},
"net": {
"amount": 489600,
"currency": "USD"
},
"count": 612
},
"tip": {
"gross": {
"amount": 402500,
"currency": "USD"
},
"net": {
"amount": 322000,
"currency": "USD"
},
"count": 190
},
"message": {
"gross": {
"amount": 918000,
"currency": "USD"
},
"net": {
"amount": 734400,
"currency": "USD"
},
"count": 804
},
"post": {
"gross": {
"amount": 98500,
"currency": "USD"
},
"net": {
"amount": 78800,
"currency": "USD"
},
"count": 51
},
"stream": {
"gross": {
"amount": 14000,
"currency": "USD"
},
"net": {
"amount": 11200,
"currency": "USD"
},
"count": 6
},
"referral": {
"gross": {
"amount": 0,
"currency": "USD"
},
"net": {
"amount": 0,
"currency": "USD"
},
"count": 0
},
"other": {
"gross": {
"amount": 0,
"currency": "USD"
},
"net": {
"amount": 0,
"currency": "USD"
},
"count": 0
}
},
"series": [
{
"start": "2026-09-01T00:00:00Z",
"gross": {
"amount": 498000,
"currency": "USD"
},
"net": {
"amount": 398400,
"currency": "USD"
},
"count": 402
},
{
"start": "2026-09-08T00:00:00Z",
"gross": {
"amount": 521500,
"currency": "USD"
},
"net": {
"amount": 417200,
"currency": "USD"
},
"count": 418
},
{
"start": "2026-09-15T00:00:00Z",
"gross": {
"amount": 470250,
"currency": "USD"
},
"net": {
"amount": 376200,
"currency": "USD"
},
"count": 390
},
{
"start": "2026-09-22T00:00:00Z",
"gross": {
"amount": 555250,
"currency": "USD"
},
"net": {
"amount": 444200,
"currency": "USD"
},
"count": 453
}
],
"topFans": [
{
"fan": {
"id": "38291045",
"username": "mike_travels",
"name": "Mike",
"avatarUrl": null
},
"gross": {
"amount": 96500,
"currency": "USD"
}
},
{
"fan": {
"id": "51820377",
"username": "danny.k",
"name": "Danny",
"avatarUrl": null
},
"gross": {
"amount": 61200,
"currency": "USD"
}
}
],
"previousPeriod": {
"gross": {
"amount": 1872500,
"currency": "USD"
},
"net": {
"amount": 1498000,
"currency": "USD"
}
}
},
"meta": {
"source": "synced",
"asOf": "2026-09-28T13:58:40Z",
"requestId": "req_7Hq2LmX9pRt4VbN8cKe3WzYa"
}
}Errors
| Code | Status | When |
|---|---|---|
account_not_found | 404 | The 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_parameter | 400 | A query parameter has a value this route does not accept, or a required one is missing. error.param names it. |
List transactions
GET /v1/accounts/{accountId}/transactions
Single transactions, each with the fan, gross, net and fee: subscriptions, tips, paid messages, posts and more.
Needs the read scope. Reads synced data.
Only sales are listed. Refunds and chargebacks are not in v1.
messageId and postId are not filled yet and are always null for now.
Path parameters
| Name | Description |
|---|---|
accountId | The account's id, which is the creator's OnlyFans user id. Get it from GET /v1/accounts. |
Query parameters
| Name | Type | Default | Description |
|---|---|---|---|
from | date or timestamp | 30 days ago | Start, ISO 8601 date or timestamp (UTC). |
to | date or timestamp | now | End, ISO 8601 date or timestamp (UTC). |
type | enum | all | Only this kind of earning. One of all, subscription, tip, message, post, stream, referral or other. |
fanId | string | None | Only this fan's transactions. |
cursor | string | None | nextCursor from the previous page. Leave out for the first page. |
limit | integer | 25 | Page size, 1 to 100. |
Returns
200 with a list of Transaction objects in data. See pagination.
Example request
curl "https://app.betterfans.link/v1/accounts/412345678/transactions?type=tip&limit=10" \
-H "Authorization: Bearer $BFL_KEY"Example response
{
"data": [
{
"id": "7730021596",
"type": "tip",
"fan": {
"id": "51820377",
"username": "danny.k",
"name": "Danny",
"avatarUrl": null
},
"gross": {
"amount": 2000,
"currency": "USD"
},
"net": {
"amount": 1600,
"currency": "USD"
},
"fee": {
"amount": 400,
"currency": "USD"
},
"createdAt": "2026-09-28T09:12:44Z",
"messageId": null,
"postId": null,
"description": "Tip from Danny"
},
{
"id": "7729988120",
"type": "tip",
"fan": {
"id": "38291045",
"username": "mike_travels",
"name": "Mike",
"avatarUrl": null
},
"gross": {
"amount": 5000,
"currency": "USD"
},
"net": {
"amount": 4000,
"currency": "USD"
},
"fee": {
"amount": 1000,
"currency": "USD"
},
"createdAt": "2026-09-27T23:40:02Z",
"messageId": null,
"postId": null,
"description": "Tip from Mike on a post"
}
],
"hasMore": true,
"nextCursor": "q8ZtR2vN5xWcL7mK4pBd",
"meta": {
"source": "synced",
"asOf": "2026-09-28T13:58:40Z",
"requestId": "req_7Hq2LmX9pRt4VbN8cKe3WzYa"
}
}Errors
| Code | Status | When |
|---|---|---|
account_not_found | 404 | The 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_parameter | 400 | A query parameter has a value this route does not accept, or a required one is missing. error.param names it. |
invalid_cursor | 400 | cursor is not a nextCursor this list returned. |
The RevenueSummary object
Revenue for a period.
| Field | Type | Description |
|---|---|---|
from | timestamp | Start of the period. |
to | timestamp | End of the period. |
interval | enum | Bucket size of series. One of day, week or month. |
gross | Money | What fans paid in the period. |
net | Money | What the creator keeps, about 80% of gross. |
byType | object | Totals per transaction type. One entry for each of subscription, tip, message, post, stream, referral and other. |
byType.<type>.gross | Money | Gross for this type. |
byType.<type>.net | Money | Net for this type. |
byType.<type>.count | integer | Number of transactions. |
series | array of objects | One point per bucket. |
series[].start | timestamp | Start of the bucket. |
series[].gross | Money | Gross in the bucket. |
series[].net | Money | Net in the bucket. |
series[].count | integer | Transactions in the bucket. |
topFans | array of objects | The fans who paid the most in the period. |
topFans[].fan | FanSummary | The fan. |
topFans[].gross | Money | What the fan paid in the period. |
previousPeriod | object | The same length of time just before from, for comparison. |
previousPeriod.gross | Money | Gross in the previous period. |
previousPeriod.net | Money | Net in the previous period. |
The Transaction object
One payment from a fan.
| Field | Type | Description |
|---|---|---|
id | string | Transaction id. |
type | enum | What the fan paid for. One of subscription, tip, message, post, stream, referral or other. |
fan | FanSummary or null | The fan who paid. |
gross | Money | What the fan paid. |
net | Money | What the creator keeps. |
fee | Money | The OnlyFans fee, gross minus net. |
createdAt | timestamp | When it happened. |
messageId | string or null | The paid message, or the message a tip came with. Not filled yet, so it is always null for now. |
postId | string or null | The post the payment was for. Not filled yet, so it is always null for now. |
description | string or null | OnlyFans' own description of the transaction. |