Catalog Endpoints

Generate and download a copy of retailer's inventory

Endpoints

MethodEndpointDescription
POST/accounts/{accountId}/catalogsCreate a catalog request to generate a new catalog for Brand account
POST/accounts/{accountId}/catalogs/sellersCreate a catalog request to generate a new catalog for Seller account
GET/catalogs/{catalogId}/statusRetrieve the status of a specific catalog request.
GET/catalogs/{catalogId}/outputDownload the output of a specific catalog once it's ready.

Catalog Creation Request Attributes (for Brand accounts)

AttributeData TypeDescription
formatenumFormat of the catalog data returned

Accepted values: json-newline
Default: json-newline
Writeable? N / Nullable? Y
brandIdFilterlistBrand ID(s) used to filter down catalog results based on specified brands

Accepted values: list of string/int64
Writeable? N / Nullable? N

Catalog Creation Request Attributes (for Seller accounts)

AttributeData TypeDescription
sellerslistList of required seller pairs retailerId and sellerId associated with the catalog to be generated

Parameters:

* retailerId: Retailer ID, generated internally by Criteo
* sellerId: seller ID in the respective retailer's catalog, used to filter down catalog products

Catalog Status Response Attributes

AttributeData TypeDescription
idstringID of the catalog creation request, to be used to retrieve its status and output (using other endpoints below - async)

Accepted values: string of int64
Writeable? N / Nullable? N
statusenumPossible status of respective catalog creation

Accepted values: pending, success, failure, expired, unknown
Default: pending
Writeable? N / Nullable? N
currencyenumCurrency of the products in the catalog

Accepted values: 3-chars currency code (in ISO-4217 ; e.g. USD, EUR)
Writeable? N / Nullable? Y
rowCountintegerNumber of products available in the catalog (available when reach success status)

Accepted values: int32
Writeable? N / Nullable? Y
fileSizeBytesintegerFile size of catalog, in bytes (available when reach success status)

Accepted values: int32
Writeable? N / Nullable? Y
md5ChecksumstringMD5 checksum of catalog's content (available when reach success status)

Accepted values: 32-char alpha-numeric strings
Writeable? N / Nullable? Y
createdAttimestampTimestamp of catalog creation, in UTC

Accepted values: yyyy-mm-ddThh:mm:ss±hh:mm(in ISO-8601)
Writeable? N / Nullable? N
messagestringOptional informative message, for developer consumption

Accepted values: string
Writeable? N / Nullable? Y

Catalog Output Response Attributes

AttributeData TypeDescription
idstringProduct ID, defined by the retailer

Accepted values: up to 500-chars string
Writeable? N / Nullable? N
namestringProduct name, defined by the retailer

Accepted values: up to 1000-chars string
Writeable? N / Nullable? N
categorystringProduct category, defined by the retailer

Accepted values: up to 1000-chars string
Writeable? N / Nullable? Y
brandNamestringBrand name of the product; brands are standardized across retailers

Accepted values: up to 120-chars string
Writeable? N / Nullable? Y
retailerIdstringRetailer ID that contains the product offer

Accepted values: string of int64
Writeable? N / Nullable? N
retailerNamestringRetailer name that contains the product offer

Accepted values: up to 100-chars string
Writeable? N / Nullable? N
pricedecimalCurrent product price in the respective retailer

Accepted values: price ≥ 0.0
Writeable? N / Nullable? Y
isInStockbooleanFlag defining if product is currently in stock or not

Accepted values: true, false
Writeable? N / Nullable? N
minBiddecimalMinimum Cost-Per-Click (CPC) an advertiser must bid for the product, established by the retailer
Any Line Item with this product must have its targetBid satisfying this value

Accepted values: minBid > 0.0
Writeable? N / Nullable? Y
gtinstringGlobal Trade Item Number (GTIN), if available; also known as European Article Number (EAN) or Universal Product Code (UPC)

Accepted values: up to 14-chars numeric string
Writeable? N / Nullable? Y
mpnstringManufacturer Part Number (MPN), if available

Accepted values: up to 70-chars string
Writeable? N / Nullable? Y
imageUrlstringHTTP URL of the product image provided by the retailer

Accepted values: string
Writeable? N / Nullable? N
updatedAttimestampTimestamp of last product info update in retailer's catalog, in UTC

Accepted values: yyyy-mm-ddThh:mm:ss±hh:mm(in ISO-8601 )
Writeable? N / Nullable? N

📘

Catalog Asynchronous Workflow: Step 1 of 3

  1. Create a request for the latest catalog of the specified account using the appropriate endpoint.
  2. This action generates a catalogId that represents the account's catalog.
  3. Catalog requests are cached for 1 hour, meaning repeated requests within this timeframe will return the same catalogId and output.

 

Create a Catalog Request for Brand account

This endpoint creates a request for the latest available catalog for a specific account

https://api.criteo.com/{version}/retail-media/accounts/{accountId}/catalogs

💭

