Skip to main content
Setup your endpoints, view report attributes, and examples of requests

Endpoints

Four separate endpoints support requests to create campaign and line item reports and retrieve the report data and status.
VerbEndpointDescription
POST/reports/campaignsCreate a Campaign report request
POST/reports/line-itemsCreate a Line Item report request
GET/reports/{reportId}/statusGet status of a specific report
GET/reports/{reportId}/outputDownload output of a specific report

Report Request Attributes

AttributeData TypeDescription
id / ids*string / list<string>Campaign or Line Item ID(s) of the desired reportExamples: id: "12345" ids: ["12345", "67890"]Accepted values: single or list of string/int64 (max 50 ids per call) Writeable? N / Nullable? N
reportTypeenumReport types are pre-packaged reports that allow the specification of the report breakdown. See Report Types for more details about each of them.- *Note**: when metrics and dimensions are used, the reportType is ignored.Accepted values: refer to Report Types page for a complete list of available values Writeable? N / Nullable? N
dimensionslist<enum>Dimension attributes desired for metrics breakdown for the custom report of the campaign(s) / line item(s).- *Note**:
  • when metrics and dimensions are used, the reportType is automatically ignoredAccepted values: refer to Metrics and Dimensions page for a complete list of available values Writeable? N / Nullable? N | | metrics | list<enum> | Quantitative metrics desired in the custom report of the campaign(s) / line item(s).- *Note**:
  • when metrics and dimensions are used, the reportType is automatically ignored
  • when including winRate metric, it is required to either define campaignType as sponsoredProducts or include campaignTypeName in the list of dimensionsAccepted values: refer to Metrics and Dimensions page for a complete list of available values Writeable? N / Nullable? N | | startDate* | date | Start date to report (inclusive)Accepted values: YYYY-MM-DD Writeable? N / Nullable? N | | endDate* | date | End date to report (inclusive)Accepted values: YYYY-MM-DD Writeable? N / Nullable? N | | campaignType | enum | Campaign typeAccepted values: sponsoredProducts, onSiteDisplays Writeable? N / Nullable? N | | timeZone | string | Time zone to consider in the reportAccepted values: IANA (TZ database) time zones (example: America/New_York, Europe/Paris, Asia/Tokyo, UTC) Writeable? N / Nullable? Y | | clickAttributionWindow | enum | The post-click attribution window, defined as the maximum number of days considered between a click and a conversion for attribution; conversions are attributed to the date of conversion, not the date of click; defaults to campaign settings if omitted; must be specified if viewAttributionWindow is one of the accepted values.The post-click attribution window, defined as the maximum number of days considered between a click and a conversion for attribution; conversions are attributed to the date of conversion, not the date of click. Defaults to campaign settings if omitted; must be specified if viewAttributionWindow is one of the accepted values.Accepted values: none, 7D, 14D, 30D Writeable? N / Nullable? Y | | viewAttributionWindow | enum | The post-view attribution window, defined as the maximum number of days considered between an impression and a conversion for attribution; conversions are attributed to the date of conversion, not the date of impression; defaults to campaign settings if omitted; must be less than or equal to clickAttributionWindow; must be specified if clickAttributionWindow is one of the accepted values.The post-view attribution window, defined as the maximum number of days considered between an impression and a conversion for attribution; conversions are attributed to the date of conversion, not the date of impression. Defaults to campaign settings if omitted; must be less than or equal to clickAttributionWindow; must be specified if clickAttributionWindow is one of the accepted values.Accepted values: none, 1D, 7D, 14D, 30D Writeable? N / Nullable? Y | | salesChannel | enum | Filter on specific sales channel: online or offlineAccepted values: online, offline Writeable? N / Nullable? Y | | format | enum | Format of the report data returnedAccepted values: json, json-compact, json-newline, csv Default: json Writeable? N / Nullable? N |
*Required
Reporting Asynchronous Workflow: Step 1 of 3
  • First, create a request for the campaign or line item report with the desired attributes
  • This generates a reportId representing the report

Create a Report Request

