> ## Documentation Index
> Fetch the complete documentation index at: https://developers.criteo.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Campaigns Endpoints

> Create the campaigns that group line items and hold shared settings and budget.

export const EndpointBadge = ({method = "GET", children}) => {
  const METHOD_STYLES = {
    GET: {
      bg: "mint-bg-[#2AB673]"
    },
    POST: {
      bg: "mint-bg-[#3064E3]"
    },
    PUT: {
      bg: "mint-bg-[#C28C30]"
    },
    PATCH: {
      bg: "mint-bg-[#DA622B]"
    },
    DELETE: {
      bg: "mint-bg-[#CB3A32]"
    },
    API: {
      bg: "mint-bg-black"
    }
  };
  const key = method.toUpperCase();
  const styles = METHOD_STYLES[key] ?? METHOD_STYLES.API;
  return <div className="relative mt-7">
      <span className={`absolute -top-2 -left-2 z-10 ${styles.bg} text-white px-2.5 py-0.5 rounded-full text-xs font-bold tracking-wide`}>
        {key}
      </span>
      {children}
    </div>;
};

<Warning>
  **These endpoints are available in the stable Retail Media API.** We recommend using [Retail Media 2026.07](/retail-media/docs/welcome-to-criteo) instead of the experimental version. In your API calls, replace `/experimental/` with `/2026-07/`, or `/2027-01/` for Release Candidates. [Learn more about our versioning policy.](/retail-media/docs/versioning-policy)
</Warning>

## Overview

A campaign groups line items that share attribution settings, flight dates and budget. It is the entity you create first, before adding the line items that control delivery.

The campaigns endpoint is shared across campaign types. It exposes common fields through one contract instead of separate Sponsored Products and Onsite Display routes.

The `campaignType` attribute is the discriminator. Type-specific fields are carried in the details object matching the type.

<Info>
  The objective and the budget belong to the details object, not to the campaign root. A `SponsoredProducts` campaign sets its own objective; an `OnsiteDisplay` campaign created through this endpoint is always an impressions campaign, so it sets no objective and its budget is required.
</Info>

## Endpoints Overview

| Method | Endpoint | Description |
| - | - | - |
| `POST` | `/accounts/{accountId}/campaigns` | Create a campaign under an account. |
| `GET` | `/accounts/{accountId}/campaigns/{campaignId}` | Fetch a campaign by id. |
| `PATCH` | `/accounts/{accountId}/campaigns/{campaignId}` | Selectively update a campaign. |
| `POST` | `/accounts/{accountId}/campaigns/search` | Search campaigns under an account. |

## Create a Campaign

<EndpointBadge method="post">
  ```http theme={null}
  https://api.criteo.com/experimental/retail-media/accounts/{accountId}/campaigns
  ```
</EndpointBadge>

### Path parameter

| Parameter | Type | Required | Description |
| - | - | - | - |
| `account-id` | string | Yes | Identifier of the account that owns the campaign. |

The authenticated user must have permission to manage campaigns on the requested account.

### Request attributes

All attributes below are nested under `data.attributes` in the request envelope, and the resource `type` is `CampaignCreateModel`.

| Attribute | Type | Required | Description |
| - | - | - | - |
| `name` | string | Yes | Display name of the campaign. It must be unique within the account and contain up to 255 characters. |
| `campaignType` | string | Yes | Type of campaign, set only on creation. `SponsoredProducts` or `OnsiteDisplay`. Determines which details objects are accepted. |
| `buyType` | string | Yes | Buy type of the campaign, set only on creation. `Auction`. |
| `attributionSettings` | object | No | Attribution windows and scopes. Each setting may be omitted and is then populated with the default for the campaign type. |
| `drawableBalanceIds` | array | No | Identifiers of the balances the campaign draws from. Defaults to empty; at least one balance is required before the campaign can start. |
| `companyName` | string | No | Name of the company associated with the advertisement. Available to European Union marketplaces only, in compliance with the Digital Services Act. Only supply accounts may set it. |
| `onBehalfCompanyName` | string | No | Name of the company the advertisement runs on behalf of. Available to European Union marketplaces only, in compliance with the Digital Services Act. Only supply accounts may set it. |
| `billByRetailerId` | string | No | Identifier of the retailer the campaign is billed to, set only on creation. Required when drawing from a retailer budget balance. Only network demand accounts may set it. |
| `regulatedCategory` | string | No | Regulated category the campaign advertises. `None` or `Alcohol`. |
| `scheduleDetails` | object | Yes | Active period of the campaign. Both campaign types own their flight dates and require it. |
| `sponsoredProductsDetails` | object | No | Objective and budget of a `SponsoredProducts` campaign. |
| `onsiteDisplayDetails` | object | No | Budget of an `OnsiteDisplay` campaign. |

