> ## 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.

# Managing Campaigns

## Overview

In Single-Seller setups, you do not create seller-campaigns directly. Instead, the underlying per-seller campaign is created implicitly by Criteo when you create the first valid budget for a `(sellerId, templateCampaignId)` pair.

Once created, you can configure and control the campaign through two main surfaces:

* **Budget suspension** (to pause/resume the campaign).
* **productSet configuration** (to restrict which products can be advertised).

## The Single-Seller campaign entity

A **Single-Seller campaign** (identified by `sellerCampaignId`) is the per-seller campaign derived from the template.

Key characteristics:

* Created implicitly when the first valid budget for a `(sellerId, templateCampaignId)` pair is accepted.
* There may be a short asynchronous provisioning delay before delivery begins after creation.
* Used by MPO stats endpoints when querying performance at the seller-campaign level.
* Can have **at most one** `productSet` attached at any given time.

To retrieve seller-campaigns and inspect their current state:

```http theme={null}
GET /marketplace-performance-outcomes/seller-campaigns
```

### Suspension reasons

When a Single-Seller campaign is not delivering, the API returns a `suspensionReasons` array explaining why.

<table>
  <thead>
    <tr>
      <th>
        <p>
          Reason
        </p>
      </th>

      <th>
        <p>
          Description
        </p>
      </th>

      <th>
        <p>
          Action required
        </p>
      </th>
    </tr>
  </thead>

  <tbody>
    <tr>
      <td>
        <p>
          ManuallyStopped
        </p>
      </td>

      <td>
        <p>
          Campaign manually paused
        </p>
      </td>

      <td>
        <p>
          Resume via budget
        </p>
      </td>
    </tr>

    <tr>
      <td>
        <p>
          NoBudgetDefined
        </p>
      </td>

      <td>
        <p>
          No valid budget linked
        </p>
      </td>

      <td>
        <p>
          Create a budget
        </p>
      </td>
    </tr>

    <tr>
      <td>
        <p>
          NoCpcDefined
        </p>
      </td>

      <td>
        <p>
          No CPC set
        </p>
      </td>

      <td>
        <p>
          Set CPC via API
        </p>
      </td>
    </tr>

    <tr>
      <td>
        <p>
          NoMoreBudget
        </p>
      </td>

      <td>
        <p>
          Budget fully spent
        </p>
      </td>

      <td>
        <p>
          Create a new budget
        </p>
      </td>
    </tr>

    <tr>
      <td>
        <p>
          RemovedFromCatalog
        </p>
      </td>

      <td>
        <p>
          Products removed
        </p>
      </td>

      <td>
        <p>
          Restore products
        </p>
      </td>
    </tr>

    <tr>
      <td>
        <p>
          NotYetStarted
        </p>
      </td>

      <td>
        <p>
          Newly created
        </p>
      </td>

      <td>
        <p>
          Wait
        </p>
      </td>
    </tr>

    <tr>
      <td>
        <p>
          NoMoreDailyBudget
        </p>
      </td>

      <td>
        <p>
          Daily limit reached
        </p>
      </td>

      <td>
        <p>
          Wait for daily reset
        </p>
      </td>
    </tr>

    <tr>
      <td>
        <p>
          Other
        </p>
      </td>

      <td>
        <p>
          Internal/system issue
        </p>
      </td>

      <td>
        <p>
          Contact your Criteo team
        </p>
      </td>
    </tr>
  </tbody>
</table>

#### Checking campaign status

```json JSON theme={null}
{
"id": "SELLER_123.TEMPLATE_CAMPAIGN_456",
"sellerId": "SELLER_123",
"campaignId": "TEMPLATE_CAMPAIGN_456",
"suspendedSince": "2026-04-28T10:00:00Z",
"suspensionReasons": ["NoMoreDailyBudget"]
}
```

<br />

* If `suspendedSince` is `null` and `suspensionReasons` is empty → the campaign is active.
* If `suspendedSince` is set and one or more reasons are present → the campaign is currently suspended.

## Suspending and resuming a Single-Seller campaign