Reporting endpoints provide two separate endpoints that allow downloading reports at the campaign or line item level. Each of the following requests can be repeated for each individual report type. Sample Request - Campaign Report
curl -X POST "https://api.criteo.com/{version}/retail-media/reports/campaigns" \
    -H "Authorization: Bearer <MY_ACCESS_TOKEN>" \
    -H "Content-Type: application/json" \
    -d '{
            "data": {
                "type": "RetailMediaReportRequest",
                "attributes": {
                    "id": "8343086999167541140",
                    "metrics": ["impressions"],
                    "dimensions": ["date"],
                    "reportType": "summary",
                    "startDate": "2025-01-01",
                    "endDate": "2025-01-31",
                    "timeZone": "America/New_York",
                    "campaignType": "sponsoredProducts",
                    "salesChannel": "offline"
                }
            }
        }'
import requests
import json

url = "https://api.criteo.com/{version}/retail-media/reports/campaigns"

payload = json.dumps({
  "data": {
    "type": "RetailMediaReportRequest",
    "attributes": {
      "id": "1285",
      "metrics": [
       		 "impressions"
      		 ],
      "dimensions": [
     		   "date"
     			 ],
      "reportType": "summary",
      "startDate": "2025-01-01",
      "endDate": "2025-01-31",
      "timeZone": "America/New_York",
      "campaignType": "sponsoredProducts",
      "salesChannel": "offline"
    }
  }
})
headers = {
  'Content-Type': 'application/json',
  'Accept': 'application/json',
  'Authorization': 'Bearer <MY_ACCESS_TOKEN>'
}

response = requests.request("POST", url, headers=headers, data=payload)

print(response.text)
OkHttpClient client = new OkHttpClient().newBuilder()
  .build();

MediaType mediaType = MediaType.parse("application/json");

RequestBody body = RequestBody.create(mediaType, "{\"data\":{\"type\":\"RetailMediaReportRequest\",\"attributes\":{\"id\":\"8343086999167541140\",\"metrics\":[\"impressions\"],\"dimensions\":[\"date\"],\"reportType\":\"summary\",\"startDate\":\"2025-01-01\",\"endDate\":\"2025-01-31\",\"timeZone\":\"America/New_York\",\"campaignType\":\"sponsoredProducts\",\"salesChannel\":\"offline\"}}}");

Request request = new Request.Builder()
  .url("https://api.criteo.com/{version}/retail-media/reports/campaigns")
  .method("POST", body)
  .addHeader("Content-Type", "application/json")
  .addHeader("Accept", "application/json")
  .addHeader("Authorization", "Bearer <MY_ACCESS_TOKEN>")
  .build();

Response response = client.newCall(request).execute();
<?php
require_once 'HTTP/Request2.php';
$request = new HTTP_Request2();
$request->setUrl('https://api.criteo.com/{version}/retail-media/reports/campaigns');
$request->setMethod(HTTP_Request2::METHOD_POST);
$request->setConfig(array(
  'follow_redirects' => TRUE
));
$request->setHeader(array(
  'Content-Type' => 'application/json',
  'Accept' => 'application/json',
  'Authorization' => 'Bearer <MY_ACCESS_TOKEN>'
));
$request->setBody('{\"data\":{\"type\":\"RetailMediaReportRequest\",\"attributes\":{\"id\":\"8343086999167541140\",\"metrics\":[\"impressions\"],\"dimensions\":[\"date\"],\"reportType\":\"summary\",\"startDate\": \"2025-01-01\",\"endDate\":\"2025-01-31\",\"timeZone\":\"America/New_York\",\"campaignType\":\"sponsoredProducts\",\"salesChannel\":\"offline\"}}}');
try {
  $response = $request->send();
  if ($response->getStatus() == 200) {
    echo $response->getBody();
  }
  else {
    echo 'Unexpected HTTP status: ' . $response->getStatus() . ' ' .
    $response->getReasonPhrase();
  }
}
catch(HTTP_Request2_Exception $e) {
  echo 'Error: ' . $e->getMessage();
}
Sample Request - Line Item Report
curl -X POST "https://api.criteo.com/{version}/retail-media/reports/line-items" \
    -H "Authorization: Bearer <MY_ACCESS_TOKEN>" \
    -H "Content-Type: application/json" \
    -d '{
            "data": {
                "type": "RetailMediaReportRequest",
                "attributes": {
                    "id": "8343086999167541140",
                    "metrics": [
                        "impressions"
                    ],
                    "dimensions": [
                        "date"
                    ],
                    "reportType": "summary",
                    "startDate": "2020-04-06",
                    "endDate": "2020-06-04",
                    "timeZone": "America/New_York",
                    "campaignType": "sponsoredProducts",
                    "salesChannel": "offline"
                }
            }
        }'