### Attribution settings attributes

| Attribute | Type | Required | Description |
| - | - | - | - |
| `clickAttributionWindow` | string | No | `OneWeek`, `TwoWeeks` or `OneMonth`. |
| `viewAttributionWindow` | string | No | `None`, `OneDay`, `OneWeek`, `TwoWeeks` or `OneMonth`. |
| `clickAttributionScope` | string | No | `SameSku`, `SameSkuCategory` or `SameSkuCategoryBrand`. |
| `viewAttributionScope` | string | No | `SameSku`, `SameSkuCategory` or `SameSkuCategoryBrand`. |

Defaults applied when a setting is omitted:

| Setting | `OnsiteDisplay` | `SponsoredProducts` |
| - | - | - |
| `clickAttributionWindow` | `TwoWeeks` | `OneMonth` |
| `viewAttributionWindow` | `TwoWeeks` | `OneDay` |
| `clickAttributionScope` | `SameSkuCategory` | `SameSkuCategory` |
| `viewAttributionScope` | `SameSkuCategory` | `SameSku` |

### Schedule details attributes

| Attribute | Type | Required | Description |
| - | - | - | - |
| `startDate` | string | Yes | Start of the campaign's active period, as a date-time. |
| `endDate` | string | Yes | End of the campaign's active period, as a date-time. |

A manual `SponsoredProducts` campaign that runs indefinitely sends exactly `9999-12-30T00:00:00Z` as its `endDate`. Any other far-future date, including a neighbouring one, is treated as a real end date.

An objective other than `Manual` spends its budget over a flight, so it needs a real end date and rejects that value. An `OnsiteDisplay` `Auction` campaign rejects it too.

### Sponsored Products details attributes

Nested under `sponsoredProductsDetails`.

| Attribute | Type | Required | Description |
| - | - | - | - |
| `objective` | string | No | What the campaign optimizes for. `Manual`, `Clicks`, `Conversion` or `Revenue`. Defaults to `Manual`. |
| `budget` | object | No | Financial intent of the campaign. Required for an objective other than `Manual`, which also restricts it to an amount. A manual campaign may cap its own periods and pace its daily spend. |

### Onsite Display details attributes

Nested under `onsiteDisplayDetails`.

| Attribute | Type | Required | Description |
| - | - | - | - |
| `budget` | object | Yes | Financial intent of the campaign. An amount only: per-period cappings and pacing apply to manual `SponsoredProducts` campaigns. |

### Budget attributes

| Attribute | Type | Required | Description |
| - | - | - | - |
| `amount` | number | OnsiteDisplay: Yes. SponsoredProducts: No | Total the campaign may spend over its flight. Must be greater than zero. A manual `SponsoredProducts` campaign may omit it to leave the total uncapped. |
| `cappings` | array | No | Manual `SponsoredProducts` campaigns only. Per-period ceilings, at most one entry per period. |
| `cappings[].type` | string | Yes | Period the ceiling applies to. `Daily` or `Monthly`. |
| `cappings[].amount` | number | Yes | Ceiling for the period. |
| `pacing` | object | No | Manual `SponsoredProducts` campaigns only. Asks the platform to spread the budget rather than cap it per period. |
| `pacing.type` | string | Yes | `Automatic` or `None`. |

Automatic pacing sets the daily amount itself, so it cannot be combined with a `Daily` capping.

### Sample request

```bash theme={null}
curl -X POST "https://api.criteo.com/experimental/retail-media/accounts/12345/campaigns" \
  -H "Authorization: Bearer <MY_ACCESS_TOKEN>" \
  -H "Content-Type: application/json" \
  -H "Accept: application/json" \
  -d '{
    "data": {
      "type": "CampaignCreateModel",
      "attributes": {
        "name": "Back-to-school sponsored products",
        "campaignType": "SponsoredProducts",
        "buyType": "Auction",
        "attributionSettings": {
          "clickAttributionWindow": "OneMonth",
          "viewAttributionWindow": "OneDay",
          "clickAttributionScope": "SameSkuCategory",
          "viewAttributionScope": "SameSku"
        },
        "drawableBalanceIds": ["1122"],
        "scheduleDetails": {
          "startDate": "2026-09-01T00:00:00Z",
          "endDate": "2026-09-30T23:59:59Z"
        },
        "sponsoredProductsDetails": {
          "objective": "Conversion",
          "budget": {
            "amount": 5000.0
          }
        }
      }
    }
  }'
```

