Core resources
Reports
Clicks, conversions and earnings for a date range, grouped by program, channel, day or sub ID.
The report row
A report row is one slice of your traffic for a date range (a program, a channel, a day or a sub ID) with its clicks, conversions and earnings.
Every row has clicks, conversions, conversionRate and earnings. The key fields in front of them depend on groupBy.
programIdintegergroupBy=program only, alongside merchantName (string | null).
channelIdintegergroupBy=channel only, alongside channelName (string | null).
datestringgroupBy=day only. A UTC day as YYYY-MM-DD.
subIdstring | nullgroupBy=subId only. Null collects clicks on links minted without a sub ID.
clicksintegerClicks recorded in the range.
conversionsinteger | nullConversions reported in the range, rejected ones excluded. Null for groupBy=subId.
conversionRatenumber | nullconversions as a percentage of clicks, rounded to one decimal, so 2.3 means 2.3%. Null when the row has no clicks, and always null for groupBy=subId.
earningsobject[]One entry per currency, never summed across currencies. Empty when the row has no conversions.
earnings[].currencystring | nullISO 4217 code the network reported the commission in. Null when the network did not say.
earnings[].commissionstringWhat you have earned: conversions that are approved, available or ready_for_payout. A two-decimal string.
earnings[].pendingstringConversions that are still pending, reported by the network but not yet approved. A two-decimal string.
Money stays in its own currency
earnings entries. Convert them yourself if you need one total. We never add USD to CAD.{
"programId": 4821,
"merchantName": "Northpeak Outdoors",
"clicks": 4180,
"conversions": 96,
"conversionRate": 2.3,
"earnings": [
{ "currency": "USD", "commission": "742.18", "pending": "210.40" },
{ "currency": "CAD", "commission": "58.90", "pending": "0.00" }
]
}Performance report
https://api.linkapprove.com/v1/reports/performancereports:readReturns a paginated list of report rows for your account across every channel. Only programs you have applied to on one of your channels contribute.
startDatestringrequiredStart of the range as YYYY-MM-DD, inclusive.
endDatestringrequiredEnd of the range as YYYY-MM-DD, inclusive. On or after startDate, and the range may cover at most 180 days.
groupByenumprogram, channel, day or subId. Defaults to program.
pageinteger1-based page number. Defaults to 1.
sizeintegerRows per page, 1–100. Defaults to 10.
When it fails
400startDate is requiredorendDate is required: both dates are mandatory.400startDate must be YYYY-MM-DDorstartDate is not a real date: the same two checks apply toendDate.400endDate must not be before startDateorThe range may cover at most 180 days: reported againstendDate. Split a longer period into several requests.400groupBy is invalid: anything other than the four groupings.403insufficient_scope: the key does not holdreports:read.
curl "https://api.linkapprove.com/v1/reports/performance?startDate=2026-08-01&endDate=2026-08-18&groupBy=program&page=1&size=10" \
-H "Authorization: Bearer $LINKAPPROVE_API_KEY"https://api.linkapprove.com/v1/reports/performance?startDate=2026-08-01&endDate=2026-08-18&groupBy=program&page=1&size=10Held in this tab's session storage only, and reused by every runner on the site.
This panel replays the documented sample response and does not call the API. Copy a code sample to send a real request with your key.
{
"success": false,
"message": "Validation failed",
"error": [
{
"field": "endDate",
"code": "invalid_format",
"message": "The range may cover at most 180 days"
}
]
}Grouping
groupBy decides what a row is. Each grouping puts its own key in front of the common fields.
program:programIdandmerchantName. The default.channel:channelIdandchannelName.day:date, one row per UTC day that had a click or a conversion. Clicks count on the day they happened, conversions on the date the network reported for them.subId:subIdfrom the tracking link. Clicks only: sub IDs are not sent to networks, soconversionsandconversionRatearenullandearningsis empty. See Sub IDs and attribution.
Ordering
day rows come back oldest first. Every other grouping is sorted by clicks, highest first. Days with no activity are not filled in, so a gap in the dates means nothing happened.
{
"success": true,
"message": "Report fetched",
"data": {
"data": [
{
"date": "2026-08-01",
"clicks": 233,
"conversions": 4,
"conversionRate": 1.7,
"earnings": [
{ "currency": "USD", "commission": "31.20", "pending": "12.75" }
]
},
{
"date": "2026-08-02",
"clicks": 0,
"conversions": 1,
"conversionRate": null,
"earnings": [
{ "currency": null, "commission": "0.00", "pending": "6.30" }
]
}
],
"count": 2,
"pages": 1
}
}Data freshness
- Clicks are written in batches, so they show up within about ten minutes.
- Conversions appear as networks report them, and move from
pendingintocommissionas networks approve them. Yesterday's numbers can still change. - A conversion the network rejects drops out of
conversionsand out of both earnings figures.
Re-pull recent days