Targeted Onsite Ad (TOA) — Partner Integration Guide
Overview
This guide walks you through the end-to-end workflow for creating and publishing Targeted Onsite Ad (TOA) campaigns using the Kroger Ad Platform (KAP) API v2. TOA is a display-style onsite ad experience — distinct from Product Listing Ads (PLAs) and Promoted Product Carousels — built from modular sub-domain endpoints: products, sub-commodity bids, a click-through destination, and a creative unit that must be reviewed and approved before the ad group can be published.
Note: This guide covers the TOA-specific workflow. For general campaign setup, refer to the Create a Campaign guide.
Before You Begin
| 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 activations. |
| Creative contact | Every TOA campaign resolves an internal creative contact automatically — TOA creative requires review before it can go live. |
| Product/UPC list | The UPCs you intend to promote and/or proxy, ready to submit once the ad group exists. |
What Makes TOA Different
| Aspect | PLA / Carousel | TOA |
|---|---|---|
| Product targeting | entities array on the ad group | Dedicated promoted products and proxy products endpoints |
| Bidding | Per-product / entity | Per sub-commodity (base bid + optional overrides) |
| Bid updates via general bid endpoint | Supported | Not supported — use the dedicated sub-commodity bids endpoint |
| Click-through destination | Not applicable | Required — curated_product_list (with optional generated URL) or manual_entry |
| Placements | Search & Browse, Basket Builder, Savings | Search & Browse, Savings, Shop & Discover (min bid $22) |
| Creative review required | Video carousels only | Always required |
Campaign objective field | Not applicable | AWARENESS, CONSIDERATION, or CONVERSION |
Workflow Overview
The TOA workflow consists of five phases:
- Campaign setup — Create a
TOAcampaign with anobjective. - Ad group setup — Create the ad group with placements/targets and a base bid.
- Sub-domain configuration — Set promoted products, proxy products, sub-commodity bids, and the click-through destination.
- Creative workflow — Retrieve the creative design, assign assets, and submit for review.
- Submission and publication — Submit the ad group and publish once creative is approved.
Step-by-Step Instructions
Phase 1: Campaign Setup
Step 1 — Create a TOA Campaign
POST /v2/campaigns
Set campaignType to TOA. TOA is the only campaign type that accepts objective. A creative contact is resolved automatically for TOA campaigns — it is not a field on the create request.
Request
{
"name": "Summer TOA Campaign",
"campaignType": "TOA",
"objective": "CONSIDERATION",
"status": "DRAFT",
"startDate": "2026-07-01",
"endDate": "2026-07-31",
"budgetAmount": 50000,
"budgetType": "MONTHLY",
"pacingType": "EVEN",
"accountId": 100,
"advertiserIds": [12],
"billingContactId": 102,
"billingAddressId": 5001
}
Response — 200 OK
{
"data": {
"id": 8101,
"name": "Summer TOA Campaign",
"campaignType": "TOA",
"objective": "CONSIDERATION",
"status": "DRAFT",
"creativeContactId": 103,
...
}
}
Save
data.idasCAMPAIGN_ID.
Objective values
| Value | Meaning |
|---|---|
AWARENESS | Optimize for reach/visibility |
CONSIDERATION | Optimize for engagement |
CONVERSION | Optimize for purchase — default when objective is omitted |
objectiveis rejected with400if it's set on any non-TOA campaign type.
Phase 2: Ad Group Setup
Step 2 — Create a TOA Ad Group
POST /v2/ad_groups
Include at least one placement target that meets the placement's minimum. TOA creative is configured separately in Phase 4, so omit carousel-only creative fields.
TOA placements
| Placement | Minimum bid | Id |
|---|---|---|
| Savings | $22.00 | 4 |
| Search & Browse | $22.00 | 5 |
| Shop & Discover | $22.00 | 6 |
Request
{
"campaignId": 8101,
"name": "Summer TOA Ad Group",
"startDate": "2026-07-01",
"endDate": "2026-07-31",
"budgetAmount": 15000,
"budgetType": "MONTHLY",
"status": "DRAFT",
"baseBid": 22.5,
"entities": [],
"targets": [
{ "type": 1, "id": 4 },
{ "type": 1, "id": 5 }
]
}
Response — 200 OK
{
"data": {
"adGroupId": 9101,
"campaignId": 8101,
"name": "Summer TOA Ad Group",
"status": "DRAFT",
...
}
}
Save
data.adGroupIdasAD_GROUP_ID.
Use GET /v2/ad_groups/{AD_GROUP_ID}/available_products at any point to see which products are eligible for targeting under the ad group's divisions/placements.
Phase 3: Sub-Domain Configuration
TOA products, bids, and the click-through destination are managed through dedicated endpoints rather than the ad group's entities array. After the ad group exists, you can complete most sub-steps in the order that fits your workflow, but set promoted products before generating a click-through URL.
Step 3a — Set Promoted Products
POST /v2/ad_groups/{AD_GROUP_ID}/products/promoted
Request
{
"data": [
{ "id": "0004300000287" },
{ "id": "0004300000294" }
]
}
Response — 200 OK
{
"data": [
{ "id": "0004300000287" },
{ "id": "0004300000294" }
]
}
To incrementally add or remove promoted products instead of replacing the full list, PATCH the same path with a deleted flag per item:
{
"data": [
{ "id": "0004300000301", "deleted": false },
{ "id": "0004300000294", "deleted": true }
]
}
Step 3b — Set Proxy Products (Optional)
Proxy products stand in for promoted products that are not yet available (e.g. a pre-launch item). onShelfDate is required and applies to the full proxy list.
POST /v2/ad_groups/{AD_GROUP_ID}/products/proxy
Request
{
"onShelfDate": "2026-07-15",
"products": [
{ "id": "0004300000350" }
]
}
Response — 200 OK
{
"data": {
"onShelfDate": "2026-07-15",
"products": [
{ "id": "0004300000350" }
]
}
}
The PATCH variant accepts the same shape with an optional onShelfDate and per-item deleted flags for incremental updates.
Step 3c — Set Sub-Commodity Bids
TOA bids at the sub-commodity level rather than at the individual product level. Use POST /v2/metadata/sub_commodities with your promoted UPCs to resolve their sub-commodity IDs first.
POST /v2/metadata/sub_commodities
{ "upcs": ["0004300000287", "0004300000294"] }
[
{ "subCommodity": { "id": "0200200007", "name": "Sparkling Water" } },
{ "subCommodity": { "id": "0200200015", "name": "Still Water" } }
]
Then set bids. baseBid is the fallback used whenever an item omits bidAmount. Bid updates via the ad group entities endpoint are not supported for TOA — use the TOA bids endpoint instead.
Note: Multiple UPCs can resolve to the same sub-commodity, so do not assume a 1:1 correspondence between the UPCs you submit and the sub-commodity items returned.
POST /v2/ad_groups/{AD_GROUP_ID}/bids/sub_commodity
Request
{
"baseBid": 22.5,
"data": [
{ "id": "0200200007" },
{ "id": "0200200015", "bidAmount": 25.0 }
]
}
Response — 200 OK
{
"data": [
{ "id": "0200200007", "bidAmount": null },
{ "id": "0200200015", "bidAmount": 25.0 }
],
"errors": []
}
Use PATCH on the same path to merge additional sub-commodity bids into the existing list.
Step 3d — Set the Click-Through Destination
POST /v2/ad_groups/{AD_GROUP_ID}/click_through
Supported type values are curated_product_list and manual_entry. url is required for manual_entry.
Request — manual entry
{
"type": "manual_entry",
"url": "https://www.kroger.com/promo/summer-toa"
}
Request — curated product list
{
"type": "curated_product_list",
"config": { "keyword": "summer-refresh" }
}
Response — 200 OK
{
"data": {
"type": "curated_product_list",
"url": null,
"config": { "keyword": "summer-refresh" }
}
}
If you used curated_product_list, first set the promoted products with POST /v2/ad_groups/{AD_GROUP_ID}/products/promoted, then generate the resulting URL:
POST /v2/ad_groups/{AD_GROUP_ID}/click_through/generate
Use GET/PATCH on /v2/ad_groups/{AD_GROUP_ID}/click_through to retrieve or update the destination later.
Phase 4: Creative Workflow
TOA reuses the same creative design/asset model as video carousels — a design with text and image fields — but without a video field.
Step 4a — Create creative for the ad group
POST /v2/ad_groups/{ad_group_id}/creative
Request
{
"shape": "API",
"include": ["validationErrors", "assetReferences"],
"designGroupName": "TOA Standard"
}
Response — 201 OK
{
"data": {
"id": "creative-group-toa-001",
"status": "DRAFT",
"designs": [
{
"id": "design-toa-100",
"name": "TOA Standard",
"fields": [
{ "id": "field-headline-001", "displayName": "Headline", "fieldDataType": "TEXT" },
{ "id": "field-subtext-002", "displayName": "Subtext", "fieldDataType": "TEXT" },
{ "id": "field-image-003", "displayName": "Image", "fieldDataType": "ZONE" }
]
}
]
}
}
Step 4b — Retrieve the Creative Design ID and Field IDs
GET /v2/ad_groups/{AD_GROUP_ID}/creative?include=validationErrors
Response — 200 OK
{
"data": {
"id": "creative-group-toa-001",
"status": "DRAFT",
"designs": [
{
"id": "design-toa-100",
"name": "TOA Standard",
"fields": [
{ "id": "field-headline-001", "displayName": "Headline", "fieldDataType": "TEXT" },
{ "id": "field-subtext-002", "displayName": "Subtext", "fieldDataType": "TEXT" },
{ "id": "field-image-003", "displayName": "Image", "fieldDataType": "ZONE" }
]
}
]
}
}
Save
data.designs[0].idasDESIGN_IDand eachfields[].idmapped to itsdisplayName(e.g.HEADLINE_FIELD_ID,SUBTEXT_FIELD_ID,IMAGE_FIELD_ID).
Step 5 — Upload the Image Asset and Assign Creative Fields
Upload the image asset using the same three-request sequence as other creative types (POST /v2/creative_asset/upload_url → PUT {uploadUrl} → POST /v2/creative_asset), then assign it — along with the text fields — to the design.
PATCH /v2/ad_groups/{AD_GROUP_ID}/creative
Request
{
"persistChanges": true,
"designs": [
{
"id": "design-toa-100",
"fields": [
{ "id": "field-headline-001", "textValue": "Fresh picks for summer" },
{ "id": "field-subtext-002", "textValue": "Shop now at Kroger" },
{ "id": "field-image-003", "assetId": "asset-img-40021" }
]
}
]
}
Set persistChanges to true to save the creative field updates. If persistChanges is omitted or set to false, the request runs validation only and does not persist the submitted creative changes.
Verify before submitting:
GET /v2/ad_groups/{AD_GROUP_ID}/creative?include=validationErrors
Resolve any included.validationErrors entries before proceeding.
Step 6 — Submit the Creative for Review
PATCH /v2/ad_groups/{AD_GROUP_ID}/creative/status
Request — first submission
{
"status": "UNDER_REVIEW",
"comment": "TOA creative ready for review."
}
Request — resubmission after rejection
{
"status": "RE_SUBMITTED",
"comment": "Updated headline and image per reviewer feedback."
}
When REJECTED, update the flagged fields/assets and resubmit with RE_SUBMITTED.
Phase 5: Submission and Publication
Once creative is approved, move the ad group through its lifecycle. All lifecycle actions are idempotent PATCH calls that return the refreshed ad group.
PATCH /v2/ad_groups/{AD_GROUP_ID}/submit
PATCH /v2/ad_groups/{AD_GROUP_ID}/publish
Response — 200 OK (shape shared by all lifecycle actions)
{
"data": {
"adGroupId": 9101,
"campaignId": 8101,
"status": "SCHEDULED",
...
}
}
statusreflects the ad group's real, current state (e.g.DRAFT,SCHEDULED,ACTIVE,PAUSED,UNDER_REVIEW,ENDED,FAILED) — it is derived from the underlying activation, not a fixed value per action.
Additional lifecycle actions are available at the same base path: pause, unpause, archive, discard, and end_now.
Endpoints Quick Reference
| Step | Method | Endpoint | Description |
|---|---|---|---|
| 1 | POST | /v2/campaigns | Create a TOA campaign with an objective |
| 2 | POST | /v2/ad_groups | Create the TOA ad group |
| — | GET | /v2/ad_groups/{id}/available_products | List products eligible for targeting |
| 3a | POST / PATCH | /v2/ad_groups/{id}/products/promoted | Set or merge promoted UPCs |
| 3b | POST / PATCH | /v2/ad_groups/{id}/products/proxy | Set or merge proxy UPCs + onShelfDate |
| 3c | POST | /v2/metadata/sub_commodities | Resolve sub-commodity IDs from UPCs |
| 3c | POST / PATCH | /v2/ad_groups/{id}/bids/sub_commodity | Set or merge sub-commodity bids |
| 3d | POST / GET / PATCH | /v2/ad_groups/{id}/click_through | Create, retrieve, or update the click-through destination |
| 3d | POST | /v2/ad_groups/{id}/click_through/generate | Generate a curated product list URL |
| 4 | GET | /v2/ad_groups/{id}/creative?include=validationErrors | Retrieve creative design ID and field IDs |
| 5 | PATCH | /v2/ad_groups/{id}/creative | Assign headline/subtext/image to the creative |
| 6 | PATCH | /v2/ad_groups/{id}/creative/status | Submit the creative for review or resubmit after rejection |
| 7 | PATCH | /v2/ad_groups/{id}/submit | Submit the ad group |
| 8 | PATCH | /v2/ad_groups/{id}/publish | Publish the ad group |
| — | PATCH | /v2/ad_groups/{id}/pause | /unpause | /archive | /discard | /end_now | Additional lifecycle actions |
Get TOA campaign and ad group info
| Method | Endpoint | Description |
|---|---|---|
GET | /campaigns/{campaign_id} | Get campaign |
GET | /campaigns/{campaign_id}/remaining_budget | Get campaign remaining budget |
GET | /ad_groups/{ad_group_id} | Get ad group base information |
GET | /ad_groups/{ad_group_id}/bids/sub_commodity | Get ad group sub commodity bids |
GET | /ad_groups/{ad_group_id}/click_through | Get ad group click through destination |
GET | /ad_groups/{ad_group_id}/available_products | Get ad group available products |
GET | /ad_groups/{ad_group_id}/products/promoted | Get ad group promoted products |
GET | /ad_groups/{ad_group_id}/products/proxy | Get ad group proxy products |
GET | /ad_groups/{ad_group_id}/creative | Get ad group creative design |
Common Errors
| Cause | Resolution |
|---|---|
objective sent on a non-TOA campaign | Remove objective, or change campaignType to TOA |
baseBid below the placement's $22 minimum | Increase baseBid or the relevant sub-commodity bidAmount |
Attempting to update TOA bids through /v2/ad_groups/{id}/entities | Use /v2/ad_groups/{AD_GROUP_ID}/bids/sub_commodity for TOA bids instead |
Proxy products submitted without onShelfDate | Include a valid onShelfDate (YYYY-MM-DD) with every proxy product POST request |
manual_entry click-through submitted without url | Include url when type is manual_entry |
| Publishing before creative is approved | Wait for creative approval, then retry submit/publish |
| Modifying a creative that is under review | Wait for review to complete before making changes |