import requests
import json

url = "https://api.criteo.com/{version}/retail-media/reports/line-items"

payload = json.dumps({
  "data": {
    "type": "RetailMediaReportRequest",
    "attributes": {
      "id": "1285",
      "metrics": [
       		 "impressions"
      		 ],
      "dimensions": [
     		   "date"
     			 ],
      "reportType": "summary",
      "startDate": "2022-06-06",
      "endDate": "2022-07-04",
      "timeZone": "America/New_York",
      "campaignType": "sponsoredProducts",
      "salesChannel": "offline"
    }
  }
})
headers = {
  'Content-Type': 'application/json',
  'Accept': 'application/json',
  'Authorization': 'Bearer <MY_ACCESS_TOKEN>'
}

response = requests.request("POST", url, headers=headers, data=payload)

print(response.text)
OkHttpClient client = new OkHttpClient().newBuilder()
  .build();

MediaType mediaType = MediaType.parse("application/json");

RequestBody body = RequestBody.create(mediaType, "{\n            \"data\": {\n                \"type\": \"RetailMediaReportRequest\",\n                \"attributes\": {\n                    \"id\": \"8343086999167541140\",\n                    \"metrics\": [\n       \t\t\t\t\t\t\t\t \"impressions\"\n      \t\t\t\t\t\t\t\t ],\n      \t\t\t\t\t\t  \"dimensions\": [\n        \t\t\t\t\t\t   \"date\"\n      \t\t\t\t\t\t\t\t ],\n                    \"reportType\": \"summary\",\n                    \"startDate\": \"2020-04-06\",\n                    \"endDate\": \"2020-06-04\",\n                    \"timeZone\": \"America/New_York\",\n                    \"campaignType\": \"sponsoredProducts\",\n      \t\t\t\t\t\t  \"salesChannel\": \"offline\"\n                }\n            }\n        }");

Request request = new Request.Builder()
  .url("https://api.criteo.com/{version}/retail-media/reports/line-items")
  .method("POST", body)
  .addHeader("Content-Type", "application/json")
  .addHeader("Accept", "application/json")
  .addHeader("Authorization", "Bearer <MY_ACCESS_TOKEN>")
  .build();

Response response = client.newCall(request).execute();
<?php
require_once 'HTTP/Request2.php';
$request = new HTTP_Request2();
$request->setUrl('https://api.criteo.com/{version}/retail-media/reports/line-items');
$request->setMethod(HTTP_Request2::METHOD_POST);
$request->setConfig(array(
  'follow_redirects' => TRUE
));
$request->setHeader(array(
  'Content-Type' => 'application/json',
  'Accept' => 'application/json',
  'Authorization' => 'Bearer <MY_ACCESS_TOKEN>'
));
$request->setBody('{\n            \"data\": {\n                \"type\": \"RetailMediaReportRequest\",\n                \"attributes\": {\n                    \"id\": \"8343086999167541140\",\n                    \"metrics\": [\n       \t\t\t\t\t\t\t\t \"impressions\"\n      \t\t\t\t\t\t\t\t ],\n      \t\t\t\t\t\t  \"dimensions\": [\n        \t\t\t\t\t\t   \"date\"\n      \t\t\t\t\t\t\t\t ],\n                    \"reportType\": \"summary\",\n                    \"startDate\": \"2020-04-06\",\n                    \"endDate\": \"2020-06-04\",\n                    \"timeZone\": \"America/New_York\",\n                    \"campaignType\": \"sponsoredProducts\",\n      \t\t\t\t\t\t  \"salesChannel\": \"offline\"\n                }\n            }\n        }');
try {
  $response = $request->send();
  if ($response->getStatus() == 200) {
    echo $response->getBody();
  }
  else {
    echo 'Unexpected HTTP status: ' . $response->getStatus() . ' ' .
    $response->getReasonPhrase();
  }
}
catch(HTTP_Request2_Exception $e) {
  echo 'Error: ' . $e->getMessage();
}
Sample Response - Both
{
    "data": {
        "type": "RetailMediaReportStatus",
        "id": "2e733b8c-9983-4237-aab9-17a42f4267cb",
        "attributes": {
            "status": "pending",
            "rowCount": null,
            "fileSizeBytes": null,
            "md5Checksum": null,
            "createdAt": null,
            "expiresAt": null,
            "message": null
        }
    }
}
Reporting Asynchronous Workflow: Step 2 of 3
  • Next, use the reportId to poll the report status endpoint until one is successfully computed

