Reports API
Pull advertiser and publisher statistics as JSON, grouped by up to four dimensions over up to 92 days, with readable names for ids.
The reports endpoint returns the same totals as the panel report, as JSON. Advertisers and publishers each have their own path. Both are relative to https://ulumob.com/api/v1:
GET /advertiser/reports
GET /publisher/reports
Each returns only your own data: advertisers see their own campaigns, publishers their own zones.
Parameters
| Parameter | Required | Format |
|---|---|---|
from |
Yes | YYYY-MM-DD |
to |
Yes | YYYY-MM-DD, on or after from, at most 92 days later |
group_by[] |
No | Up to four distinct dimensions. Default: date. |
geo |
No | ISO country code, two capital letters |
format |
No | An ad format, for example popunder or in_page_push |
os |
No | Operating system family, up to 20 characters |
device |
No | desktop, mobile, tablet or other |
campaign_id |
No | Campaign id (advertisers) |
zone_id |
No | Zone id |
website_id |
No | Website id |
subid |
No | Sub-ID, up to 100 characters |
Dimensions
| Dimension | Advertiser | Publisher |
|---|---|---|
date |
Yes | Yes |
geo |
Yes | Yes |
format |
Yes | Yes |
os |
Yes | Yes |
device |
Yes | Yes |
zone_id |
Yes | Yes |
website_id |
Yes | Yes |
subid |
Yes | Yes |
campaign_id |
Yes | No |
ad_id |
Yes | No |
website_id and subid cannot be used together with geo, format, os, device or ad_id, whether as a grouping or a filter. Such a request returns 422 with the message under errors.group_by. See Sub-IDs and sites for the reason.
Example
Daily cost per country for one campaign in October:
curl -G https://ulumob.com/api/v1/advertiser/reports \
-H "Authorization: Bearer YOUR_KEY" \
-H "Accept: application/json" \
--data-urlencode "from=2026-10-01" \
--data-urlencode "to=2026-10-31" \
--data-urlencode "group_by[]=date" \
--data-urlencode "group_by[]=geo" \
--data-urlencode "campaign_id=815"
Response
{
"group_by": ["date", "geo"],
"rows": [
{"date": "2026-10-01", "geo": "US", "impressions": 48210, "clicks": 312,
"conversions": 9, "fraud_events": 41, "cost": "72.315000", "revenue": "180.000000"}
],
"names": {}
}
Each row holds the grouping columns followed by the metrics:
| Metric | Who sees it | Meaning |
|---|---|---|
impressions, clicks, conversions |
Both | Counts for the row. |
fraud_events |
Both | Events flagged by the quality checks. They are not charged and not paid. |
cost |
Advertisers | What you were charged, in USD. |
revenue |
Advertisers | Sum of the payout values your postbacks reported. |
earnings |
Publishers | Your share of what advertisers were charged, in USD. |
The names map
Rows contain ids. The names object maps those ids to labels you are allowed to see, so you can print readable tables without extra calls:
"names": {
"campaign_id": {"815": "Pop US mobile"},
"website_id": {"77": "example.com"}
}
- Advertisers get campaign names and site domains.
- Publishers get zone names and site domains.
A map appears only when the matching id is among the rows.
Limits
- At most 5,000 rows per response. Narrow the date range or drop a dimension if you reach it.
- Rows are sorted by the grouping columns.
- The endpoint shares the general limit of 120 requests a minute. Reports are summaries, so polling more than every few minutes rarely returns anything new. See Rate limits and errors.
Something missing or wrong? Tell us.