Reporting API
The report endpoint returns totals rather than individual leads: new leads and CRM statuses reached, per day (or for a whole period) and per channel or UTM source, medium or campaign. It is the simplest way to feed a dashboard.
You need an API key and the project ID.
Request
GET https://api.tagpilot.io/integrations/v1/lead-tracking/projects/{projectId}/report
| Parameter | Values | Default |
|---|---|---|
from, to |
First and last day as YYYY-MM-DD, both included; at most 366 days |
required |
timezone |
IANA time zone the days are cut in, e.g. Europe/Warsaw |
UTC |
granularity |
day for a row per day, total for the whole period |
day |
group_by |
Comma-separated: channel, utm_source, utm_medium, utm_campaign; empty for no grouping |
channel |
curl -H "Authorization: Bearer $TAGPILOT_KEY" -H "User-Agent: acme-dashboard/1.0" \
"https://api.tagpilot.io/integrations/v1/lead-tracking/projects/$PROJECT_ID/report?from=2026-10-01&to=2026-10-07&timezone=Europe/Warsaw&group_by=channel"
Response
{
"from": "2026-10-01",
"to": "2026-10-07",
"timezone": "Europe/Warsaw",
"granularity": "day",
"group_by": ["channel"],
"statuses": ["Client", "Prospect", "Suspect"],
"rows": [
{ "date": "2026-10-01", "channel": "Paid Search", "leads": 4, "statuses": { "Client": 0, "Prospect": 1, "Suspect": 3 } },
{ "date": "2026-10-01", "channel": "Organic Social", "leads": 2, "statuses": { "Client": 0, "Prospect": 0, "Suspect": 1 } },
{ "date": "2026-10-01", "channel": "Not tracked", "leads": 0, "statuses": { "Client": 1, "Prospect": 2, "Suspect": 9 } }
],
"totals": { "leads": 6, "statuses": { "Client": 1, "Prospect": 3, "Suspect": 13 } }
}
| Field | Meaning |
|---|---|
statuses |
Every CRM status reached in the period; each row has a count for each |
rows[].date |
The day, in timezone (only with granularity=day) |
rows[].channel, utm_* |
The group, one field per group_by dimension |
rows[].leads |
Leads whose first form submission was on that day |
rows[].statuses |
Leads that reached each CRM status on that day |
totals |
The same counts for the whole period |
Rows are ordered by day, then by the most leads. Days and groups with nothing to count are left out, so fill gaps with zeros in your chart.
How leads are counted
- New leads count on the day of the person's first form submission. A second form from the same email address is not a new lead.
- Statuses count on the day your CRM says the lead reached them. They are credited to the source of the lead's last form submission before that day (last click), the same source the conversion sent to ad platforms is credited to.
- Not tracked holds statuses of leads your CRM knows but who never submitted a tracked form before reaching that status, for example leads from sales calls or events.
- Past days stay fixed: a lead that becomes a client today adds to today's
Clientcount, not to the day it first arrived.
If your CRM sends status changes without a timestamp, they are dated when Tag Pilot receives them, so days are only as precise as your CRM sync interval.
Sources and channels
A form submission's source is taken from, in this order: the form page's UTM parameters or ad click ID; the visitor's landing page before the form (its UTMs, click ID or referrer); the external site that referred the form page; an ad click ID kept in the ad platforms' cookies; otherwise (direct).
An ad click ID without UTMs reads like Google Analytics auto-tagging: gclid becomes google / cpc, msclkid becomes bing / cpc. fbclid alone counts as organic, because Meta adds it to organic links too. A referrer becomes the site's host with medium organic for search engines and referral otherwise.
Channels follow the Google Analytics 4 default channel group:
| Channel | When |
|---|---|
| Paid Search | Google or Microsoft Ads click ID, or a search engine source with a paid medium (cpc, ppc, paid…) |
| Paid Social | TikTok, LinkedIn, X, Reddit, Pinterest or Snapchat click ID; a social source with a paid medium; or medium paid_social |
| Display | Medium display, banner, cpm, or a Google dclid |
| Paid Other | Any other paid medium |
Source or medium email, newsletter, or a webmail referrer |
|
| Organic Search | Medium organic, or a search engine source |
| Organic Social | Medium social, or a social network source (Facebook, Instagram, LinkedIn, X, TikTok, YouTube, …) |
| Affiliates | Medium affiliate |
| Referral | Medium referral, e.g. another website linking to yours |
| Direct | No source at all |
| Unassigned | UTMs that match none of the above |
| Not tracked | No form submission before the status (see above) |
When a link has UTM parameters, they decide the channel, source and medium, even if an ad click ID is present too.
Examples
Totals per channel for October:
…/report?from=2026-10-01&to=2026-10-31&granularity=total
Daily leads per campaign:
…/report?from=2026-10-01&to=2026-10-31&group_by=utm_source,utm_medium,utm_campaign
Daily totals with no grouping:
…/report?from=2026-10-01&to=2026-10-31&group_by=