Mass Messages
Mass Message Statistics
Returns mass message stats — sent count, viewed count, media, and PPV purchase counts per mass message. Paginate by following _pagination.next_page. Requires permission api_mass_messages_list.
https://public-api.fansmetric.comAuthorization
defaultAuthorizationBearer <token>Send your FansMetric API key as a Bearer token in the Authorization header.
In: header
Path Parameters
account_id*integerOnlyFans numeric account ID.
Query Parameters
limitintegerNumber of items. Default 10. Min 1, max 100.
start_datestringEarliest mass message date (UTC). Default 2 years ago. Format
YYYY-MM-DD HH:MM:SS; a bare RFC 3339 timestamp (2026-08-19T00:00:00) is also accepted, but a trailing UTC offset such as+00:00is not — strip it. Hold this value fixed while paginating.end_datestringLatest mass message date (UTC), exclusive. Default end of today. This doubles as the pagination cursor — prefer following
_pagination.next_pageover setting it by hand. FormatYYYY-MM-DD HH:MM:SS.
Response Fields
data.items[]arrayPer-mass-message stat rows, newest first. Shape is determined by upstream OnlyFans and proxied as-is.
data.items[].idintegerMass message ID.
data.items[].datestringSend time, RFC 3339 with offset (
2026-09-18T06:32:28+00:00). This is the value behind the pagination cursor, but it is not directly reusable asend_date— convert it to2026-09-18 06:32:28first (drop theTand the+00:00), or just use_pagination.next_page, which is already converted.data.items[].sentCountintegerFans the message was delivered to.
data.items[].viewedCountintegerFans who opened it.
data.items[].pricestringPPV price as a decimal string (e.g.
"14.59"), not a number. Omitted entirely on free sends — checkisFreebefore reading it.data.items[].purchasedCountintegerNumber of purchases of the PPV. Omitted on free sends.
data.items[].previewsarrayMedia IDs shown as the free preview on a PPV send. Empty array on free sends.
data.items[].media[]arrayAttached media:
id,type(photoorvideo),duration,videoSources, andfiles.{full,thumb,preview,squarePreview}with signed FansMetric URLs.data.items[].mediaCountintegerNumber of attachments.
data.items[].isFreebooleanWhether the send carried no PPV price.
data.items[].isCanceledbooleanWhether the send was cancelled before completing.
data.items[].templatestringMessage kind —
groupfor mass messages.data.items[].canUnsendbooleanWhether the message is still inside its unsend window.
data.items[].unsendSecondsintegerSeconds remaining in the unsend window.
data.hasMorebooleanWhether another page exists. Stop paginating when this is
false.dataobject | arrayEndpoint-specific payload. See the fields below for this route.
_pagination.next_pagestringRelative URL for the next page, with the cursor or offset already applied. Append it to the API base URL and send it as-is. Omitted entirely on the last page.
_meta._credits.usedintegerCredits consumed by this request (currently always
1)._meta._rate_limits.limit_minuteintegerMaximum requests per minute for the organization.
_meta._rate_limits.remaining_minuteintegerRemaining requests in the current minute window.
_meta._rate_limits.limit_dayintegerMaximum requests per day for the organization.
_meta._rate_limits.remaining_dayintegerRemaining requests in the current day window.
| Field | Type | Description |
|---|---|---|
| data.items[] | array | Per-mass-message stat rows, newest first. Shape is determined by upstream OnlyFans and proxied as-is. |
| data.items[].id | integer | Mass message ID. |
| data.items[].date | string | Send time, RFC 3339 with offset (2026-09-18T06:32:28+00:00). This is the value behind the pagination cursor, but it is not directly reusable as end_date — convert it to 2026-09-18 06:32:28 first (drop the T and the +00:00), or just use _pagination.next_page, which is already converted. |
| data.items[].sentCount | integer | Fans the message was delivered to. |
| data.items[].viewedCount | integer | Fans who opened it. |
| data.items[].price | string | PPV price as a decimal string (e.g. "14.59"), not a number. Omitted entirely on free sends — check isFree before reading it. |
| data.items[].purchasedCount | integer | Number of purchases of the PPV. Omitted on free sends. |
| data.items[].previews | array | Media IDs shown as the free preview on a PPV send. Empty array on free sends. |
| data.items[].media[] | array | Attached media: id, type (photo or video), duration, videoSources, and files.{full,thumb,preview,squarePreview} with signed FansMetric URLs. |
| data.items[].mediaCount | integer | Number of attachments. |
| data.items[].isFree | boolean | Whether the send carried no PPV price. |
| data.items[].isCanceled | boolean | Whether the send was cancelled before completing. |
| data.items[].template | string | Message kind — group for mass messages. |
| data.items[].canUnsend | boolean | Whether the message is still inside its unsend window. |
| data.items[].unsendSeconds | integer | Seconds remaining in the unsend window. |
| data.hasMore | boolean | Whether another page exists. Stop paginating when this is false. |
| data | object | array | Endpoint-specific payload. See the fields below for this route. |
| _pagination.next_page | string | Relative URL for the next page, with the cursor or offset already applied. Append it to the API base URL and send it as-is. Omitted entirely on the last page. |
| _meta._credits.used | integer | Credits consumed by this request (currently always 1). |
| _meta._rate_limits.limit_minute | integer | Maximum requests per minute for the organization. |
| _meta._rate_limits.remaining_minute | integer | Remaining requests in the current minute window. |
| _meta._rate_limits.limit_day | integer | Maximum requests per day for the organization. |
| _meta._rate_limits.remaining_day | integer | Remaining requests in the current day window. |
curl --request GET "https://public-api.fansmetric.com/v1/100000001/mass-messages?limit=20&start_date=2026-01-01%2000%3A00%3A00&end_date=2026-01-31%2023%3A59%3A59" \
--header "Authorization: Bearer YOUR_API_KEY"Response
200