You do **not** pause Single-Seller campaigns directly via a campaign-level endpoint. Instead, you control campaign run state by suspending or resuming the associated **budget**.

### Suspend (pause) a campaign

To stop spend for a seller, set `isSuspended: true` on the active budget:

<CodeGroup>
  ```http POST theme={null}
  POST  https://api.criteo.com/2026-01/marketing-solutions/marketplace-performance-outcomes/budgets/{budgetId}
  Content-Type: application/json
  ```

  ```json JSON theme={null}
  {
  "budgetId": "789",
  "isSuspended": true
  }
  ```
</CodeGroup>

**Expected behavior:**

* The budget becomes inactive and the associated Single-Seller campaign stops serving.
* The budget remains present in the API for auditing and historical purposes.

### Resume a campaign

To resume spend, set `isSuspended: false`:

<CodeGroup>
  ```http POST theme={null}
  POST  https://api.criteo.com/2026-01/marketing-solutions/marketplace-performance-outcomes/budgets/{budgetId}
  Content-Type: application/json
  ```

  ```json JSON theme={null}
  json
  {
  "budgetId": "789",
  "isSuspended": false
  }
  ```
</CodeGroup>

**Guidance:**

* If the `endDate` is in the past, resuming will **not** restart delivery; you may need to create a new budget with a future period.
* If there is a future budget scheduled for the same `(sellerId, templateCampaignId)`, the campaign will automatically resume when that future budget’s `startDate` is reached (assuming that future budget is not itself suspended).

### Cancel a scheduled future budget

To logically cancel a future, not-yet-active budget:

<CodeGroup>
  ```http POST theme={null}
  POST  https://api.criteo.com/2026-01/marketing-solutions/marketplace-performance-outcomes/budgets/{budgetId}
  Content-Type: application/json
  ```

  ```json JSON theme={null}
  {
  "budgetId": "FUTURE_BUDGET_1011",
  "isSuspended": true
  }
  ```
</CodeGroup>

After suspension:

* Treat the budget as **canceled**.
* You can create a new budget covering the same period if needed; suspended budgets do **not** block new ones for the same dates.

## productSet for Single-Seller campaigns

The `productSet` feature lets you restrict a Single-Seller campaign to a specific list of product IDs from the seller’s catalog.

### Overview

A `productSet` is a **whitelist of product IDs**:

* Only products whose external item IDs are in the `productSet` are eligible to be advertised by that Single-Seller campaign.

The `productSet`:

* Is configured at the **seller-campaign** level.
* Applies to **all ads** served by that campaign.
* Is **optional**; if no `productSet` is configured, the campaign can use all eligible products from the seller’s catalog (subject to other targeting and policy constraints).
* There is at most **one** `productSet` per Single-Seller campaign at any given time.

> `productSet` configuration is only supported for Single-Seller campaigns associated with a Single-Seller template. Do not attempt to use `productSet` on legacy multi-seller campaigns or other campaign types.

## Inspecting the current productSet

When you retrieve a Single-Seller campaign, the response will:

* Return no `productSet` or `productSet: null` if no `productSet` has ever been configured.
* Return a structured rule when a `productSet` is configured.

**Example response fragment:**

```json JSON theme={null}
{
"data": [
{
"id": "SELLER_123.TEMPLATE_CAMPAIGN_456",
"sellerId": "SELLER_123",
"campaignId": "TEMPLATE_CAMPAIGN_456",
"productSet": {
"rules": [
{
"operator": "IsIn",
"field": "ExternalItemId",
"values": [
"SKU_1",
"SKU_2",
"SKU_3"
]
}
],
"productSetStatus": "Valid",
"productSetNumberOfProducts": 3
}
}
]
}
```

**Interpretation:**

* `productSet.rules` contains an array of rules; in Single-Seller mode, only a **single rule** is supported.
* Each rule:
  * `operator: "IsIn"` — inclusion list.
  * `field: "ExternalItemId"` — field in the seller’s catalog feed.
  * `values` — list of product IDs (strings).
* If `productSet` is `null` or omitted, no additional product-ID filter is applied.

