Skip to content

Affiliate Reports API

GET /v1/reports/*

Fetch affiliate analytics data for a business. Supports multiple data sections (stats, trends, charts, tables, and paginated activity feeds), each with optional metric filtering and date range scoping.

Authentication

All endpoints require a Bearer access token with the reports:read scope.

text
Authorization: Bearer <access_token>

Endpoints

MethodPathScopeThrottleDescription
GET/v1/reports/statsreports:read120/minAggregate statistics and trends
GET/v1/reports/commission-chartreports:read120/minTime-series data for charting
GET/v1/reports/top-affiliatesreports:read120/minTop affiliates by earnings
GET/v1/reports/clicks-by-campaignreports:read120/minClicks grouped by campaign
GET/v1/reports/payoutsreports:read120/minPayout history (paginated)
GET/v1/reports/exportreports:read30/minCSV export of report data

Common Query Parameters

Most report endpoints share these optional date range filters:

ParameterTypeDefaultConstraintsDescription
fromdate30 days agoYYYY-MM-DDStart of date range
todatetodayYYYY-MM-DD, must be >= fromEnd of date range

Report Stats — GET /v1/reports/stats

Returns aggregated summary statistics and period-over-period trend data.

Example

bash
curl "https://heldsway.com/api/v1/reports/stats?from=2026-03-17&to=2026-04-16" \
  -H "Authorization: Bearer <access_token>"

Success Response — HTTP 200

json
{
  "success": true,
  "message": "Report statistics retrieved.",
  "data": {
    "total_commission_paid": 28.00,
    "pending_payouts": 14.00,
    "conversion_rate": 3.2,
    "total_referral_clicks": 2,
    "trends": {
      "commission_paid": 14.0,
      "pending_payouts": 0.0,
      "conversion_rate": 1.1,
      "referral_clicks": -8.3
    },
    "filters": {
      "from": "2026-03-17",
      "to": "2026-04-16"
    }
  }
}

Response Fields

FieldTypeDescription
total_commission_paidnumberSum of commission_amount from approved conversions in the date range
pending_payoutsnumberApproved commission minus completed payouts (owed but not yet paid)
conversion_ratenumberPercentage of referral clicks that resulted in a conversion
total_referral_clicksintegerTotal distinct referral click sessions in the date range
trends.commission_paidnumber% change vs previous period (positive = increase)
trends.pending_payoutsnumberReserved — always 0.0 (trend requires payout history)
trends.conversion_ratenumberAbsolute percentage-point change vs previous period
trends.referral_clicksnumber% change vs previous period
filters.fromstringApplied start date (YYYY-MM-DD)
filters.tostringApplied end date (YYYY-MM-DD)

Trend Calculation

Trends compare the requested date range against the immediately preceding period of equal length. For example, if from=2026-03-17 and to=2026-04-16 (31 days), the previous period is 2026-02-14 to 2026-03-16.

  • Commission and clicks: ((current - previous) / previous) * 100, rounded to 1 decimal place. Returns 0.0 when the previous period value is zero.
  • Conversion rate: Absolute difference in percentage points (current_rate - previous_rate), rounded to 1 decimal place.

Commission Chart — GET /v1/reports/commission-chart

Returns time-series data for rendering a commission-over-time bar chart. Supports daily, weekly, or monthly granularity.

Query Parameters

ParameterTypeRequiredDefaultConstraintsDescription
fromdateNo30 days agoYYYY-MM-DDStart of date range
todateNotodayYYYY-MM-DDEnd of date range
granularitystringNodailydaily, weekly, monthlyTime bucket size

Example

bash
curl "https://heldsway.com/api/v1/reports/commission-chart?from=2026-04-01&to=2026-04-16&granularity=daily" \
  -H "Authorization: Bearer <access_token>"

Success Response — HTTP 200

json
{
  "success": true,
  "message": "Commission chart data retrieved.",
  "data": {
    "granularity": "daily",
    "labels": ["Apr 01", "Apr 02", "Apr 03", "Apr 04", "Apr 05"],
    "data": [4.50, 0.00, 12.00, 0.00, 7.00],
    "filters": {
      "from": "2026-04-01",
      "to": "2026-04-16"
    }
  }
}

Response Fields

FieldTypeDescription
granularitystringApplied granularity (daily, weekly, or monthly)
labelsstring[]Human-readable time bucket labels
datanumber[]Sum of commission_amount for each time bucket (2 decimal places)
filters.fromstringApplied start date
filters.tostringApplied end date

Label Format by Granularity

GranularityFormatExample
dailyMMM DDApr 01
weeklyMMM DD – MMM DDApr 01 – Apr 07
monthlyMMM YYYYApr 2026

Empty time buckets are filled with 0.00 to ensure the chart has no gaps.


Top Affiliates — GET /v1/reports/top-affiliates

Returns the top-performing affiliates ranked by commission earned within the date range. Only affiliates with at least one conversion or click in the period are included.

Query Parameters

ParameterTypeRequiredDefaultConstraintsDescription
fromdateNo30 days agoYYYY-MM-DDStart of date range
todateNotodayYYYY-MM-DDEnd of date range
limitintegerNo101–50Maximum number of affiliates to return

Example

bash
curl "https://heldsway.com/api/v1/reports/top-affiliates?from=2026-03-17&to=2026-04-16&limit=5" \
  -H "Authorization: Bearer <access_token>"

Success Response — HTTP 200

json
{
  "success": true,
  "message": "Top affiliates retrieved.",
  "data": {
    "items": [
      {
        "affiliate_id": 1,
        "name": "Salman",
        "referral_code": "SALMAN2026",
        "earned": 140.00,
        "clicks": 2,
        "conversions": 5
      }
    ],
    "filters": {
      "from": "2026-03-17",
      "to": "2026-04-16"
    }
  }
}

Response Fields

FieldTypeDescription
items[].affiliate_idintegerAffiliate record ID
items[].namestringAffiliate user's display name
items[].referral_codestringAffiliate's referral code
items[].earnednumberTotal commission earned in the date range (2 decimal places)
items[].clicksintegerTotal referral clicks attributed to this affiliate
items[].conversionsintegerTotal conversions attributed to this affiliate
filters.fromstringApplied start date
filters.tostringApplied end date

Clicks by Campaign — GET /v1/reports/clicks-by-campaign

Returns referral click counts grouped by the campaign tag on referral links. All active campaigns for the business are included, even those with zero clicks in the date range.

Query Parameters

ParameterTypeRequiredDefaultConstraintsDescription
fromdateNo30 days agoYYYY-MM-DDStart of date range
todateNotodayYYYY-MM-DDEnd of date range
limitintegerNo101–50Maximum number of campaigns to return

Example

bash
curl "https://heldsway.com/api/v1/reports/clicks-by-campaign?from=2026-03-17&to=2026-04-16" \
  -H "Authorization: Bearer <access_token>"

Success Response — HTTP 200

json
{
  "success": true,
  "message": "Clicks by campaign retrieved.",
  "data": {
    "items": [
      {
        "campaign": "mountain_rentals_brand",
        "clicks": 0
      },
      {
        "campaign": "women_skier_interest",
        "clicks": 0
      },
      {
        "campaign": "winter_sale",
        "clicks": 0
      },
      {
        "campaign": null,
        "clicks": 2
      }
    ],
    "filters": {
      "from": "2026-03-17",
      "to": "2026-04-16"
    }
  }
}

Response Fields

FieldTypeDescription
items[].campaignstring|nullCampaign tag from the referral link (null = links with no campaign assigned)
items[].clicksintegerTotal referral clicks for links with this campaign tag
filters.fromstringApplied start date
filters.tostringApplied end date

Results are ordered by clicks descending. The null campaign entry (representing links without a campaign tag) is always listed last.


Payouts — GET /v1/reports/payouts

Returns a paginated list of payout records with optional filtering by status and affiliate.

Query Parameters

ParameterTypeRequiredDefaultConstraintsDescription
fromdateNo30 days agoYYYY-MM-DDStart of date range
todateNotodayYYYY-MM-DDEnd of date range
statusstringNoallpending, completed, failedFilter by payout status
affiliate_idintegerNoallAffiliate IDFilter by affiliate
per_pageintegerNo151–100Items per page
pageintegerNo1min:1Page number

Example

bash
curl "https://heldsway.com/api/v1/reports/payouts?status=completed&per_page=10" \
  -H "Authorization: Bearer <access_token>"

Success Response — HTTP 200

json
{
  "success": true,
  "message": "Payouts retrieved.",
  "data": {
    "items": [
      {
        "id": 1,
        "affiliate_id": 1,
        "affiliate_name": "Salman",
        "amount": 28.00,
        "currency": "USD",
        "method": "bank_transfer",
        "status": "completed",
        "reference": "TXN-20260410-001",
        "paid_at": "2026-04-10T14:30:00.000000Z",
        "created_at": "2026-04-10T14:00:00.000000Z"
      }
    ],
    "meta": {
      "current_page": 1,
      "per_page": 15,
      "total": 1,
      "last_page": 1
    },
    "filters": {
      "from": "2026-03-17",
      "to": "2026-04-16"
    }
  }
}

Response Fields

FieldTypeDescription
items[].idintegerPayout record ID
items[].affiliate_idintegerAffiliate record ID
items[].affiliate_namestringAffiliate user's display name
items[].amountnumberPayout amount (2 decimal places)
items[].currencystring3-letter currency code (default USD)
items[].methodstring|nullPayment method (bank_transfer, paypal, check, other)
items[].statusstringpending, completed, or failed
items[].referencestring|nullExternal transaction reference/ID
items[].paid_atstring|nullISO 8601 timestamp when payment was completed (null if pending/failed)
items[].created_atstringISO 8601 timestamp of payout record creation
meta.current_pageintegerCurrent page number
meta.per_pageintegerItems per page
meta.totalintegerTotal matching records
meta.last_pageintegerLast available page

Date Range Behavior

Date range filters are applied differently based on payout status:

  • Completed payouts: filtered by paid_at (when the payment was made)
  • Pending/failed payouts: filtered by created_at (when the payout was recorded)

This ensures completed payouts appear in the period they were paid, not when they were initially created.


Export Report — GET /v1/reports/export

Downloads a CSV file containing report data. By default exports all sections; use the sections parameter to select specific sections.

Query Parameters

ParameterTypeRequiredDefaultConstraintsDescription
fromdateNo30 days agoYYYY-MM-DDStart of date range
todateNotodayYYYY-MM-DDEnd of date range
sectionsstringNoallComma-separated listSections to include in the export

Available Sections

Section KeyDescription
statsHeadline metrics with trend percentages
commission_chartCommission over time (daily granularity)
top_affiliatesTop affiliates ranked by earnings
clicks_by_campaignClick counts grouped by campaign
payoutsPayout history

Example

bash
curl "https://heldsway.com/api/v1/reports/export?from=2026-04-01&to=2026-04-16&sections=stats,top_affiliates" \
  -H "Authorization: Bearer <access_token>" \
  -o affiliate-reports.csv

Success Response — HTTP 200

Content-Type: text/csvContent-Disposition: attachment; filename="affiliate-reports-2026-04-16.csv"

csv
"--- Report Stats ---"
Metric,Value,Trend (%)
Total Commission Paid,28.00,14.0
Pending Payouts,14.00,0.0
Conversion Rate (%),3.2,1.1
Total Referral Clicks,2,-8.3

"--- Top Affiliates ---"
Name,Referral Code,Earned,Clicks,Conversions
Salman,SALMAN2026,140.00,2,5

"--- Clicks by Campaign ---"
Campaign,Clicks
mountain_rentals_brand,0
women_skier_interest,0
winter_sale,0
(no campaign),2

"--- Commission Over Time (daily) ---"
Date,Commission
Apr 01,4.50
Apr 02,0.00
Apr 03,12.00

"--- Payouts ---"
Affiliate,Amount,Currency,Method,Status,Reference,Paid At,Created At
Salman,28.00,USD,bank_transfer,completed,TXN-20260410-001,2026-04-10 14:30:00,2026-04-10 14:00:00

CSV Structure

  • Each section is separated by a header row in the format --- Section Name ---
  • Sections appear in the order: stats, top affiliates, clicks by campaign, commission chart, payouts
  • When sections is specified, only the requested sections appear
  • Unknown section keys in the sections parameter are silently ignored
  • Payout timestamps use YYYY-MM-DD HH:MM:SS format (not ISO 8601)

Payout Status Workflow

text
  ┌─────────┐
  │ pending │ ← initial state (payout recorded)
  └────┬────┘

  ┌────┴────┐
  ▼         ▼
┌─────────┐ ┌────────┐
│completed│ │ failed │
└─────────┘ └────────┘
  • pending: Payout has been recorded but not yet processed
  • completed: Payment was successfully processed (paid_at is set)
  • failed: Payment processing failed

Error Reference

HTTP StatusError CodeCause
401UNAUTHORIZEDMissing or invalid Bearer token
403FORBIDDENToken does not have reports:read scope
422VALIDATION_ERRORInvalid query parameters (bad date format, invalid granularity, etc.)
429Rate limit exceeded
500REPORT_ERRORInternal error during report generation

Error Response Format

json
{
  "success": false,
  "error": {
    "code": "VALIDATION_ERROR",
    "message": "Validation failed",
    "details": {
      "granularity": ["The selected granularity is invalid."]
    }
  }
}

Rate Limiting

Endpoint GroupLimit
Read endpoints (stats, chart, tables, payouts)120 requests/min
Export30 requests/min

Exceeding the limit returns HTTP 429 Too Many Requests.


Returns aggregate statistics for all referral links in your business.

GET /v1/links/stats

  • Required scope: affiliates:read
  • Rate limit: 120 requests/minute

Example Request

bash
curl "https://heldsway.com/api/v1/links/stats" \
  -H "Authorization: Bearer <access_token>"

Success Response — 200 OK

json
{
  "success": true,
  "message": "OK",
  "data": {
    "total": 42,
    "active": 38,
    "inactive": 4,
    "total_clicks": 1523
  }
}

Response Fields

FieldTypeDescription
totalintegerTotal number of referral links (active + inactive)
activeintegerLinks with is_active = true
inactiveintegerLinks with is_active = false
total_clicksintegerSum of click_count across all links

Note: Soft-deleted links are excluded from all counts. total_clicks is derived from the denormalized click_count field on each link, which is incremented in real time by the click tracking system.

Released under the MIT License.