Best Practice Tip!

To speed up catalog downloads, you can narrow down the results by using the brandIdFilter body parameter. This allows you to filter the catalog by specific brands, helping to return results faster.

Sample Request

curl -L -X POST 'https://api.criteo.com/{version}/retail-media/accounts/18446744073709551616/catalogs' \
-H 'Content-Type: application/json' \
-H 'Accept: application/json' \
-H 'Authorization: Bearer <MY_ACCESS_TOKEN>' \
--data-raw '{
  "data": {
    "type": "RetailMediaCatalogStatus",
    "attributes": {
      "format": "json-newline",
      "brandIdFilter": [
        "40115",
        "9092"
      ]
    }
  }
}'
import requests
import json

url = "https://api.criteo.com/{version}/retail-media/accounts/18446744073709551616/catalogs"

payload = json.dumps({
  "data": {
    "type": "RetailMediaCatalogStatus",
    "attributes": {
      "format": "json-newline",
      "brandIdFilter": [
        "4768"
      ]
    }
  }
})
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\": \"RetailMediaCatalogStatus\",\n    \"attributes\": {\n      \"format\": \"json-newline\",\n      \"brandIdFilter\": [\n        \"4768\"\n      ]\n    }\n  }\n}");

Request request = new Request.Builder()
  .url("https://api.criteo.com/{version}/retail-media/accounts/18446744073709551616/catalogs")
  .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/accounts/18446744073709551616/catalogs');
$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": "RetailMediaCatalogStatus",\n    "attributes": {\n      "format": "json-newline",\n      "brandIdFilter": [\n        "4768"\n      ]\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

{
    "data": {
        "id": "1122850670915847014",
        "type": "RetailMediaCatalogStatus",
        "attributes": {
            "status": "pending",
            "currency": null,
            "rowCount": null,
            "fileSizeBytes": null,
            "md5Checksum": null,
            "createdAt": "2024-04-06T05:11:41.351+00:00",
            "message": null
        }
    }
}

📘

Catalog Asynchronous Workflow: Step 2 of 3

After generating a catalogId, use it to poll the catalog status endpoint to check the progress. Continue polling until the catalog is successfully created and ready for download.

 

Create a Catalog Request for Seller account

This endpoint creates catalog for a particular Seller account:

https://api.criteo.com/{version}/retail-media/accounts/{accountId}/catalogs/sellers

Sample Request

curl --location 'https://api.criteo.com/{version}/retail-media/accounts/18446744073709551616/catalogs/sellers' \
--header 'Content-Type: application/json' \
--header 'Accept: text/plain' \
--header 'Authorization: Bearer <TOKEN>' \
--data '{
  "data": {
    "type": "RetailMediaCatalogStatus",
    "attributes": {
      "sellers": [
        {
          "retailerId": "123",
          "sellerId": "60axxxxxxxxxxxxxxxx"
        }
      ]
    }
  }
}'
import requests
import json

url = "https://api.criteo.com/{version}/retail-media/accounts/18446744073709551616/catalogs/sellers"

payload = json.dumps({
  "data": {
    "type": "RetailMediaCatalogStatus",
    "attributes": {
      "sellers": [
        {
          "retailerId": "123",
          "sellerId": "60axxxxxxxxxxxxxxxx"
        }
      ]
    }
  }
})
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\": \"RetailMediaCatalogStatus\",\n    \"attributes\": {\n      \"sellers\": [\n        {\n          \"retailerId\": \"123\",\n          \"sellerId\": \"60axxxxxxxxxxxxxxxx\"\n        }\n      ]\n    }\n  }\n}");

Request request = new Request.Builder()
  .url("https://api.criteo.com/{version}/retail-media/accounts/18446744073709551616/catalogs/sellers")
  .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/accounts/18446744073709551616/catalogs/sellers');
$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": "RetailMediaCatalogStatus",\n    "attributes": {\n      "sellers": [\n        {\n          "retailerId": "123",\n          "sellerId": "60axxxxxxxxxxxxxxxx"\n        }\n      ]\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

{
    "data": {
        "id": "1122850670915847014",
        "type": "RetailMediaCatalogStatus",
        "attributes": {
            "status": "success",
            "currency": "USD",
            "rowCount": 369318,
            "fileSizeBytes": 216634050,
            "md5Checksum": "713f2d3c0ed718125a1acdef05224df5",
            "createdAt": "2025-01-17T22:45:11.44+00:00",
            "message": null
        }
    }
}

Get Status of a Specific Catalog

This endpoint retrieves the status of a specific catalog. Status can be pending, success, failure, or expired

https://api.criteo.com/{version}/retail-media/catalogs/{catalogId}/status

Sample Request

curl -X GET "https://api.criteo.com/{version}/retail-media/catalogs/1122850670915847014/status" \
    -H "Authorization: Bearer <MY_ACCESS_TOKEN>"
import requests