Get Status of a Specific Report

This endpoint retrieves the status of a specific report. Status can be pending, success, failure, or expired Sample Request
curl -X GET "https://api.criteo.com/{version}/retail-media/reports/2e733b8c-9983-4237-aab9-17a42f4267cb/status" \
    -H "Authorization: Bearer <MY_ACCESS_TOKEN>"
import requests

url = "https://api.criteo.com/{version}/retail-media/reports/73fb7859-301f-4371-be91-3e4ad00964aa/status"

payload={}
headers = {
  'Accept': 'application/json',
  'Authorization': 'Bearer <MY_ACCESS_TOKEN>'
}

response = requests.request("GET", url, headers=headers, data=payload)

print(response.text)
OkHttpClient client = new OkHttpClient().newBuilder()
  .build();

MediaType mediaType = MediaType.parse("text/plain");

RequestBody body = RequestBody.create(mediaType, "");

Request request = new Request.Builder()
  .url("https://api.criteo.com/{version}/retail-media/reports/73fb7859-301f-4371-be91-3e4ad00964aa/status")
  .method("GET", body)
  .addHeader("Accept", "application/json")
  .addHeader("Authorization", "Bearer <MY_ACCESS_TOKEN>")
  .build();

Response response = client.newCall(request).execute();
<?php
require_once 'HTTP/Request2.php';
$request = new HTTP_Request2();
$request->setUrl('https://api.criteo.com/{version}/retail-media/reports/73fb7859-301f-4371-be91-3e4ad00964aa/status');
$request->setMethod(HTTP_Request2::METHOD_GET);
$request->setConfig(array(
  'follow_redirects' => TRUE
));
$request->setHeader(array(
  'Accept' => 'application/json',
  'Authorization' => 'Bearer <MY_ACCESS_TOKEN>'
));
try {
  $response = $request->send();
  if ($response->getStatus() == 200) {
    echo $response->getBody();
  }
  else {
    echo 'Unexpected HTTP status: ' . $response->getStatus() . ' ' .
    $response->getReasonPhrase();
  }
}
catch(HTTP_Request2_Exception $e) {
  echo 'Error: ' . $e->getMessage();
}
Sample Response
{
    "data": {
        "attributes": {
            "status": "success",
            "rowCount": 50,
            "fileSizeBytes": 9711,
            "md5CheckSum": "b92bf24cd899f172907f8b001b8a5edb",
            "createdAt": "2025-02-19T19:40:27.000Z",
            "expiresAt": "2025-02-26T19:40:30.000Z",
            "message": "rows_count=50",
            "id": "16d70ce4-6917-48b8-8a55-184809dd59b5"
        },
        "id": "16d70ce4-6917-48b8-8a55-184809dd59b5",
        "type": "StatusResponse"
    },
    "warnings": [],
    "errors": []
}
Reporting Asynchronous Workflow: Step 3 of 3
  • Finally, download the report using the report output endpoint
  • Report outputs are cached for at least 1 hour before expiration
  • Exact expiration is indicated by the expiresAt field in the /status response

Download Output of a Specific Report

This endpoint returns the specific report in the requested format. Sample Request
curl -X GET "https://api.criteo.com/{version}/retail-media/reports/2e733b8c-9983-4237-aab9-17a42f4267cb/output" \
    -H "Authorization: Bearer <MY_ACCESS_TOKEN>"
import requests

url = "https://api.criteo.com/{version}/retail-media/reports/73fb7859-301f-4371-be91-3e4ad00964aa/output"