## Create / Update: Attaching a productSet

To create or update the `productSet` for a Single-Seller campaign, call the seller-campaign update endpoint with a `productSet` object.

```http theme={null}
PATCH  https://api.criteo.com/2026-01/marketing-solutions/marketplace-performance-outcomes/seller-campaigns
Content-Type: application/json
```

**Example request body:**

```json JSON theme={null}
[
{
"id": "SELLER_123.TEMPLATE_CAMPAIGN_456",
"productSet": {
"value": [
{
"operator": "IsIn",
"field": "ExternalItemId",
"values": [
"SKU_001", "SKU_002", "SKU_003", "SKU_004", "SKU_005",
"SKU_006", "SKU_007", "SKU_008", "SKU_009", "SKU_010", "SKU_011"
]
}
]
}
}
]
```

**Behavior:**

* If the Single-Seller campaign had no `productSet` before, this **creates and attaches** a new `productSet`.
* If a `productSet` already existed, this **replaces** the existing rule with the new one (it is not additive).
* After a successful update, subsequent GETs for this campaign will return the new `productSet` configuration.

**Constraints:**

* Only:
  * `operator = "IsIn"` or `operator = "IsNotIn"`, with
  * `field = "ExternalItemId"`\
    is supported for Single-Seller usage.
* A **minimum number of product IDs per `productSet`** may be enforced per advertiser (default: 20). Providing fewer IDs than configured will return a **4xx** error.

## Delete / Unset: Removing the productSet

To remove the `productSet` and revert to no additional product filter, set `productSet.value` to `null`:

```json JSON theme={null}
[
{
"id": "SELLER_123.TEMPLATE_CAMPAIGN_456",
"productSet": {
"value": null
}
}
]
```

**Expected behavior:**

* The Single-Seller campaign stops using a `productSet` to filter products.
* A subsequent GET for this campaign will show `productSet: null` (or omit the field, depending on the schema).
* Products are once again selected from the seller’s catalog without additional ID whitelisting, subject to other targeting rules and policies.

## Supported productSet patterns

<table>
  <thead>
    <tr>
      <th>
        <p>
          Pattern
        </p>
      </th>

      <th>
        <p>
          Supported?
        </p>
      </th>

      <th>
        <p>
          Notes
        </p>
      </th>
    </tr>
  </thead>

  <tbody>
    <tr>
      <td>
        <p>
          Single-Seller + no productSet (default)
        </p>
      </td>

      <td>
        <p>
          Yes
        </p>
      </td>

      <td>
        <p>
          All eligible products from the seller are used.
        </p>
      </td>
    </tr>

    <tr>
      <td>
        <p>
          Single-Seller + one

          <code>
            IsIn
          </code>

          rule on

          <code>
            ExternalItemId
          </code>
        </p>
      </td>

      <td>
        <p>
          Yes
        </p>
      </td>

      <td>
        <p>
          Recommended pattern for SKU restriction.
        </p>
      </td>
    </tr>

    <tr>
      <td>
        <p>
          Multiple

          <code>
            productSet
          </code>

          rules per Single-Seller
        </p>
      </td>

      <td>
        <p>
          No
        </p>
      </td>

      <td>
        <p>
          Updates replace the existing rule.
        </p>
      </td>
    </tr>

    <tr>
      <td>
        <p>
          <code>
            productSet
          </code>

          on a multi-seller campaign
        </p>
      </td>

      <td>
        <p>
          No
        </p>
      </td>

      <td />
    </tr>
  </tbody>
</table>

***

## Workflow: Restrict products for a seller

1. **Obtain product IDs** from your catalog or internal systems for the seller.
2. **Attach `productSet`** via:

```http theme={null}
PATCH /marketplace-performance-outcomes/seller-campaigns
```

with:

* `operator: "IsIn"`
* `field: "ExternalItemId"`
* `values: ["SKU_1", "SKU_2", ...]`

3. **Update or remove later as needed:**

   * Update the `values` list to change the whitelist.
   * Set `productSet.value` to `null` to remove the filter entirely.
