v1
latestOpenAPI 3.0.12026-08-06241391671.8 KBReturns aggregated report grouped by the specified dimension(s).
Returns aggregated performance data grouped by the specified dimension(s). This is the primary reporting endpoint for campaign analytics.
Prerequisites
Before building report queries, call these endpoints to discover account-specific configuration:
- GET /column/info — returns all valid groupBy dimensions (canGroupBy: true) and metric columns with their display labels and types.
- GET /custom-conversions — returns custom conversion type definitions (index 1-20 mapping to customConversions{N} and customRevenue{N} columns).
- GET /custom-columns — returns user-defined derived metric names that can be passed as column values alongside built-in metrics.
- GET /traffic-source — returns each source's customVariables[] array, where every entry carries index, name (user-facing label) and parameter (the URL parameter the source sends on the click). Variable meanings are defined per traffic source — the same slot index can mean different things on different sources.
Key behaviors
- Date range is half-open [from, to): the 'to' date is exclusive. To query March 5 in full, set from=2026-03-05T00:00:00Z and to=2026-03-06T00:00:00Z.
- Name columns must be requested explicitly: groupBy=campaignId only returns campaignId. Add campaignName to the column list to get human-readable names.
- Column is a repeated parameter: use column=visits&column=clicks, not column=visits,clicks.
- Drilldown filters: use filter1=campaignId&filter1Value=<id> to filter results. Multiple filters: filter1/filter1Value, filter2/filter2Value, etc.
Metric formulas
- CTR = clicks / visits (lander effectiveness)
- CR = conversions / clicks (offer quality)
- CV = conversions / visits (end-to-end funnel efficiency)
- ROI = (revenue - cost) / cost (expressed as percentage, e.g. 125.0 = 125%)
- CPA = cost / conversions
- EPV = revenue / visits
- EPC = revenue / clicks
- CPV = cost / visits
Direct-linking campaigns
Campaigns without a lander (direct-linking) never record click events. CTR, CR, clicks, and EPC are always zero — this is expected, not a tracking error. Use CV (conversions/visits) and EPV (revenue/visits) instead. Detection: inspect the campaign's flow for lander presence (GET /campaign/{id}), or run groupBy=landerId filtered to the campaign — if no landers appear, it is direct-linking.
This endpoint vs /report/conversions
This endpoint returns aggregated data grouped by dimensions. For individual conversion events (no grouping), use GET /report/conversions instead — that endpoint does not accept groupBy, conversionTimeMode, or include parameters.
Rate limits and response size
Throttling applies at three levels:
Per Bearer token (per user) — three independent buckets:
| Bucket | Base allocation | Notes |
|---|---|---|
| Per-second (burst) | ~4 req/s | Hit first by most clients |
| Concurrent in-flight | ~30 | Counted while a request is on the wire |
| Per-minute (sustained) | Higher; rarely the binding cap | Only hit if you sustain perfectly even pacing |
Base allocation only — many accounts have higher negotiated limits. Contact support for your values.
Per IP — anti-abuse cap; authenticated clients from a single host should not normally hit it.
Per-user utilization budget (reports only) — independent of request count. Heavier queries (longer date ranges, wider groupBy, more column values) cost more; light queries cost little. Often the binding cap on heavy analytics workloads — prefer many narrow queries over a few enormous ones if you see 429s without exceeding the per-second cap.
Exceeding any of these returns 429 Too Many Requests with an empty body and no Retry-After header. Back off and retry.
Per-request row cap: see the limit query parameter. Per-account caps and throttling thresholds are configurable; contact support to raise them.
Query parameters
Controls which entities appear in the report. Default: TRAFFIC.
- ALL — all entities, including those with no traffic in the period
- ACTIVE — only active (non-archived) entities, including those with no traffic
- ARCHIVED — only archived entities, including those with no traffic
- TRAFFIC — only rows with non-zero traffic events (excludes entities with no traffic)
Entities with no traffic in the period are returned for every value except TRAFFIC.
Pagination offset (zero-based). Default: 0.
Time zone for date aggregation, e.g. 'America/New_York', 'Europe/Warsaw', or 'Etc/GMT'. Default: Etc/GMT. Affects how day, dayOfWeek, and hourOfDay boundaries are calculated.
Columns to include in the response. Repeated query parameter — use column=visits&column=clicks, NOT comma-separated.
Volume: visits, clicks, conversions, impressions, uniqueVisits, uniqueClicks
Financial: revenue, cost, profit
Rate/efficiency metrics (with formulas):
| Column | Formula | Note |
|---|---|---|
| ctr | clicks / visits | Lander effectiveness. Always 0 for direct-linking campaigns |
| cr | conversions / clicks | Offer quality. Always 0 for direct-linking campaigns |
| cv | conversions / visits | End-to-end funnel. The only rate metric valid for both lander and direct-linking |
| roi | (revenue-cost) / cost | Percentage, e.g. 125.0 = 125% ROI |
| cpa | cost / conversions | Cost per acquisition |
| epv | revenue / visits | Earnings per visit |
| epc | revenue / clicks | Always 0 for direct-linking campaigns |
| cpv | cost / visits | Cost per visit |
| cpc | cost / clicks | Cost per click |
Other rate metrics: ecpa, ecpc, ecpm, cpm, ap, rpm, sctr, ictr, viewRate
Quality: suspiciousVisits, suspiciousClicks, robotVisits
Entity names: campaignName, offerName, landerName, trafficSourceName, affiliateNetworkName, countryName, deviceName, connectionTypeName, languageName, flowName
Custom: customConversions1-20, customRevenue1-20 (discover via GET /custom-conversions). User-defined derived metrics (discover via GET /custom-columns).
No Name variant for self-labeling dimensions: region, city, os, osVersion, browser, browserVersion, isp, mobileCarrier, referrerDomain are already human-readable — there is no regionName/cityName/osName/browserName column, and requesting one returns 400. (Code/name pairs like countryCode/countryName and connectionType/connectionTypeName are the exception — those Name columns do exist.)
Tags: the tag column is campaignTags (also offerTags, landerTags) — plain tags is not a column.
To discover all available columns at runtime, call GET /column/info.
Drilldown filter dimension — a dimension column to filter the report by an EXACT value, e.g. campaignId. Pair with filter1Value. This is the correct, server-side way to scope a report to a single entity by id; the filter parameter only does free-text name search, which is fragile and can match the wrong row.
Start date/time (inclusive) for the comparison period. ISO 8601 format. Used for period-over-period analysis.
Second drilldown filter dimension (optional), e.g. countryCode. Pair with filter2Value.
Dimension(s) to group results by. Repeated parameter — use groupBy=campaignId&groupBy=countryCode, not comma-separated.
Call GET /column/info to discover all valid groupBy values for this account (filter response for canGroupBy: true). The list evolves — don't hardcode it.
Common examples: campaignId, offerId, landerId, trafficSourceId, affiliateNetworkId, countryCode, day, dayOfWeek, hourOfDay, month, device, os, browser, isp, referrerDomain, flowId, customVariable1 through customVariable10.
Name column mapping — grouping by an entity returns only the ID. You must request the name column explicitly via the 'column' parameter:
| groupBy | Name column to request |
|---|---|
| campaignId | campaignName |
| offerId | offerName |
| landerId | landerName |
| trafficSourceId | trafficSourceName |
| affiliateNetworkId | affiliateNetworkName |
| countryCode | countryName |
| device | deviceName |
| connectionType | connectionTypeName |
| language | languageName |
| flowId | flowName |
Custom variables: slot meanings are per-source (slot 1 may be zoneid on PropellerAds, pubid on Reacheffect). Discover labels via GET /traffic-source → each source's customVariables[] array. customVariable1..10 breakdowns must be scoped to a single campaign (or at least a single traffic source) via filter1=campaignId&filter1Value=<id>; unscoped breakdowns mix incompatible populations. The endpoint accepts unscoped queries — scoping is on the caller.
Group by the ID, not the Name — Name columns (campaignName, offerName, landerName, ...) have canGroupBy: false; grouping by one returns Could not find matching view. Group by the matching ID and request the Name as a column (see the table above).
Self-labeling dimensions — region, city, os, osVersion, browser, browserVersion, isp, mobileCarrier, referrerDomain return the human-readable value directly and have no Name variant. (Code/name pairs like countryCode/countryName and connectionType/connectionTypeName are the exception — see the table above.)
Common mistakes returning 400: deviceType (use device), campaignName and other Name columns (group by the ID instead — see above), conversion (use /report/conversions endpoint). canGroupBy: true is necessary but not sufficient — some flagged-groupable dimensions (e.g. category, externalCampaignId) still return Could not find matching view for a given account; treat that as a prompt to pick a different dimension, not a bug. Both referrer and referrerDomain are valid groupBy keys; prefer referrerDomain to avoid high-cardinality full-URL rows.
End date/time (exclusive) for the comparison period. ISO 8601 format. Same half-open semantics as the 'to' parameter.
Column name to sort by. Can be any valid metric or dimension column. Default: visits.
Exact value for filter1, e.g. the campaign id. Returns only rows matching this value.
Free-text substring search over NAME columns only (campaignName, offerName, ...). NOT for ids and NOT exact — a fragment can match several rows or none. To scope a report to a specific entity by id, use the drilldown filters filter1/filter1Value (e.g. filter1=campaignId, filter1Value=<id>); never put an id here.
Maximum rows to return per request. Default: 100. Values above the per-account cap are silently capped; totalRows always reflects the true count. Use offset to page through.
Start date/time (inclusive, required). ISO 8601 format, e.g. 2026-03-01T00:00:00Z.
Must be aligned to an hour boundary — minutes and seconds must be zero.
The date range is half-open [from, to) — 'from' is included in results.
Currency code for monetary values in the response, e.g. USD, EUR, GBP. Default: USD.
End date/time (EXCLUSIVE). ISO 8601 format. The date range is half-open [from, to) — 'to' is NOT included.
Must be aligned to an hour boundary — minutes and seconds must be zero.
Default: start of the next hour in the request timezone (e.g. if current time is 14:30, default to is 15:00). This means omitting to gives you data up to the current hour.
To query the full day of March 5, set to=2026-03-06T00:00:00Z (next day). Common mistake: setting to=2026-03-05T00:00:00Z returns zero results for March 5.
Exact value for filter2.
Workspace IDs to filter by. Only returns data for campaigns in the specified workspaces.
Controls how conversions are attributed in time. Default: VISIT.
- VISIT — attribute conversion to the time of the original visit (click time)
- CONVERSION — attribute conversion to the time the postback was received
Use VISIT when you want conversions aligned with the traffic that generated them. Not applicable to /report/conversions endpoint.
Period-over-period comparisons: use the same mode for both periods (e.g. WoW with compareFrom/compareTo). Mixing VISIT and CONVERSION produces fake late-funnel drops — conversions registered after the first period closes are visible under CONVERSION but invisible under VISIT.
Sort direction. Default: desc (descending).
Response
Aggregated report data.