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:
| 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
The video carousel creative workflow consists of four phases:
- Campaign setup — Create a campaign and a Carousel-Type ad group.
- Asset management — Upload your video and image assets.
- Creative workflow — Create, verify, update, and submit your creative for review.
- 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
Step 1 — Create a CAROUSEL Campaign
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
}
Response — 201 Created
{
"data": {
"id": 8001,
"name": "Summer Video Carousel",
"campaignType": "CAROUSEL",
"status": "DRAFT",
.....
}
}
Save
data.idasCAMPAIGN_ID.
Step 2 — Create a Video Carousel Ad Group
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
}
]
}
Response — 201 Created
{
"data": {
"adGroupId": 9001,
"campaignId": 8001,
"name": "Summer Video Carousel Ad Group",
"creativeType": "Video",
"status": "DRAFT",
.....
}
}
Save
data.adGroupIdasAD_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
| Parameter | Value | Purpose |
|---|---|---|
shape | API | Returns the machine-readable API shape |
include | validationErrors | Returns any current validation errors |
Response — 200 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 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
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)
POST /v2/creative_asset/upload_url
Request
{
"fileName": "summer-hero.mp4",
"contentType": "video/mp4"
}
Response — 201 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 beforeexpiresAt.
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.
Response — 201 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:
| 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
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
{
"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).
Response — 200 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."
}
Response — 200 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
| 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
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
| 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 |