curl --request GET \
--url https://api.fanvue.com/v1/insights/earnings \
--header 'Authorization: Bearer <token>' \
--header 'X-Fanvue-API-Version: <x-fanvue-api-version>'import requests
url = "https://api.fanvue.com/v1/insights/earnings"
headers = {
"X-Fanvue-API-Version": "<x-fanvue-api-version>",
"Authorization": "Bearer <token>"
}
response = requests.get(url, headers=headers)
print(response.text)const options = {
method: 'GET',
headers: {
'X-Fanvue-API-Version': '<x-fanvue-api-version>',
Authorization: 'Bearer <token>'
}
};
fetch('https://api.fanvue.com/v1/insights/earnings', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));{
"data": [
{
"date": "2024-01-15T00:00:00.000Z",
"gross": 5000,
"net": 4250,
"currency": "USD",
"source": "subscription",
"transactionOrderId": "FV-ORDER-123",
"transactionOrderStatus": "availableForPayout",
"user": {
"uuid": "f47ac10b-58cc-4372-a567-0e02b2c3d479",
"handle": "sarah-jones",
"nickname": "SarahK",
"displayName": "Sarah Jones",
"isTopSpender": true,
"avatarUrl": "https://media.fanvue.com/avatars/example-avatar.jpg",
"registeredAt": "2024-01-10T12:00:00.000Z"
}
},
{
"date": "2024-01-14T00:00:00.000Z",
"gross": 2500,
"net": 2125,
"currency": "USD",
"source": "tip",
"transactionOrderId": "FV-ORDER-124",
"transactionOrderStatus": "pendingBalance",
"tipContext": "message",
"user": {
"uuid": "6ba7b810-9dad-11d1-80b4-00c04fd430c8",
"handle": "mike-smith",
"nickname": null,
"displayName": "Mike Smithly",
"isTopSpender": false,
"avatarUrl": "https://media.fanvue.com/avatars/example-avatar.jpg",
"registeredAt": "2024-01-10T12:00:00.000Z"
}
},
{
"date": "2024-01-14T00:00:00.000Z",
"gross": 2500,
"net": 2125,
"currency": "USD",
"source": "message",
"transactionOrderId": "FV-ORDER-126",
"transactionOrderStatus": "availableForPayout",
"messageUuid": "b7c8d9e0-1234-5678-9abc-def012345678",
"messageType": "BROADCAST",
"user": {
"uuid": "f47ac10b-58cc-4372-a567-0e02b2c3d479",
"handle": "sarah-jones",
"nickname": "SarahK",
"displayName": "Sarah Jones",
"isTopSpender": true,
"avatarUrl": "https://media.fanvue.com/avatars/example-avatar.jpg",
"registeredAt": "2024-01-10T12:00:00.000Z"
}
},
{
"date": "2024-01-14T00:00:00.000Z",
"gross": -2500,
"net": -2125,
"currency": "USD",
"source": "refund",
"transactionOrderId": "FV-ORDER-125",
"transactionOrderStatus": "availableForPayout",
"reversedTransactionOrderId": "FV-ORDER-124",
"user": {
"uuid": "6ba7b810-9dad-11d1-80b4-00c04fd430c8",
"handle": "mike-smith",
"nickname": null,
"displayName": "Mike Smithly",
"isTopSpender": false,
"avatarUrl": "https://media.fanvue.com/avatars/example-avatar.jpg",
"registeredAt": "2024-01-10T12:00:00.000Z"
}
}
],
"nextCursor": "eyJkYXRlIjoiMjAyNC0wMS0xNVQwMDowMDowMC4wMDBaIn0"
}{
"error": "<string>",
"message": "<string>"
}{
"error": "<string>"
}{
"error": "<string>"
}{
"error": "<string>",
"message": "<string>",
"nextVersion": "<string>"
}{
"error": "<string>"
}Get earnings data
Returns cursor-paginated invoice data for the authenticated creator over a specified time period. Each transaction includes information about the fan who made the payment. Reversals are included as refund/chargeback rows with negative gross (matching /insights/spending); filter them with source.
Pass transactionOrderIds (comma-separated, max 100) to fetch only specific transactions by ID — useful for re-fetching known transactions to pick up status changes. It combines with the other filters and normal pagination still applies.
Pass experienceUuid to return only the revenue one fan experience produced: its one-off access purchases, its first subscription charge, every renewal, and the refunds and chargebacks reversing any of them. Every row also reports experienceUuid and experienceAppUuid, so an unfiltered page can be attributed client-side too.
Polling for real-time updates? Use a webhook instead.
If you are calling this endpoint on a schedule to detect new activity, subscribe to the creator.payment.succeeded, creator.refund.created, creator.dispute.created, creator.dispute.flagged webhook events instead — you’ll get pushed updates in real time without polling. See the webhook documentation.
Webhooks replace polling for detecting these events, but for authoritative financial figures you should still reconcile against this endpoint. The creator.payment.succeeded payload’s data.id is the Fanvue invoice number, which matches the transactionOrderId on the rows returned here — pass it to transactionOrderIds to cross-check specific transactions without a full re-poll.
curl --request GET \
--url https://api.fanvue.com/v1/insights/earnings \
--header 'Authorization: Bearer <token>' \
--header 'X-Fanvue-API-Version: <x-fanvue-api-version>'import requests
url = "https://api.fanvue.com/v1/insights/earnings"
headers = {
"X-Fanvue-API-Version": "<x-fanvue-api-version>",
"Authorization": "Bearer <token>"
}
response = requests.get(url, headers=headers)
print(response.text)const options = {
method: 'GET',
headers: {
'X-Fanvue-API-Version': '<x-fanvue-api-version>',
Authorization: 'Bearer <token>'
}
};
fetch('https://api.fanvue.com/v1/insights/earnings', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));{
"data": [
{
"date": "2024-01-15T00:00:00.000Z",
"gross": 5000,
"net": 4250,
"currency": "USD",
"source": "subscription",
"transactionOrderId": "FV-ORDER-123",
"transactionOrderStatus": "availableForPayout",
"user": {
"uuid": "f47ac10b-58cc-4372-a567-0e02b2c3d479",
"handle": "sarah-jones",
"nickname": "SarahK",
"displayName": "Sarah Jones",
"isTopSpender": true,
"avatarUrl": "https://media.fanvue.com/avatars/example-avatar.jpg",
"registeredAt": "2024-01-10T12:00:00.000Z"
}
},
{
"date": "2024-01-14T00:00:00.000Z",
"gross": 2500,
"net": 2125,
"currency": "USD",
"source": "tip",
"transactionOrderId": "FV-ORDER-124",
"transactionOrderStatus": "pendingBalance",
"tipContext": "message",
"user": {
"uuid": "6ba7b810-9dad-11d1-80b4-00c04fd430c8",
"handle": "mike-smith",
"nickname": null,
"displayName": "Mike Smithly",
"isTopSpender": false,
"avatarUrl": "https://media.fanvue.com/avatars/example-avatar.jpg",
"registeredAt": "2024-01-10T12:00:00.000Z"
}
},
{
"date": "2024-01-14T00:00:00.000Z",
"gross": 2500,
"net": 2125,
"currency": "USD",
"source": "message",
"transactionOrderId": "FV-ORDER-126",
"transactionOrderStatus": "availableForPayout",
"messageUuid": "b7c8d9e0-1234-5678-9abc-def012345678",
"messageType": "BROADCAST",
"user": {
"uuid": "f47ac10b-58cc-4372-a567-0e02b2c3d479",
"handle": "sarah-jones",
"nickname": "SarahK",
"displayName": "Sarah Jones",
"isTopSpender": true,
"avatarUrl": "https://media.fanvue.com/avatars/example-avatar.jpg",
"registeredAt": "2024-01-10T12:00:00.000Z"
}
},
{
"date": "2024-01-14T00:00:00.000Z",
"gross": -2500,
"net": -2125,
"currency": "USD",
"source": "refund",
"transactionOrderId": "FV-ORDER-125",
"transactionOrderStatus": "availableForPayout",
"reversedTransactionOrderId": "FV-ORDER-124",
"user": {
"uuid": "6ba7b810-9dad-11d1-80b4-00c04fd430c8",
"handle": "mike-smith",
"nickname": null,
"displayName": "Mike Smithly",
"isTopSpender": false,
"avatarUrl": "https://media.fanvue.com/avatars/example-avatar.jpg",
"registeredAt": "2024-01-10T12:00:00.000Z"
}
}
],
"nextCursor": "eyJkYXRlIjoiMjAyNC0wMS0xNVQwMDowMDowMC4wMDBaIn0"
}{
"error": "<string>",
"message": "<string>"
}{
"error": "<string>"
}{
"error": "<string>"
}{
"error": "<string>",
"message": "<string>",
"nextVersion": "<string>"
}{
"error": "<string>"
}read:insights— Access analytics, metrics, and insights data for performance tracking.
Authorizations
OAuth 2.0 access token, presented as a JWT bearer token in the Authorization header. Obtain a token via the authorization-code flow; the scopes granted to the token determine which operations it may call.
Headers
API version to use for the request
"2025-06-26"
Query Parameters
Start date as ISO 8601 datetime string with optional timezone offset (e.g., 2024-10-20T00:00:00+01:00 or 2024-10-20T00:00:00Z).
End date as ISO 8601 datetime string with optional timezone offset (e.g., 2024-10-25T00:00:00+01:00 or 2024-10-25T00:00:00Z). Non-inclusive - data before this date is included.
Comma-separated list of earning sources
What produced this earning.
renewal is a catch-all for every recurring charge after the first payment: profile subscriptions, checkout-link subscriptions and fan-experience subscriptions all bill as renewal from their second charge onwards. So subscription, checkoutLink and fanExperience only ever hold first payments and one-off purchases. appStore is the single exception: an app's recurring charges stay appStore.
fanExperience and appStore are different sides of a third-party app: fanExperience is the creator selling a paid experience to a fan, appStore is the app's developer selling to the creator, so an appStore row is not fan-to-creator spend. referral, affiliate and giveaway are creator rewards rather than fan purchases. user follows the invoice rather than the source: it is null when the row records no fan, the common case for those three, and a giveaway granted to a specific fan returns that fan.
Reversals are surfaced here too: refund and chargeback rows carry negative gross/net, matching /insights/spending.
all, affiliate, appStore, checkoutLink, fanExperience, mediaLink, message, post, referral, renewal, subscription, tip, giveaway, refund, chargeback Comma-separated transaction order IDs to fetch (max 100). Use to re-fetch specific transactions by ID and pick up status changes. Combines with the other filters; normal pagination still applies. Comma-separated transaction order IDs (max 100)
Return only earnings attributed to this fan experience. Matches every charge the experience produced, including one-off access purchases, the first subscription charge and each renewal, plus the refunds and chargebacks that reverse any of them, so a filtered total nets out correctly. Combines with the other filters; normal pagination still applies.
Use this rather than filtering on source: a renewal reports source: "renewal", so source=fanExperience under-reports recurring experience revenue from the second charge onwards.
Cursor for pagination - If given, pass nextCursor to get the next page.
Number of items to return per page (1-50, default: 20). When omitted on a cursor request, the size from the previous page (carried in the cursor) is reused.
1 <= x <= 50Was this page helpful?