Overview
The Product Level Reporting API provides product-level (SKU) performance data for Marketplace Performance Outcomes (MPO). It is designed for use cases where you need to understand how individual products perform across clicks, displays, and cost -at a granularity that campaign or seller-level reporting does not provide. This API is asynchronous and file-based. Because product-level reports cover every product with activity in the requested period, they are designed for large-scale data export: you create a report job, poll for its status, and download the result as a CSV or JSON file once it is ready. Totals returned by this API reconcile with the MPO Statistics API for the same scope and period.When to Use This API
Use the Product Level Reporting API when you need to:- Analyze performance at individual product level across sellers and campaigns
- Export complete product-level data with no truncation -all products with activity in the period are included
- Understand product-level cost and delivery (clicks, displays) for BI or data warehouse use
- Filter performance by advertiser, campaign, ad set.
Campaign vs Ad Set -Terminology
This API follows the standard MPO object model:campaignId refers to the marketing campaign, and adSetId refers to the ad set -the buying entity below the campaign.
Legacy MPO APIs use the term campaignId to refer to what this API calls adSetId. If your integration uses the legacy campaignId to identify a buying entity, that same ID maps to adSetId here. The campaignId dimension and filter in this API refer to the marketing campaign and are available for MPO Pro only.
How It Works
The API follows a three-step asynchronous flow:- Create a report job (
POST /product-reports/export) - Poll for job status (
GET /report-jobs/{reportId}) - Download the report once ready (
GET /product-reports/{reportId})
DONE status immediately with the cached result.
Reports contain totals over the requested interval -there is no time breakdown or date column in the output.
Endpoint Reference
1. Create Report Job
POST https://api.criteo.com/{version}/marketing-solutions/marketplace-performance-outcomes/stats/product-reports/exportCreates a new asynchronous product-level report job. Returns a
reportId to use in subsequent status and download calls.
Request Body
{ "data": { "type": "ProductReportJob", "attributes": { "fileFormat": "csv", "advertiserIds": ["2914"], "adSetIds": ["106509"], "dimensions": ["advertiserId", "adSetId", "sellerId", "productId"], "metrics": ["displays", "clicks", "cost"], "startDate": "2026-03-09T00:00:00Z", "endDate": "2026-03-11T00:00:00Z" } }}Request Parameters
Data availability grows progressively after launch. If your
startDate is earlier than the available data window, the request will be rejected with an invalid-query error. Full 1-year lookback is expected to be available progressively after go-live.
Response
{ "data": { "type": "ProductReportJobStatus", "attributes": { "reportId": "e0893b6b-be25-477f-9ca3-e6e8c8ec9e30", "status": "PENDING" } }}If an identical request was recently processed and the cache is still valid, the response may already show
"status": "DONE".
2. Get Report Status
GET https://api.criteo.com/{version}/marketing-solutions/marketplace-performance-outcomes/stats/report-jobs/{reportId}Returns the current status of a report job.
Path Parameters
Response
{ "data": { "type": "ProductReportJobStatus", "attributes": { "reportId": "e0893b6b-be25-477f-9ca3-e6e8c8ec9e30", "status": "DONE", "expiresAt": "2026-03-18T10:35:53Z", "fileSizeBytes": 154555 } }}Status Values
Poll this endpoint at a regular interval (recommended: every 30–60 seconds) until status is
DONE before downloading.
3. Download Report
GET https://api.criteo.com/{version}/marketing-solutions/marketplace-performance-outcomes/stats/product-reports/{reportId}Downloads the completed report file. Only available when job status is
DONE.
Path Parameters
Response -CSV (text/csv)
One row per combination of the requested dimensions, with metrics totalled over the full reporting interval. There is no date column -the report returns interval totals only.
advertiserId,adSetId,sellerId,productId,displays,clicks,cost2914,106509,515151,847392011,220,45,44002914,106509,515151,847392012,800,4,4002914,106509,131313,564656664,1832,3,450Response -JSON (application/json)
{ "data": [ [2914, 106509, 515151, 847392011, 220, 45, 4400], [2914, 106509, 515151, 847392012, 800, 4, 400], [2914, 106509, 131313, 564656664, 1832, 3, 450] ], "metadata": { "columns": ["advertiserId", "adSetId", "sellerId", "productId", "displays", "clicks", "cost"], "rows": 3 }}Dimensions
Duplicate dimension values in the same request are not permitted. Time dimensions (
date, day, hour) are not supported by this API -the report always returns interval totals.
Metrics
Duplicate metric values in the same request are not permitted.
Error Handling
HTTP Status Codes
Error Codes
Example: Invalid file format
{ "errors": [ { "traceId": "56ed4096-f96a-4944-8881-05468efe0ec9", "code": "unsupported-file-format", "title": "Unsupported file format", "detail": "The requested fileFormat 'xls' is not supported. Supported formats are: csv and json." } ]}Integration Pattern
A typical integration for a daily product-level export:- Call
POST /product-reports/exportwith your desired dimensions, metrics, and date range. - Store the returned
reportId. - Poll
GET /report-jobs/{reportId}every 30–60 seconds. - When status is
DONE, callGET /product-reports/{reportId}to download the file. - If status is
FAILURE, check your request parameters and retry. - If status is
EXPIRED, submit a new report job.
DONE immediately on the initial POST response -check before polling.