Skip to main content

Reports

POST /publisher/reports/ and POST /advertiser/reports/ return your statistics: clicks, conversions and money, grouped by day, month, offer, website and more. Each request returns one report. type picks the grouping, fields picks the numbers, and filters limits the period and what is counted.

Reports are requested with POST, so they need a token with the write scope. A token with only read gets 403 Forbidden.

A first report​

A publisher's clicks, conversions and earnings for each day of October 2026:

curl -X POST "https://api.convertiser.com/publisher/reports/"
-H "Authorization: Token your-personal-secret-token-here"
-H "Content-Type: application/json"
-d '{
"type": "date",
"fields": ["clicks", "conversions", "approved_conversions", "approved_publisher_income"],
"filters": [
{"created": {"lookup": "gte", "value": "2026-10-01"}},
{"created": {"lookup": "lte", "value": "2026-10-31"}}
],
"currency": "PLN",
"ordering": "date",
"page_size": 31
}'
{
"count": 31,
"next": null,
"previous": null,
"results": [
{
"date": "2026-10-01",
"gross_clicks": 1520,
"conversions_cnt_created": 14,
"conversions_cnt_approved": 9,
"publisher_payout_approved": 412.5
},
...
]
}

Each row is one group, here one day. The keys in a row are not the names you asked for in fields. The fields table pairs them up.

The period​

Filter on created, the day a click or conversion was recorded. gte sets the first day and lte the last, and both days count in full:

"filters": [
{"created": {"lookup": "gte", "value": "2026-10-01"}},
{"created": {"lookup": "lte", "value": "2026-10-31"}}
]

Dates are ISO 8601 and are read in your account's timezone, which GET /my/timezone_preferences/ shows.

A date, month or year report needs both filters. It has one row for every day, month or year from gte to lte, zeros included. Without the filters it comes back empty, and with only one of them it has a single row. For the current month so far, set lte to today.

The other report types cover all your history when you leave out created.

Use gte and lte only. lt and gt also count the whole day you give them.

Report types​

type is required and takes one grouping per request.

typeOne row perThe row names it with
dateDaydate
monthMonthmonth and month_year
yearYearyear
hourHour of the day, 0 to 23, summed over the periodhour
offerOfferoffer_id and offer_title
goalOffer goalgoal_id and goal_title
websiteWebsitewebsite_id and website_url
ctag1Traffic sourcectag1 and traffic_source

Publishers can also group by subaccount and by keyword. Advertisers can group by atag1, the discount code a conversion came with.

A goal report, and an advertiser's atag1 report, count conversions only. Asking one of them for a click field returns 400 Bad Request.

Fields​

fields is the list of numbers to return. Send it with every request, because a request without it fails. A field your account type may not ask for returns 400 Bad Request.

Counts, for both audiences:

In fieldsIn the rowWhat it counts
clicksgross_clicksClicks
unique_clicksunique_clicksClicks from different visitors
conversionsconversions_cnt_createdConversions recorded
pending_conversionsconversions_cnt_pendingConversions waiting for approval
approved_conversionsconversions_cnt_approvedApproved conversions
rejected_conversionsconversions_cnt_rejectedRejected conversions
approved_sale_amountsale_amount_approvedThe order value of approved conversions
crcrApproved conversions per 100 unique clicks

Money for publishers:

In fieldsIn the rowWhat it is
pending_publisher_incomepublisher_payout_pendingYour commission on pending conversions
approved_publisher_incomepublisher_payout_approvedYour commission on approved conversions
rejected_publisher_incomepublisher_payout_rejectedYour commission on rejected conversions
cpacpaApproved commission per approved conversion
cpccpcApproved commission per unique click

Money for advertisers:

In fieldsIn the rowWhat it is
pending_advertiser_expenseadvertiser_revenue_pendingWhat pending conversions cost you
approved_advertiser_expenseadvertiser_revenue_approvedWhat approved conversions cost you
rejected_advertiser_expenseadvertiser_revenue_rejectedWhat rejected conversions would have cost
rparpaApproved cost per approved conversion
rpcrpcApproved cost per unique click