url = "https://api.criteo.com/{version}/retail-media/catalogs/357957813719011328/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/catalogs/357957813719011328/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/catalogs/357957813719011328/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": {
        "id": "1122850670915847014",
        "type": "RetailMediaCatalogStatus",
        "attributes": {
            "status": "success",
            "currency": "USD",
            "rowCount": 1001,
            "fileSizeBytes": 353293,
            "md5Checksum": "2c15b77740028435ca476823df7fb4f8",
            "createdAt": "2020-04-06T05:11:41.351+00:00",
            "message": null
        }
    }
}

📘

Catalog Asynchronous Workflow: Step 3 of 3

Once the catalog is successfully created, use the catalog output endpoint to download the collection of catalog products. Note that catalog outputs are typically available for 72 hours before they expire, so be sure to download them within this time frame.

 

Download Output of a Specific Catalog

This endpoint returns the products in a specific catalog as a newline-delimited JSON byte stream

https://api.criteo.com/{version}/retail-media/catalogs/{catalogId}/output

Sample Request

curl -X GET "https://api.criteo.com/{version}/retail-media/catalogs/1122850670915847014/output" \
    -H "Authorization: Bearer <MY_ACCESS_TOKEN>"
import http.client

conn = http.client.HTTPSConnection("api.criteo.com")
payload = ''
headers = {
  'Accept': 'application/x-json-stream',
  'Authorization': 'Bearer <MY_ACCESS_TOKEN>'
}
conn.request("GET", "/{version}/retail-media/catalogs/357957813719011328/output", payload, headers)
res = conn.getresponse()
data = res.read()
print(data.decode("utf-8"))
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/catalogs/357957813719011328/output")
  .method("GET", body)
  .addHeader("Accept", "application/x-json-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/catalogs/357957813719011328/output');
$request->setMethod(HTTP_Request2::METHOD_GET);
$request->setConfig(array(
  'follow_redirects' => TRUE
));
$request->setHeader(array(
  'Accept' => 'application/x-json-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 - Brand Catalog

{ \
    "id": "sku1", \
    "name": "Product One", \
    "category": "category1", \
    "brandId": "7672171780147256541", \
    "brandName": "Brand 123", \
    "retailerId": "3239117063738827231", \
    "retailerName": "Retailer 123", \
    "price": 1.00, \
    "isInStock": true, \
    "minBid": 0.30, \
    "gtin": "abc123", \
    "mpn": "789xyz", \
    "imageUrl": "/image1.jpg", \
    "updatedAt": "2020-04-06T02:23:07Z" \
}
 
// ... newline-delimited, no comma
 
{ \
    "id": "product-1001", \
    "name": "Product One Thousand and One", \
    "category": "category2", \
    "brandId": "7672171780147256541", \
    "brandName": "Brand 123", \
    "retailerId": "18159942378514859684", \
    "retailerName": "Retailer 789", \
    "price": 5.00, \
    "isInStock": false, \
    "minBid": 0.45, \
    "gtin": "none", \
    "mpn": "none", \
    "imageUrl": "/image1001.jpg", \
    "updatedAt": "2020-04-06T01:07:23Z" \
}

Sample Response - Seller Catalog

{ \
    "id": "86833674", \
    "name": "Flat Front Short 46 x 10.5\" - Black", \
    "category": "clothing, shoes & accessories|men’s clothing|bottoms|shorts", \
    "categoryId": "3051218", \
    "brandId": "40095", \
    "brandName": "Test Brand", \
    "retailerId": "131", \
    "retailerName": "Retailer Name", \
    "price": 39.99, \
    "isInStock": true, \
    "minBid": 0.4000, \
    "gtin": "1234567890", \
    "mpn": null, \
    "imageUrl": "https://example.com/is/image/a610-881aa9a71c93", \
    "updatedAt": "2024-07-25T19:52:30Z", \
    "sellerId": "60axxxxxxxxxxxxxxxx", \
    "sellerName": "Test Seller" \
}
 
// ... newline-delimited, no comma
 
{ \
    "id": "86833235", \
    "name": "Pleated Front Short 52 x 10.5\" - String", \
    "category": "clothing, shoes & accessories|men’s clothing|bottoms|shorts", \
    "categoryId": "3051218", \
    "brandId": "40095", \
    "brandName": "Test Brand", \
    "retailerId": "131", \
    "retailerName": "Retailer Name", \
    "price": 39.99, \
    "isInStock": true, \
    "minBid": 0.4000, \
    "gtin": "1234567890", \
    "mpn": null, \
    "imageUrl": "https://example.com/is/image/a610-881aa9a71c93", \
    "updatedAt": "2024-07-25T19:52:30Z", \
    "sellerId": "60axxxxxxxxxxxxxxxx", \
    "sellerName": "Test Seller" \
}

Responses

ResponseDescription
🟢200Success
🔴 400The indicated catalog is not available for retrieval, wait for a success status
🔴 403API user does not have the authorization to make requests to the account ID. For an authorization request, follow the authorization request steps