Skip to content
Browse the docs

API

Reports

The same numbers your team sees in Viffy, from the same source.

Endpoints

GET/reports/summaryThe whole program over a range, by brand. Filter: brandId.
GET/campaigns/{id}/reportOne campaign: totals, a daily series, and its creators ranked (paged).
GET/reports/creator-countsOne row per creator per campaign for your payment process. Filters: brandId, campaignId.

All three take a range: preset, or from and through. See Conventions. Summary and campaign reports accept up to 366 inclusive days; creator counts have no 366-day cap.

Summary

Request and response
GET /reports/summary?preset=30d

{
  "range": { "from": "2026-08-13", "through": "2026-09-11", "timeZone": "America/Chicago", "preset": "30d" },
  "totals": {
    "activeCampaigns": 3, "campaigns": 5,
    "linkViews": 18420, "codesIssued": 2210, "verifiedRedemptions": 640,
    "redemptionRate": 0.2896
  },
  "brands": [
    { "brand": { "id": "9a2b835d-674e-48ab-b012-a93b6407c2e8", "name": "Example Brand" }, "campaigns": 2, "activeCampaigns": 1,
      "linkViews": 9100, "codesIssued": 1200, "verifiedRedemptions": 350, "redemptionRate": 0.2917 },
    { "brand": { "id": "4713e408-cf7b-43ec-a5e1-d9138b079f22", "name": "North Star Foods" }, "campaigns": 3, "activeCampaigns": 2,
      "linkViews": 9320, "codesIssued": 1010, "verifiedRedemptions": 290, "redemptionRate": 0.2871 }
  ]
}
  • The funnel is link views → codes issued → verified redemptions. Only counted redemptions are in it.
  • Ratios are null, not 0, when there is nothing to divide by.
  • Brand counts add up to the totals; calculate rates from the counts, not by summing or averaging brand rates.

Campaign report

GET /campaigns/{id}/report?preset=today: 200 response
{
  "range": { "from": "2026-09-11", "through": "2026-09-11", "timeZone": "America/Chicago", "preset": "today" },
  "campaign": { "id": "7c1e29a4-5b68-4d02-91f3-8a4c6e0b752d", "externalReference": "fall-launch-2026", "name": "Fall launch" },
  "brand": { "id": "9a2b835d-674e-48ab-b012-a93b6407c2e8", "name": "Example Brand" },
  "totals": { "linkViews": 100, "codesIssued": 20, "verifiedRedemptions": 5, "redemptionRate": 0.25 },
  "daily": [{ "date": "2026-09-11", "linkViews": 100, "codesIssued": 20, "verifiedRedemptions": 5 }],
  "creators": {
    "items": [{ "rank": 1, "creator": { "externalId": "cr-1042", "name": "Jane Doe" }, "active": true,
      "linkViews": 100, "codesIssued": 20, "verifiedRedemptions": 5, "conversionRate": 0.05 }],
    "page": 0, "pageSize": 50, "totalCount": 1
  }
}

daily includes every day in the range, including days with no activity. Dates use your organization’s reporting time zone.

creators contains a page of creators ranked by verified redemptions, with their activity. Use page and pageSize to read more creators; totals and daily figures still cover the whole campaign.

What the fields mean

FieldWhat it is
rangeObject { from, through, timeZone, preset }. Days include both endpoints; custom dates return preset: custom.
campaign / brand / creatorReferences: campaign { id, externalReference, name }, brand { id, name }, creator { externalId, name }. externalReference can be null.
totals.campaigns / brands[].campaignsInteger count of all campaigns matching the organization and brand filter, including campaigns with no activity in the selected range.
activeCampaignsInteger count currently marked active whose dates overlap the range. This does not reconstruct historical campaign status.
linkViewsInteger link opens in the range, counted once per network origin per link per reporting day. A shared connection can undercount individual shoppers.
codesIssued / verifiedRedemptionsInteger shopper codes handed out and counted redemptions, each by its own date. Staff test activity is excluded; excluded redemptions are omitted from redemption totals.
redemptionRateDecimal verifiedRedemptions / codesIssued, or null with no issued codes. It can exceed 1 because codes issued earlier may redeem in this range.
creators.items[].conversionRateDecimal verifiedRedemptions / linkViews, or null with no views.
creators.items[].rank / activeInteger position in the ranked campaign list and boolean link status, independent of roster status.
daily[].dateCalendar day in range.timeZone; daily entries also include integer linkViews, codesIssued, and verifiedRedemptions.

Creator counts

Request and response
GET /reports/creator-counts?from=2026-09-01&through=2026-09-30

{
  "range": { "from": "2026-09-01", "through": "2026-09-30", "timeZone": "America/Chicago", "preset": "custom" },
  "items": [
    {
      "creator": { "externalId": "cr-1042", "name": "Jane Doe" },
      "campaign": { "id": "7c1e29a4-5b68-4d02-91f3-8a4c6e0b752d", "externalReference": "fall-launch-2026", "name": "Fall launch" },
      "brand": { "id": "9a2b835d-674e-48ab-b012-a93b6407c2e8", "name": "Example Brand" },
      "verifiedRedemptions": 42
    }
  ],
  "page": 0, "pageSize": 50, "totalCount": 1
}

These rows match the creator-count CSV for the same dates and filters. Each creator with a campaign link appears, including creators with zero redemptions or paused links.

Read every page using page and pageSize. totalCount counts creator-campaign rows, so a creator on two campaigns appears twice.