Earnings stats, chart and recent transactions
API reference

Earnings stats, chart and recent transactions

The same revenue the creator sees on their own dashboard: drop sales + tips + subscription payments, refunds and chargebacks excluded, bucketed by day in the caller's timezone.

View as MarkdownUpdated Aug 19, 2026
GET/api/external/v1/earningsalso served at /api/external/earnings

The same revenue the creator sees on their own dashboard: drop sales + tips + subscription payments, refunds and chargebacks excluded, bucketed by day in the caller's timezone.

Everything here is in cents (the balance endpoint is dollars). stats.totalEarningsCents is NET (after the platform fee); grossEarningsCents and the chart series are seller GROSS (buyer-paid minus tax, before the fee) so per-day merges against your own gross ledgers compare like for like. Pass tz = the creator's timezone (read it from GET /api/external/v1/timezone) or your day buckets won't match their dashboard.

transactions is a fixed cap, not a page

transactions is always the newest 50 across all three sources. For the complete, paginated ledger with net / fee / VAT per transaction, use GET /api/external/v1/earnings/transactions.

Authentication

Send the creator's API key as a bearer token: Authorization: Bearer dpfn_…. See Authentication & API keys.

For a creator you manage or onboarded

GET /api/external/v1/creators/{creatorId}/earnings — an agency's own key for a creator or AI persona it manages (needs canViewStats), or your app owner's own key for an account your app onboarded. The X-Dropfans-Account header still works but is deprecated. See Acting for a creator.

Query parameters

NameTypeRequiredDescription
startDatestringRequiredWindow start, YYYY-MM-DD, interpreted in tz.
Format: date
endDatestringRequiredWindow end (inclusive), YYYY-MM-DD, interpreted in tz.
Format: date
tzstringOptionalIANA timezone for day bucketing. **Invalid values silently fall back to UTC** — no error.
Default: "UTC"
Format: iana-timezone

Responses

200Stats, chart and the newest transactions. All money in cents.
NameTypeDescription
statsEarningsStatsWindow totals. Cents throughout (the balance endpoint is dollars).
Show child attributes
totalEarningsCentsinteger**NET** seller earnings in cents for the window (after platform fee).
grossEarningsCentsintegerSeller gross in cents (buyer-paid minus tax, before the platform fee) — matches the dashboard’s Gross toggle.
previousPeriodEarningsCentsintegerNET cents for the same-length window immediately before startDate.
previousPeriodGrossEarningsCentsintegerGross cents for the previous window.
transactionCountintegerPaid transactions in the window (drops + tips + subscription payments).
avgTransactionCentsintegerAverage NET cents per transaction.
uniqueCustomersintegerDistinct buyer emails in the window.
typeTotalsobjectPer-type window totals (additive field, 2026-07-22).
Show child attributes
dropobjectTotals for drop revenue.
Show child attributes
grossCentsintegerGross cents.
netCentsintegerNet cents.
countintegerTransaction count.
tipobjectTotals for tip revenue.
Show child attributes
grossCentsintegerGross cents.
netCentsintegerNet cents.
countintegerTransaction count.
subscriptionobjectTotals for subscription revenue.
Show child attributes
grossCentsintegerGross cents.
netCentsintegerNet cents.
countintegerTransaction count.
chartEarningsChartBucketed GROSS series in the caller’s timezone.
Show child attributes
labelsstring[]Chart x-axis labels, aligned with values and dates.
valuesinteger[]**GROSS** cents per bucket (gross so per-day merges against your own gross ledgers compare like for like).
datesstring[]Bucket keys in the caller’s tz. Weekly buckets use the week-start date, monthly the 1st.
groupBystringBucket size: day when the span is ≤31 days, week ≤90, else month.
One of: day, week, month
typedValuesobjectPer-type GROSS cent series aligned 1:1 with dates (additive field, 2026-07-22).
Show child attributes
dropinteger[]Gross cents per bucket from drops.
tipinteger[]Gross cents per bucket from tips.
subscriptioninteger[]Gross cents per bucket from subscriptions.
transactionsEarningsTransaction[]The newest 50 transactions across all three sources — a fixed cap, not a page. For the complete ledger use GET /api/external/v1/earnings/transactions.
Show child attributes
idstringThe order / tip / renewal id (source-specific — matches nothing on the buyer’s side).
productIdstringThe sold product’s id — **drop transactions only**; absent on tips and subscriptions. Join it back to your own drop records.
productNamestringProduct name, or the literal "Tip" / "Subscription".
amountCentsintegerNET seller earnings in cents.
grossAmountCentsintegerGross cents (buyer-paid minus tax).
buyerEmailstring | nullBuyer email when known.
Format: email
buyerNamestring | nullBuyer display name — tips and subscriptions only; always null on drops.
paidAtstringWhen it was paid.
Format: date-time
typestringRevenue source.
One of: drop, tip, subscription
Example response
{
  "stats": {
    "totalEarningsCents": 182050,
    "grossEarningsCents": 214180,
    "previousPeriodEarningsCents": 141200,
    "previousPeriodGrossEarningsCents": 166100,
    "transactionCount": 41,
    "avgTransactionCents": 4440,
    "uniqueCustomers": 28,
    "typeTotals": {
      "drop": {
        "grossCents": 150000,
        "netCents": 127500,
        "count": 30
      },
      "tip": {
        "grossCents": 44180,
        "netCents": 37550,
        "count": 8
      },
      "subscription": {
        "grossCents": 20000,
        "netCents": 17000,
        "count": 3
      }
    }
  },
  "chart": {
    "labels": [
      "Aug 18",
      "Aug 19"
    ],
    "values": [
      12500,
      9800
    ],
    "dates": [
      "2026-08-18",
      "2026-08-19"
    ],
    "groupBy": "day",
    "typedValues": {
      "drop": [
        10000,
        7500
      ],
      "tip": [
        2500,
        2300
      ],
      "subscription": [
        0,
        0
      ]
    }
  },
  "transactions": [
    {
      "id": "clx0rd3r000001sale",
      "productId": "clxdr0p000001prod",
      "productName": "Beach set — 6 photos",
      "amountCents": 2000,
      "grossAmountCents": 2500,
      "buyerEmail": "buyer@example.com",
      "buyerName": null,
      "paidAt": "2026-08-18T21:03:00.000Z",
      "type": "drop"
    }
  ]
}

