Dashboard stats
Your integration dashboard’s Dashboard tab as data: revenue, booked commission, sales and new accounts, as totals plus zero-filled hour, day, week or month buckets.
/api/external/crm/statsNewYour integration dashboard’s Dashboard tab as data: revenue, booked commission, sales and new accounts, as totals plus zero-filled hour, day, week or month buckets.
It returns revenue through your app’s links, the commission booked for your app owner, sales and newly connected accounts. The numbers are the dashboard’s own: same sales, same day boundaries (Europe/Stockholm unless you pass tz), same automatic bucket size. Amounts are integer US cents, excluding tax, before our platform fee; refunded and charged-back sales are left out. earningsCents is the commission booked on those sales — it is paid out with your app owner’s earnings, so booked is not the same as already paid.
Authentication
Send the creator's API key as a bearer token: Authorization: Bearer dpfn_…. See Authentication & API keys.
Query parameters
| Name | Type | Required | Description |
|---|---|---|---|
startDate | string | Required | First day, YYYY-MM-DD (inclusive, in tz).Format: date |
endDate | string | Required | Last day, YYYY-MM-DD (inclusive, in tz). At most 366 days after startDate.Format: date |
tz | string | Optional | IANA time zone the calendar days (and buckets) are cut in. Defaults to Europe/Stockholm, like your dashboard. Default: "Europe/Stockholm"Format: iana-timezone |
granularity | string | Optional | Bucket size. Leave it out for the dashboard’s automatic pick (hour for one day, day up to 30 days, week up to 90, month beyond). hour is allowed for up to 3 days.One of: hour, day, week, month |
Responses
| Name | Type | Description | ||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
startDate | string | As requested. Format: date | ||||||||||||||||||
endDate | string | As requested. Format: date | ||||||||||||||||||
tz | string | The zone days and buckets are cut in. Format: iana-timezone | ||||||||||||||||||
granularity | string | Bucket size used (the one you asked for, or the automatic pick). One of: hour, day, week, month | ||||||||||||||||||
currency | string | Currency of every *Cents field. One of: USD | ||||||||||||||||||
totals | object | The whole range. Counts equal the sum of series; cent amounts are rounded once over the range, so they can differ from the summed buckets by a cent.Show child attributes
| ||||||||||||||||||
series | CrmStatsBucket[] | Every bucket of the range, oldest first, zero-filled.Show child attributes
|
{
"startDate": "2026-10-27",
"endDate": "2026-10-29",
"tz": "Europe/Stockholm",
"granularity": "day",
"currency": "USD",
"totals": {
"revenueCents": 6000,
"earningsCents": 300,
"transactions": 4,
"newConnectedAccounts": 1,
"connectedAccountsNow": 18
},
"series": [
{
"bucket": "2026-10-27",
"start": "2026-10-26T23:00:00.000Z",
"revenueCents": 0,
"earningsCents": 0,
"transactions": 0,
"newConnectedAccounts": 0
},
{
"bucket": "2026-10-28",
"start": "2026-10-27T23:00:00.000Z",
"revenueCents": 4500,
"earningsCents": 225,
"transactions": 3,
"newConnectedAccounts": 1
},
{
"bucket": "2026-10-29",
"start": "2026-10-28T23:00:00.000Z",
"revenueCents": 1500,
"earningsCents": 75,
"transactions": 1,
"newConnectedAccounts": 0
}
]
}Errors
| Status | Body | When |
|---|---|---|
| 400 | {"error":"startDate must be a real calendar day, YYYY-MM-DD.","code":"invalid_input","field":"startDate"} | `startDate` / `endDate` missing (stats) or not a YYYY-MM-DD day. |
| 400 | {"error":"endDate must be on or after startDate.","code":"invalid_input","field":"endDate"} | `endDate` is before `startDate`. |
| 400 | {"error":"The range can be at most 366 days.","code":"invalid_input","field":"endDate"} | More than 366 days. |
| 400 | {"error":"tz must be an IANA time zone, e.g. Europe/Stockholm or America/New_York.","code":"invalid_input","field":"tz"} | Unknown `tz`. |
| 400 | {"error":"granularity=hour is only allowed for ranges of up to 3 days.","code":"invalid_input","field":"granularity"} | `granularity=hour` over more than 3 days, or an unknown granularity. |
| 401 | {"error":"Unauthorized","code":"unauthorized"} | Missing or invalid API key. |
| 403 | {"error":"This endpoint needs a key bound to an approved app.","code":"app_key_required"} | A Personal key was used. |
| 403 | {"error":"Use the app owner's key for this endpoint.","code":"owner_key_required"} | The key was minted by a creator for themselves. App-level calls need a key held by your app owner: their own, or one their agency minted for its personas or managed creators. |
| 400 | {"error":"This endpoint only acts as the key’s own account — send it without X-Dropfans-Account.","code":"account_header_not_allowed"} | `X-Dropfans-Account` was sent. These endpoints always answer for the key’s app. |
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/crm/stats?startDate=2026-10-01&endDate=2026-10-30&tz=America%2FNew_York" \
-H "Authorization: Bearer $DROPFANS_API_KEY"const res = await fetch(`https://www.dropfans.io/api/external/crm/stats?startDate=2026-10-01&endDate=2026-10-30&tz=America%2FNew_York`, {
headers: {
Authorization: `Bearer ${process.env.DROPFANS_API_KEY}`,
},
});
console.log(await res.json());import os
import requests
res = requests.get(
"https://www.dropfans.io/api/external/crm/stats",
headers={"Authorization": f"Bearer {os.environ['DROPFANS_API_KEY']}"},
params={"startDate": "2026-10-01", "endDate": "2026-10-30", "tz": "America/New_York"},
)
print(res.json())Notes
Buckets are local to tz: on a day the clocks go forward there are 23 hourly buckets; on a day they go back the repeated hour is a single bucket (24). Each bucket’s start is its exact UTC instant.
Questions? [email protected]