The reference for publishers and advertisers lists the rest.

Money comes back as a JSON number rounded to two decimal places, in the currency you ask for with currency: EUR, USD or PLN, in capitals. Without currency, it is your account's default currency.

Filters​

Besides created, filters takes:

FilterValue
offerAn offer id, such as offer_id from an offer report
goalA goal id, such as goal_id from a goal report
websiteA website id, such as website_id from a website report
A count from fields, such as approved_conversionsA number
For publishers, a money field such as approved_publisher_incomeA number

The ids take exact. A list as value matches any of its ids, and ~exact leaves them out. An id the API does not recognise is ignored without an error, and the report then covers every offer, goal or website. If a report is larger than you expect, check the ids.

The counts and money take exact, lt, lte, gt and gte, and apply to each row of the report, after the grouping. {"approved_conversions": {"lookup": "gt", "value": 0}} drops the rows with no approved conversions.

Every filter has to hold.

Ordering and pages​

ordering takes one name from fields, or the type's own name such as date. A - in front sorts from the highest.

page_size is 20 by default and at most 100. next and previous are URLs with a page number in the query string, but a POST reads page from the body. For the next page, send the same body again with "page": 2. A page past the last one returns 404 Not Found.

Publisher examples​

This month's earnings per offer, the best first:

{
"type": "offer",
"fields": ["clicks", "approved_conversions", "pending_publisher_income", "approved_publisher_income"],
"filters": [
{"created": {"lookup": "gte", "value": "2026-10-01"}}
],
"ordering": "-approved_publisher_income"
}

One offer, day by day, for the first half of October:

{
"type": "date",
"fields": ["clicks", "unique_clicks", "conversions", "cr"],
"filters": [
{"created": {"lookup": "gte", "value": "2026-10-01"}},
{"created": {"lookup": "lte", "value": "2026-10-15"}},
{"offer": {"lookup": "exact", "value": "your-offer-id"}}
],
"ordering": "date"
}

Your websites in 2026 that brought at least one approved conversion, in euro:

{
"type": "website",
"fields": ["clicks", "approved_conversions", "approved_publisher_income", "cpc"],
"filters": [
{"created": {"lookup": "gte", "value": "2026-01-01"}},
{"created": {"lookup": "lte", "value": "2026-12-31"}},
{"approved_conversions": {"lookup": "gt", "value": 0}}
],
"currency": "EUR",
"ordering": "-approved_conversions"
}

Advertiser examples​

Each month of 2026, with the order value and what it cost:

curl -X POST "https://api.convertiser.com/advertiser/reports/"
-H "Authorization: Token your-personal-secret-token-here"
-H "Content-Type: application/json"
-d '{
"type": "month",
"fields": ["clicks", "conversions", "approved_conversions", "approved_sale_amount", "approved_advertiser_expense"],
"filters": [
{"created": {"lookup": "gte", "value": "2026-01-01"}},
{"created": {"lookup": "lte", "value": "2026-12-31"}}
],
"ordering": "month"
}'

The publishers' websites that sent the most approved conversions to one offer in September:

{
"type": "website",
"fields": ["clicks", "approved_conversions", "approved_advertiser_expense", "rpa"],
"filters": [
{"created": {"lookup": "gte", "value": "2026-09-01"}},
{"created": {"lookup": "lte", "value": "2026-09-30"}},
{"offer": {"lookup": "exact", "value": "your-offer-id"}}
],
"ordering": "-approved_conversions",
"page_size": 100
}

Conversions waiting for your approval, per goal:

{
"type": "goal",
"fields": ["pending_conversions", "pending_advertiser_expense"],
"filters": [
{"pending_conversions": {"lookup": "gt", "value": 0}}
],
"ordering": "-pending_conversions"
}

When a report is empty​

If the statistics service cannot answer, the API still answers 200 OK, with "count": 0 and no rows. A report that should have rows and comes back like that is worth requesting again a little later.