Video Carousel Creative — Partner Integration Guide

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


Before You Begin

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

PrerequisiteDetails
API accessValid API credentials for the KAP API (api.8451.com/kap/). Contact your account representative if you do not have credentials.
Advertiser accountAn active advertiser account with permissions to create campaigns and manage creatives.
Creative contactA creative contact must be associated with your campaign. This is required for the creative workflow.
Video and image assetsYour video files and any companion image assets ready for upload. Refer to the asset specifications for supported formats and dimensions.

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:


Step-by-Step Instructions

Phase 1: Campaign Setup

POST /v2/campaigns

Set campaignType to CAROUSEL.

Request

{
  "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
}

Response201 Created

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

Save data.id as CAMPAIGN_ID.


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

{
  "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
    }
  ]
}

Response201 Created

{
  "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

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

ParameterValuePurpose
shapeAPIReturns the machine-readable API shape
includevalidationErrorsReturns any current validation errors

Response200 OK

{
  "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 nameSave as
Thumbnail ImageTHUMBNAIL_FIELD_ID
VideoVIDEO_FIELD_ID
Video Audio Description Track or Video Description TrackAUDIO_FIELD_ID
Video CaptionsSUBTITLES_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

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

AssetRequiredAccepted MIME typesNotes
Thumbnail imageYesimage/jpeg, image/pngCheck constraints.media from step 3 for dimension requirements
VideoYesvideo/mp4Must reach READY status before assignment (step 5)
Audio descriptionNoaudio/mpeg, audio/wavRecommended — improves accessibility for visually impaired viewers
Subtitles / captionsNotext/vttRecommended — required for WCAG 2.1 AA compliance
Step 4a — Get a Pre-signed Upload URL (Optional if you have your own public URL)
POST /v2/creative_asset/upload_url

Request

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

Response201 Created

{
  "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
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

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
POST /v2/creative_asset

Request

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

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

Response201 Created

{
  "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:

AssetSave as
Thumbnail imageTHUMBNAIL_ASSET_ID
VideoVIDEO_ASSET_ID
Audio descriptionAUDIO_ASSET_ID
SubtitlesSUBTITLES_ASSET_ID

Step 5 — Wait for the Video Asset to Be Ready

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

StatusMeaning
PROCESSINGTranscoding in progress — continue polling
READYAsset is ready to be assigned
FAILEDTranscoding 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 ready200 OK

{
  "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

Step 6 — Assign Assets to the Creative

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

{
  "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).

Response200 OK

{
  "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:

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

Step 7 — Submit the Creative for Review

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

Request — first submission

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

Request — resubmission after rejection

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

Response200 OK

{
  "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

StepMethodEndpointDescription
1POST/v2/campaignsCreate a CAROUSEL campaign
2POST/v2/ad_groupsCreate a Video carousel ad group
3GET/v2/ad_groups/{AD_GROUP_ID}/creative?shape=API&include=validationErrorsRetrieve the creative design ID and field IDs
4aPOST/v2/creative_asset/upload_urlGet a pre-signed upload URL for each asset
4bPUT{uploadUrl}Upload the file bytes to the pre-signed Azure Blob Storage URL
4cPOST/v2/creative_assetRegister the uploaded asset
5GET/v2/creative_asset/{VIDEO_ASSET_ID}Wait for the video asset to reach READY status
6PATCH/v2/ad_groups/{AD_GROUP_ID}/creative?shape=APIAssign uploaded assets to the creative fields
6GET/v2/ad_groups/{AD_GROUP_ID}/creative?shape=API&include=validationErrorsVerify validation errors are cleared before submission
7PATCH/v2/ad_groups/{AD_GROUP_ID}/creative/statusSubmit the creative for review or resubmit after rejection
8Creative review & approval

Video Carousels vs. Standard Carousels

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

FeatureStandard CarouselVideo Carousel
Asset typesImages onlyVideos + 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 creativeN/A✓ Yes — same creative entity

Common Errors

CauseResolution
Attempting to activate a campaign before the video creative is approvedWait for creative approval, then retry activation
Uploaded asset does not meet format or size requirementsVerify asset specifications and re-upload
Pre-signed upload URL has expiredRequest a new upload URL (Step 4a) and retry
Attempting to modify a creative that is under reviewWait for review to complete before making changes
Required accountInfo fields are missingInclude all required fields in the creative request body