---
title: "Video Carousel Creative Partner Integration Guide"
url: "https://api-catalog-test.8451.com/apis/kroger-ad-platform-api-1/docs/documentation/video-carousel-creative-partner-integration-guide"
image: "https://api-catalog-test.8451.com/_og/d/c_Ocean.takumi,title_Video+Carousel+Creative+Partner+Integration+Guide,props_eyJ0aGVtZSI6eyJtb2RlIjoibGlnaHQiLCJjb2xvcnMiOnsicHJpbWFyeSI6IiM4NDUxRUMifX19,p_Ii9hcGlzL2tyb2dlci1hZC1wbGF0Zm9ybS1hcGktMS9kb2NzL2RvY3VtZW50YXRpb24vdmlkZW8tY2Fyb3VzZWwtY3JlYXRpdmUtcGFydG5lci1pbnRlZ3JhdGlvbi1ndWlkZSI,s_SgeDtC1Dz-A4VFM-.png"
---

# Video Carousel Creative — Partner Integration Guide

## [Overview](#overview)

This guide walks you through the end-to-end workflow for creating and managing video carousel creatives using the Kroger Ad Platform (KAP) API. Video carousels allow you to include video creative assets in your Promoted Product Carousel (PPC) campaigns.

Unlike standard carousels, video carousels require a **creative approval step** before the campaign can be published. This guide covers each step from campaign creation through creative approval.