An `OnsiteDisplay` campaign carries its budget under `onsiteDisplayDetails` and sets no objective. Its budget is an amount only:

```bash theme={null}
curl -X POST "https://api.criteo.com/experimental/retail-media/accounts/12345/campaigns" \
  -H "Authorization: Bearer <MY_ACCESS_TOKEN>" \
  -H "Content-Type: application/json" \
  -H "Accept: application/json" \
  -d '{
    "data": {
      "type": "CampaignCreateModel",
      "attributes": {
        "name": "Summer display",
        "campaignType": "OnsiteDisplay",
        "buyType": "Auction",
        "attributionSettings": {
          "clickAttributionWindow": "TwoWeeks",
          "viewAttributionWindow": "TwoWeeks",
          "clickAttributionScope": "SameSkuCategory",
          "viewAttributionScope": "SameSkuCategory"
        },
        "drawableBalanceIds": ["1122"],
        "scheduleDetails": {
          "startDate": "2026-09-01T00:00:00Z",
          "endDate": "2026-09-30T23:59:59Z"
        },
        "onsiteDisplayDetails": {
          "budget": { "amount": 5000.0 }
        }
      }
    }
  }'
```

### Response attributes

All attributes below are nested under `data.attributes` in the response envelope, and the resource `type` is `CampaignResponseModel`. Alongside the attributes accepted on creation, the response carries:

| Attribute | Type | Description |
| - | - | - |
| `accountId` | string | Identifier of the account that owns the campaign. |
| `status` | string | Campaign status, derived from the status of the line items it holds. `Active` when at least one line item is active, otherwise `Inactive`. |
| `createdAt` | string | When the campaign was created. |
| `updatedAt` | string | When the campaign was last modified. |

The details object carries the stored budget back, with `amount` and, for a manual `SponsoredProducts` campaign, the `cappings` and `pacing` it holds. Only capped periods are reported.

The details object that does not match the campaign type is returned as `null`.

### Sample response

```json theme={null}
{
  "data": {
    "id": "987654321",
    "type": "CampaignResponseModel",
    "attributes": {
      "accountId": "12345",
      "name": "Back-to-school sponsored products",
      "campaignType": "SponsoredProducts",
      "buyType": "Auction",
      "status": "Inactive",
      "createdAt": "2026-09-01T10:00:00Z",
      "updatedAt": "2026-09-01T10:00:00Z",
      "attributionSettings": {
        "clickAttributionWindow": "OneMonth",
        "viewAttributionWindow": "OneDay",
        "clickAttributionScope": "SameSkuCategory",
        "viewAttributionScope": "SameSku"
      },
      "companyName": null,
      "onBehalfCompanyName": null,
      "billByRetailerId": null,
      "drawableBalanceIds": ["1122"],
      "regulatedCategory": "None",
      "scheduleDetails": {
        "startDate": "2026-09-01T00:00:00Z",
        "endDate": "2026-09-30T23:59:59Z"
      },
      "sponsoredProductsDetails": {
        "objective": "Conversion",
        "budget": {
          "amount": 5000.0
        }
      },
      "onsiteDisplayDetails": null
    }
  }
}
```

***

## Get a Campaign

<EndpointBadge method="get">
  ```http theme={null}
  https://api.criteo.com/experimental/retail-media/accounts/{accountId}/campaigns/{campaignId}
  ```
</EndpointBadge>

### Path parameters

| Parameter | Type | Required | Description |
| - | - | - | - |
| `account-id` | string | Yes | Identifier of the account that owns the campaign. |
| `campaign-id` | string | Yes | Identifier of the campaign to fetch. |

### Response