Errors

StatusBodyWhen
400{"error":"startDate and endDate query params are required (YYYY-MM-DD)"}Either date param is missing.
401{"error":"Unauthorized","code":"unauthorized"}Missing or invalid API key.
500{"error":"Failed to fetch earnings"}Query failed — retry later.
400{"error":"X-Dropfans-Account must be an account id (from GET /api/external/agency/creators), not a username.","code":"invalid_account_header"}`X-Dropfans-Account` is not an account id.
400{"error":"X-Dropfans-Account names a different account than the path — send one or the other.","code":"account_mismatch"}Called under /v1/creators/{creatorId}/ with an `X-Dropfans-Account` naming another account.
403{"error":"This key cannot act for that account.","code":"account_not_managed"}The creator in the path (or `X-Dropfans-Account`) is one this key cannot act for: no ACCEPTED management by your agency and not an account your app onboarded (or it no longer holds a key bound to your app), a key minted for one creator, or someone is suspended, banned or deleted. An unknown id gets the same answer.
403{"error":"The agency does not have permission for this on that account.","code":"permission_denied","permission":"canViewStats"}For a managed creator: the agency lacks `canViewStats` on that account.
403{"error":"This app does not have the earnings API category enabled. Contact support to enable it.","code":"api_category_disabled","category":"earnings"}Your app has the Earnings & balance [API category](/developers/concepts/api-categories) switched off.

Rate limiting

Every response carries the X-RateLimit-Tier header and, on limited tiers, the per-minute and per-day trios — read X-RateLimit-Remaining and X-RateLimit-Reset instead of hardcoding limits. Details in Rate limits.

Code samples

curl "https://www.dropfans.io/api/external/v1/earnings?startDate=2026-08-01&endDate=2026-08-19&tz=Europe%2FStockholm" \
  -H "Authorization: Bearer $DROPFANS_API_KEY"

Notes

Chart bucketing: day for spans ≤31 days, week ≤90, month beyond. transactions[].productId only exists on type "drop" — use it to join a sale back to the drop your app created. Because refunds are excluded here but NOT in check-status, the two can legitimately disagree.

Questions? support@dropfans.io