payload={}
headers = {
  'Accept': 'application/octet-stream',
  'Authorization': 'Bearer <MY_ACCESS_TOKEN>'
}

response = requests.request("GET", url, headers=headers, data=payload)

print(response.text)
OkHttpClient client = new OkHttpClient().newBuilder()
  .build();

MediaType mediaType = MediaType.parse("text/plain");

RequestBody body = RequestBody.create(mediaType, "");

Request request = new Request.Builder()
  .url("https://api.criteo.com/{version}/retail-media/reports/73fb7859-301f-4371-be91-3e4ad00964aa/output")
  .method("GET", body)
  .addHeader("Accept", "application/octet-stream")
  .addHeader("Authorization", "Bearer <MY_ACCESS_TOKEN>")
  .build();

Response response = client.newCall(request).execute();
<?php
require_once 'HTTP/Request2.php';
$request = new HTTP_Request2();
$request->setUrl('https://api.criteo.com/{version}/retail-media/reports/73fb7859-301f-4371-be91-3e4ad00964aa/output');
$request->setMethod(HTTP_Request2::METHOD_GET);
$request->setConfig(array(
  'follow_redirects' => TRUE
));
$request->setHeader(array(
  'Accept' => 'application/octet-stream',
  'Authorization' => 'Bearer <MY_ACCESS_TOKEN>'
));
try {
  $response = $request->send();
  if ($response->getStatus() == 200) {
    echo $response->getBody();
  }
  else {
    echo 'Unexpected HTTP status: ' . $response->getStatus() . ' ' .
    $response->getReasonPhrase();
  }
}
catch(HTTP_Request2_Exception $e) {
  echo 'Error: ' . $e->getMessage();
}
Sample Response Campaign Summary Report
{
    "columns": [
        "campaignId", "campaignName", "campaignTypeName", "date", "impressions", "clicks", 
        "attributedOrders", "attributedUnits", "attributedSales", "ctr", "spend", "cpc", "cpo", 
        "roas", "uniqueVisitors", "frequency"
    ],
    "data": [
        [
            "1285", "End of Summer Sale", "Open Auction", "2025-01-31", 0, 0, 
            1, 1, 76.9400, null, 0.0000, null, 0.0000, 
            null, null, null
        ],
        [
            "1285", "End of Summer Sale", "Open Auction", "2025-01-29", 1883, 6, 
            8, 8, 1749.2600, 0.0032, 3.7000, 0.6167, 0.4625, 
            472.7730, null, null
        ],
        [
            "1285", "End of Summer Sale", "Open Auction", "2025-01-28", 0, 0, 
            1, 1, 99.4600, null, 0.0000, null, 0.0000, 
            null, null, null
        ],
        [
            "1285", "End of Summer Sale", "Open Auction", "2025-01-27", 35087, 107, 
            25, 25, 4381.2700, 0.0030, 96.3000, 0.9000, 3.8520, 
            45.4961, null, null
        ] 
    ], 
    "rows":4
}
Campaign Attribution Report
{
    "columns": [
        "purchasedDate", "purchasedHour", "advDate", "advHour", "daysDifference", 
        "campaignId", "campaignName", "lineItemId", "lineItemName", 
        "advProductId", "advProductGtin", "advProductMpn", "advProductName", 
        "advProductCategory", "purchasedProductId", "purchasedProductGtin", 
        "purchasedProductMpn", "purchasedProductName", "purchasedProductCategory", 
        "attributedUnits", "attributedSales", "advEngagement", 
        "advToPurchasedProductRelationship", "salesChannel", "retailerName", 
        "pageTypeName", "keyword", "attributionWindow"
    ],
    "data": [
        [
            "2022-10-21", 16, "2022-10-21", 16, 0, 
            "1344", "End to end testing", "2602", "LJ Test", 
            "426292", null, null, 
            "Arm & Hammer Pure Baking Soda, 13.5 lbs", "hardware > tools > hammers > powered hammers", "426292", null, null, 
            "Arm & Hammer Pure Baking Soda, 13.5 lbs", "hardware > tools > hammers > powered hammers", 
            1, 8.6900, "click", 
            "same sku", "online", "Costco", 
            "category", "", "C30V01"
        ]
    ],
    "rows": 1
}

What’s Next