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/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/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 — there is no pagination. To get a complete ledger, narrow the date window until fewer than 50 come back.

Authentication

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

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 a complete ledger, narrow the date window until fewer than 50 come back.
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": "[email protected]",
      "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.

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/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? [email protected]