Returns the campaign as a `CampaignResponseModel`. See [Create a Campaign — Response attributes](#response-attributes) for the full field list.

| Status | Description |
| - | - |
| `200 OK` | Returns the campaign. |
| `403 Forbidden` | The account or campaign does not exist or is not accessible. |
| `404 Not Found` | No campaign with the given id exists under the account. |

***

## Update a Campaign

Selectively updates a campaign. Only the fields you include in the request are changed — omitted fields remain unchanged.

`campaignType`, `buyType`, `billByRetailerId`, and `drawableBalanceIds` cannot be changed after creation.

<EndpointBadge method="patch">
  ```http theme={null}
  https://api.criteo.com/experimental/retail-media/accounts/{accountId}/campaigns/{campaignId}
  ```
</EndpointBadge>

### Path parameters

| Parameter | Type | Required | Description |
| - | - | - | - |
| `account-id` | string | Yes | Identifier of the account that owns the campaign. |
| `campaign-id` | string | Yes | Identifier of the campaign to update. |

### Request attributes

All attributes are nested under `data.attributes`. The resource `type` is `CampaignUpdateModel`. All fields are optional — include only what you want to change.

| Attribute | Type | Description |
| - | - | - |
| `name` | string | New display name. Must be unique within the account and up to 255 characters. |
| `attributionSettings` | object | Attribution windows and scopes. Same structure as on creation; any sub-field omitted remains unchanged. |
| `scheduleDetails` | object | New flight dates. When present, both `startDate` and `endDate` are required. Only valid for campaigns that own their dates (`SponsoredProducts` and `OnsiteDisplay Auction`). |
| `sponsoredProductsDetails.budget` | object | `SponsoredProducts` only. When present, the whole budget node replaces the previous one. Accepts `amount` (nillable — send `{"value": 1000.0}` to set, `{"value": null}` to clear, omit to leave unchanged), `cappings` (array of `{type, amount}`), and `pacing.type` (`Automatic` or `None`). |
| `onsiteDisplayDetails.budget` | object | `OnsiteDisplay` only. When present, the whole budget node replaces the previous one. `amount` is required within it. |
| `companyName` | object | Nillable. Name of the company paying for the ad (EU DSA). Pass `{"value": null}` to clear. |
| `onBehalfCompanyName` | object | Nillable. Name of the company the ad runs on behalf of (EU DSA). Pass `{"value": null}` to clear. |

### Sample request

```bash theme={null}
curl -X PATCH "https://api.criteo.com/experimental/retail-media/accounts/12345/campaigns/987654321" \
  -H "Authorization: Bearer <MY_ACCESS_TOKEN>" \
  -H "Content-Type: application/json" \
  -H "Accept: application/json" \
  -d '{
    "data": {
      "type": "CampaignUpdateModel",
      "attributes": {
        "name": "Back-to-school sponsored products — updated",
        "sponsoredProductsDetails": {
          "budget": {
            "amount": { "value": 8000.0 },
            "pacing": { "type": "Automatic" }
          }
        }
      }
    }
  }'
```

### Response

Returns the updated campaign as a `CampaignResponseModel`.

| Status | Description |
| - | - |
| `200 OK` | Returns the updated campaign. |
| `400 Bad Request` | Validation error. See [Responses](#responses) for error codes. |
| `403 Forbidden` | The account or campaign does not exist or is not accessible. |
| `404 Not Found` | No campaign with the given id exists under the account. |

***

## Search Campaigns

Search campaigns under an account using optional filters and pagination.

<Note>
  Budget details in search results come from a search index and may be **eventually consistent** with the values returned by the GET endpoint. If you need guaranteed up-to-date budget figures, fetch the campaign individually. `drawableBalanceIds` is not included in search results.
</Note>

<EndpointBadge method="post">
  ```http theme={null}
  https://api.criteo.com/experimental/retail-media/accounts/{accountId}/campaigns/search
  ```
</EndpointBadge>

### Path parameters

| Parameter | Type | Required | Description |
| - | - | - | - |
| `account-id` | string | Yes | Identifier of the account to search within. |

### Request attributes

All attributes are nested under `data.attributes`. The resource `type` is `CampaignSearchModel`. All fields are optional. Values within a single filter are ORed; distinct filters are ANDed.

| Attribute | Type | Description |
| - | - | - |
| `campaignIdFilter` | array of strings | Return only campaigns with these ids. |
| `campaignTypeFilter` | array of strings | `SponsoredProducts`, `OnsiteDisplay`. |
| `campaignStatusFilter` | array of strings | `Active`, `Inactive`. |
| `buyTypeFilter` | array of strings | `Auction`, `PreferredDeals`, `Sponsorship`. |
| `limit` | integer | Maximum number of campaigns to return per page. |
| `offset` | integer | Number of matching campaigns to skip. |

### Sample request

```bash theme={null}
curl -X POST "https://api.criteo.com/experimental/retail-media/accounts/12345/campaigns/search" \
  -H "Authorization: Bearer <MY_ACCESS_TOKEN>" \
  -H "Content-Type: application/json" \
  -H "Accept: application/json" \
  -d '{
    "data": {
      "type": "CampaignSearchModel",
      "attributes": {
        "campaignTypeFilter": ["SponsoredProducts"],
        "campaignStatusFilter": ["Active"],
        "limit": 25,
        "offset": 0
      }
    }
  }'
```

### Response

Returns a paginated list of campaigns as `CampaignResponseModel` entries. See [Create a Campaign — Response attributes](#response-attributes) for the full field list.

| Field | Type | Description |
| - | - | - |
| `metadata.count` | integer | Total number of campaigns matching the filters, across all pages. |
| `metadata.limit` | integer | Page size applied to this response. |
| `metadata.offset` | integer | Offset applied to this response. |

| Status | Description |
| - | - |
| `200 OK` | Returns matching campaigns and pagination metadata. |
| `403 Forbidden` | The account does not exist or is not accessible. |

***

## Responses

Validation failures return `type: validation` and a `code` identifying the rule that rejected the request.

| Status | Code | Description |
| - | - | - |
| `201 Created` | | Returns the created campaign. |
| `400 Bad Request` | `campaign-name-cannot-be-null-or-whitespace` | The campaign name is missing or blank. |
| `400 Bad Request` | `invalid-name` | The campaign name exceeds 255 characters. |
| `400 Bad Request` | `campaign-name-already-exists` | Another campaign in the account already uses this name. |
| `400 Bad Request` | `json-serialization-error` | A value is outside its enum, for example an unsupported `campaignType`, `buyType` or `objective`. |
| `400 Bad Request` | `invalid-objective-campaign-type` | The objective is not accepted for the campaign type. |
| `400 Bad Request` | `invalid-objective-buy-type` | An automatic objective was set without the `Auction` buy type. |
| `400 Bad Request` | `missing-flight-dates` | `scheduleDetails` is absent. |
| `400 Bad Request` | `invalid-date-range` | The start date is after the end date. |
| `400 Bad Request` | `invalid-cd-flight-dates` | An `OnsiteDisplay` `Auction` campaign was given the indefinite end date `9999-12-30T00:00:00Z`. |
| `400 Bad Request` | `manual-objective-refuses-budget` | A budget was supplied for a manual `OnsiteDisplay` campaign. |
| `400 Bad Request` | `objective-requires-budget` | An objective other than `Manual` was set without a budget. |
| `400 Bad Request` | `dynamic-objective-requires-end-date` | An objective other than `Manual` was given the indefinite end date `9999-12-30T00:00:00Z`. It spends its budget over a flight, so it needs a real one. |
| `400 Bad Request` | `dynamic-objective-budget-is-amount-only` | Cappings or pacing were supplied for an objective other than `Manual`. |
| `400 Bad Request` | `missing-budget-amount` | The budget carries no amount. |
| `400 Bad Request` | `invalid-budget-amount` | The budget amount is not greater than zero. |
| `400 Bad Request` | `invalid-budget-capping-amount` | A capping amount is not greater than zero. |
| `400 Bad Request` | `duplicate-budget-capping` | The budget carries more than one capping for the same period. |
| `400 Bad Request` | `invalid-budget-pacing` | Automatic pacing was combined with a `Daily` capping. |
| `400 Bad Request` | `invalid-company-name` | The company name exceeds 255 characters. |
| `400 Bad Request` | `invalid-on-behalf` | The on-behalf company name exceeds 255 characters. |
| `400 Bad Request` | `only-supply-can-set-paying-company-name` | Only supply accounts can set the company name paying for the ad. |
| `400 Bad Request` | `only-supply-can-set-on-behalf` | Only supply accounts can set the company name the ad is on behalf of. |
| `400 Bad Request` | `invalid-retailer-billed-retailer-id` | Only network demand accounts can set `billByRetailerId`. |
| `400 Bad Request` | `invalid-click-lookback` | The click attribution window is not a supported value. |
| `400 Bad Request` | `invalid-view-lookback` | The view attribution window is not a supported value. |
| `400 Bad Request` | `invalid-click-match-level` | The click attribution scope is not a supported value. |
| `400 Bad Request` | `invalid-view-match-level` | The view attribution scope is not a supported value. |
| `400 Bad Request` | `click-attribution-window-not-greater-than-view-attribution-window` | The click attribution window is shorter than the view attribution window. |
| `400 Bad Request` | `click-attribution-scope-smaller-than-view-attribution-scope` | The click attribution scope is narrower than the view attribution scope. |
| `403 Forbidden` | `forbidden` | The account, or a referenced drawable balance, does not exist or is not accessible. For security, the response does not identify which condition occurred. |