> **Note:** This guide covers the **creative workflow** specifically for video carousels. For general campaign setup (budgets, targeting, bidding), refer to the [Create a Campaign](https://mp-help.8451.com/mp-help/content/how-to/create-campaign.htm) guide.

---

## [Before You Begin](#before-you-begin)

Make sure you have the following before starting the video carousel creative workflow:

| Prerequisite           | Details                                                                          |
| :--------------------- | :------------------------------------------------------------------------------- |
| API access             | Valid API credentials for the KAP API (api.8451.com/kap/). Contact your account representative if you do not have credentials. |
| Advertiser account     | An active advertiser account with permissions to create campaigns and manage creatives. |
| Creative contact       | A creative contact must be associated with your campaign. This is required for the creative workflow. |
| Video and image assets | Your video files and any companion image assets ready for upload. Refer to the asset specifications for supported formats and dimensions. |

---

## [Workflow Overview](#workflow-overview)

The video carousel creative workflow consists of four phases:

1.  **Campaign setup** — Create a campaign and a Carousel-Type ad group.
2.  **Asset management** — Upload your video and image assets.
3.  **Creative workflow** — Create, verify, update, and submit your creative for review.
4.  **Review and activation** — After creative approval, publish your campaign.

The diagram (mermaid flowchart) below shows the complete workflow:

```mermaid
flowchart TD
    S1["1. POST /v2/campaigns<br/>Create CAROUSEL campaign"] --> S2["2. POST /v2/ad_groups<br/>Create Video ad group<br/>Set creativeType: VIDEO"]
    S2 --> S3["3. GET creative<br/>Retrieve design ID + field IDs"]
    S3 --> S4A["4a. POST /v2/creative_asset/upload_url<br/>Get pre-signed URL per asset<br/>Optional(if have own public URL)"]
    S4A --> S4B["4b. PUT pre-signed URL<br/>Upload file bytes."]
    S4B --> S4C["4c. POST /v2/creative_asset<br/>Register the uploaded file"]
    S4C --> MORE{"More assets<br/>to upload?"}
    MORE -- Yes --> S4A
    MORE -- No --> S5["5. GET /v2/creative_asset/CREATIVE_ASSET_ID<br/>Wait until video status = READY"]
    S5 --> S6["6. PATCH /v2/ad_groups/ExternalAdGroupId/creative<br/>Assign assets to field IDs"]
    S6 --> VERIFY{"validationErrors<br/>clear?"}
    VERIFY -- No --> FIX["Resolve validation errors"]
    FIX --> S6
    VERIFY -- Yes --> S7["7. PATCH v2/ad_groups/ExternalAdGroupId/creative/status<br/>Submit: UNDER_REVIEW"]
    S7 --> OUTCOME{"Review outcome"}
    OUTCOME -- APPROVED --> SERVE["Ad group eligible to serve"]
    OUTCOME -- REJECTED --> REFETCH["Fetch feedback<br/>Re-upload corrected assets"]
    REFETCH --> S4A
```

---

## [Step-by-Step Instructions](#step-by-step-instructions)

### [Phase 1: Campaign Setup](#phase-1-campaign-setup)

#### [Step 1 — Create a CAROUSEL Campaign](#step-1-create-a-carousel-campaign)

```text
POST /v2/campaigns
```

Set `campaignType` to `CAROUSEL`.

**Request**

```json
{
  "name": "Summer Video Carousel",
  "campaignType": "CAROUSEL",
  "status": "DRAFT",
  "startDate": "2026-07-01",
  "endDate": "2026-07-31",
  "budgetAmount": 200000,
  "budgetType": "MONTHLY",
  "pacingType": "EVEN",
  "accountId": 100,
  "advertiserIds": [12],
  "billingContactId": 102,
  "billingAddressId": 5001
}
```

**Response** — `201 Created`

```json
{
  "data": {
    "id": 8001,
    "name": "Summer Video Carousel",
    "campaignType": "CAROUSEL",
    "status": "DRAFT",
    .....
  }
}
```

> Save `data.id` as `CAMPAIGN_ID`.

---

#### [Step 2 — Create a Video Carousel Ad Group](#step-2-create-a-video-carousel-ad-group)

```text
POST /v2/ad_groups
```

Set `creativeType` to `VIDEO`. Include at least three entity (product UPC) and one placement target — these are required for the platform to initialize the creative design group in step 3.

The `carouselHeadline` and `carouselSubtext` become the visible copy displayed on the rendered carousel. The ad group budget must be less than the campaign budget.

**Request**

```json
{
  "campaignId": 8001,
  "name": "Summer Video Carousel Ad Group",
  "startDate": "2026-07-01",
  "endDate": "2026-07-31",
  "budgetAmount": 20000,
  "budgetType": "MONTHLY",
  "status": "DRAFT",
  "baseBid": 1.25,
  "carouselHeadline": "Fresh picks for summer",
  "carouselSubtext": "Shop now at Kroger",
  "creativeType": "VIDEO",
  "entities": [
    {
      "id": 1000231,
      "useBaseBid": true,
      "deleted": false
    }
  ],
  "targets": [
    {
      "type": 1,
      "id": 42
    }
  ]
}
```

**Response** — `201 Created`

```json
{
  "data": {
    "adGroupId": 9001,
    "campaignId": 8001,
    "name": "Summer Video Carousel Ad Group",
    "creativeType": "Video",
    "status": "DRAFT",
    .....
  }
}
```

> Save `data.adGroupId` as `AD_GROUP_ID`.

---

#### [Step 3 — Retrieve the Creative Design ID and Field IDs](#step-3-retrieve-the-creative-design-id-and-field-ids)

```text
GET /v2/ad_groups/{AD_GROUP_ID}/creative?shape=API&include=validationErrors
```

Creating a video carousel ad group automatically initializes a creative design group. This call returns the `designId` and the `fieldId` for each asset slot. You will need these IDs in step 6.

**Query parameters**

| Parameter | Value            | Purpose                                                                          |
| :-------- | :--------------- | :------------------------------------------------------------------------------- |
| shape     | API              | Returns the machine-readable API shape with designs, groupFields, assetReferences, and accountInfo. When omitted, these nested fields are omitted from the response (not included in the requested shape) even though the data is still saved. |
| include   | validationErrors | Returns any current validation errors                                            |

**Response** — `200 OK`

```json
{
  "data": {
    "id": "creative-group-abc123",
    "status": "DRAFT",
    "designs": [
      {
        "id": "design-xyz789",
        "name": "Carousel Video",
        "fields": [
          { "id": "field-thumb-001", "displayName": "Thumbnail Image", "fieldDataType": "ZONE" },
          { "id": "field-video-002", "displayName": "Video", "fieldDataType": "ZONE" },
          { "id": "field-audio-003", "displayName": "Video Audio Description Track", "fieldDataType": "ZONE" },
          { "id": "field-subs-004", "displayName": "Video Captions", "fieldDataType": "ZONE" }
        ]
      },
      .....
    ],
    .....
  }
}
```

Save `data.designs[0].id` as `DESIGN_ID`. Save each `fields[].id` mapped to its `displayName`:

| Display name                                             | Save as            |
| :------------------------------------------------------- | :----------------- |
| Thumbnail Image                                          | THUMBNAIL_FIELD_ID |
| Video                                                    | VIDEO_FIELD_ID     |
| Video Audio Description Track or Video Description Track | AUDIO_FIELD_ID     |
| Video Captions                                           | SUBTITLES_FIELD_ID |

Each field also returns a `constraints` object describing accepted file types, size limits, and dimension requirements. Read these before uploading to validate assets client-side.

---

### [Phase 2: Asset Management](#phase-2-asset-management)

#### [Step 4 — Upload Creative Assets](#step-4-upload-creative-assets)

Repeat the following three-request sequence for each asset file. Assets can be uploaded in parallel.

**Required and optional assets**

| Asset                | Required | Accepted MIME types   | Notes                                                              |
| :------------------- | :------- | :-------------------- | :----------------------------------------------------------------- |
| Thumbnail image      | Yes      | image/jpeg, image/png | Check constraints.media from step 3 for dimension requirements     |
| Video                | Yes      | video/mp4             | Must reach READY status before assignment (step 5)                 |
| Audio description    | No       | audio/mpeg, audio/wav | Recommended — improves accessibility for visually impaired viewers |
| Subtitles / captions | No       | text/vtt              | Recommended — required for WCAG 2.1 AA compliance                  |

##### Step 4a — Get a Pre-signed Upload URL (Optional if you have your own public URL)

```text
POST /v2/creative_asset/upload_url
```

**Request**

```json
{
  "fileName": "summer-hero.mp4",
  "contentType": "video/mp4"
}
```

**Response** — `201 Created`

```json
{
  "data": {
    "uploadUrl": "https://storage.example.com/assets/summer-hero.mp4?sig=...",
    "expiresAt": "2026-07-01T14:00:00Z"
  }
}
```

> Save `data.uploadUrl`. The URL expires — complete the upload before `expiresAt`.

##### Step 4b — Upload the File

```text
PUT {uploadUrl}
```

Send the file bytes directly to the Azure Blob Storage URL. This request does **not** use your KAP `Authorization` header. Use the Azure-specific header instead.

**Required header**

```text
x-ms-blob-type: BlockBlob
Content-Type: video/mp4
```

A `2xx` response from Azure confirms the file was stored. On failure, repeat steps 4a–4b (the upload URL cannot be reused after a failed upload).

##### Step 4c — Register the Asset

```text
POST /v2/creative_asset
```

**Request**

```json
{
  "sourceUrl": "https://storage.example.com/assets/summer-hero.mp4?sig=...",
  "fileName": "summer-hero.mp4"
}
```

Use the same `uploadUrl` from step 4a as the `sourceUrl`.

**Response** — `201 Created`

```json
{
  "data": {
    "id": "asset-vid-55512",
    "fileName": "summer-hero.mp4",
    "status": "PROCESSING",
    "mimeType": "video/mp4"
  }
}
```

Save `data.id` as the asset ID for this file. Repeat steps 4a–4c for each asset:

| Asset             | Save as            |
| :---------------- | :----------------- |
| Thumbnail image   | THUMBNAIL_ASSET_ID |
| Video             | VIDEO_ASSET_ID     |
| Audio description | AUDIO_ASSET_ID     |
| Subtitles         | SUBTITLES_ASSET_ID |

---

#### [Step 5 — Wait for the Video Asset to Be Ready](#step-5-wait-for-the-video-asset-to-be-ready)

```text
GET /v2/creative_asset/{VIDEO_ASSET_ID}
```

Video files are transcoded asynchronously. Poll this endpoint until `data.status` is `READY` before proceeding to step 6. Assign the video asset while it is still `PROCESSING` and the creative will fail validation.

**Asset status values**

| Status     | Meaning                                                 |
| :--------- | :------------------------------------------------------ |
| PROCESSING | Transcoding in progress — continue polling              |
| READY      | Asset is ready to be assigned                           |
| FAILED     | Transcoding failed — re-upload the file (repeat step 4) |

**Recommended polling strategy:** poll every 5 seconds for up to 6 minutes. If the asset has not reached `READY` within that window, surface an error and allow the user to re-upload.

**Response when ready** — `200 OK`

```json
{
  "data": {
    "id": "asset-vid-55512",
    "fileName": "summer-hero.mp4",
    "status": "READY",
    "mimeType": "video/mp4",
    "durationInSeconds": 28,
    "fileSize": 104857600,
    "dimensions": { "width": 1920, "height": 1080, "unit": "px" }
  }
}
```

> Non-video assets (thumbnail, audio, subtitles) do not require polling — they are available immediately after step 4c.

---

### [Phase 3: Creative Workflow](#phase-3-creative-workflow)

#### [Step 6 — Assign Assets to the Creative](#step-6-assign-assets-to-the-creative)

```text
PATCH /v2/ad_groups/{AD_GROUP_ID}/creative?shape=API
```

Assign each uploaded asset to its matching creative field using the IDs collected in steps 3 and 4. Set `persistChanges` to `true` to save the design.

**Request**

```json
{
  "persistChanges": true,
  "designs": [
    {
      "id": "design-xyz789",
      "fields": [
        { "id": "field-thumb-001", "assetId": "asset-img-33301" },
        { "id": "field-video-002", "assetId": "asset-vid-55512" },
        { "id": "field-audio-003", "assetId": "asset-aud-77703" },
        { "id": "field-subs-004", "assetId": "asset-vtt-88804" }
      ]
    }
  ]
}
```

Omit fields for assets you did not upload (e.g., audio description and subtitles if not provided).

**Response** — `200 OK`

```json
{
  "data": {
    "id": "creative-group-abc123",
    "status": "DRAFT",
    "designs": [
      {
        "id": "design-xyz789",
        "fields": [
          {
            "id": "field-thumb-001",
            "assetReference": "asset-img-33301",
            "displayName": "Thumbnail Image"
          },
          {
            "id": "field-video-002",
            "assetReference": "asset-vid-55512",
            "displayName": "Video"
          }
        ]
      },
      .....
    ],
    .....
  }
}
```

**Verify before submitting:** Fetch the creative with `include=validationErrors` to confirm no required fields are missing:

```text
GET /v2/ad_groups/{AD_GROUP_ID}/creative?shape=API&include=validationErrors
```

If `included.validationErrors` contains entries, resolve them before proceeding to step 7.

---

### [Phase 4: Review and Activation](#phase-4-review-and-activation)

#### [Step 7 — Submit the Creative for Review](#step-7-submit-the-creative-for-review)

```text
PATCH /v2/ad_groups/{AD_GROUP_ID}/creative/status
```

**Request — first submission**

```json
{
  "status": "UNDER_REVIEW",
  "comment": "Creative ready for review."
}
```

**Request — resubmission after rejection**

```json
{
  "status": "RE_SUBMITTED",
  "comment": "Updated video and thumbnail per reviewer feedback."
}
```

**Response** — `200 OK`

```json
{
  "data": {
    "id": "creative-group-abc123",
    "status": "UNDER_REVIEW"
  }
}
```

Once submitted, the KAP review team will evaluate the creative. The creative status will transition to `APPROVED` or `REJECTED`. When `REJECTED`, the response includes reviewer feedback; update the relevant assets and resubmit using `RE_SUBMITTED`.

---

## [Endpoints Quick Reference](#endpoints-quick-reference)

| Step | Method | Endpoint                                                                | Description                                                    |
| :--- | :----- | :---------------------------------------------------------------------- | :------------------------------------------------------------- |
| 1    | POST   | /v2/campaigns                                                           | Create a CAROUSEL campaign                                     |
| 2    | POST   | /v2/ad_groups                                                           | Create a Video carousel ad group                               |
| 3    | GET    | /v2/ad_groups/{AD_GROUP_ID}/creative?shape=API&include=validationErrors | Retrieve the creative design ID and field IDs                  |
| 4a   | POST   | /v2/creative_asset/upload_url                                           | Get a pre-signed upload URL for each asset                     |
| 4b   | PUT    | {uploadUrl}                                                             | Upload the file bytes to the pre-signed Azure Blob Storage URL |
| 4c   | POST   | /v2/creative_asset                                                      | Register the uploaded asset                                    |
| 5    | GET    | /v2/creative_asset/{VIDEO_ASSET_ID}                                     | Wait for the video asset to reach READY status                 |
| 6    | PATCH  | /v2/ad_groups/{AD_GROUP_ID}/creative?shape=API                          | Assign uploaded assets to the creative fields                  |
| 6    | GET    | /v2/ad_groups/{AD_GROUP_ID}/creative?shape=API&include=validationErrors | Verify validation errors are cleared before submission         |
| 7    | PATCH  | /v2/ad_groups/{AD_GROUP_ID}/creative/status                             | Submit the creative for review or resubmit after rejection     |
| 8    | —      | —                                                                       | Creative review & approval                                     |

---

## [Video Carousels vs. Standard Carousels](#video-carousels-vs-standard-carousels)

The table below highlights the key differences between video carousel and standard (image-only) carousel workflows.

| Feature                    | Standard Carousel | Video Carousel                |
| :------------------------- | :---------------- | :---------------------------- |
| Asset types                | Images only       | Videos + images               |
| Creative review required   | ✕ No              | ✓ Yes — mandatory             |
| Publish before approval    | ✓ Yes             | ✕ No — blocked until approved |
| Asset upload step required | ✕ No              | ✓ Yes (pre-signed URL)        |
| Reuse TOA creative         | N/A               | ✓ Yes — same creative entity  |

---

## [Common Errors](#common-errors)

| Cause                                                                   | Resolution                                               |
| :---------------------------------------------------------------------- | :------------------------------------------------------- |
| Attempting to activate a campaign before the video creative is approved | Wait for creative approval, then retry activation        |
| Uploaded asset does not meet format or size requirements                | Verify asset specifications and re-upload                |
| Pre-signed upload URL has expired                                       | Request a new upload URL (Step 4a) and retry             |
| Attempting to modify a creative that is under review                    | Wait for review to complete before making changes        |
| Required accountInfo fields are missing                                 | Include all required fields in the creative request body |