Creating Product Ads via API

With a product catalog synced to Kevel, it is possible to create product-based ads (PLAs and other formats) via API or UI. This page describes the process using Kevel's API. There are two ways to create product ads via API:

  1. A fixed list of SKUs
  2. A query specifying product characteristics

Product ads can be created at the same time as the Campaign and Flight(s) they belong to using the Create Campaign v2 endpoint (recommended) or separately associated with existing Flights using Kevel's Jobs API, an asynchronous service that handles longer-running batch operations in the system. In both cases, Kevel facilitates the creation of many product ads in a single request and returns a Job ID. The Job ID is used to poll for the status of the Job and when complete a list of Ad IDs is returned. See the Submit Job API documentation for more details.

Aside from the difference in how the products are specified, there are other key differences between the options:

  1. Option #1 supports providing overrides alongside the list of SKUs allowing you to set product bids, for example, and other Ad-level settings on a per-product basis. This is not supported with Option #2.
  2. Option #1 allows you to manually inactivate and activate products via the UI/API. This is not allowed for Option #2, where the Ads are fully managed by the Kevel system.

Create a Campaign with product ads

Below is a complete example request to create a Campaign with one Flight filled with product ads for the brand cashewco. See additional sections that follow for more examples and definitions of all fields included in the Jobs object for use within Flights or in standalone calls to the Jobs API.

curl --request POST \
     --url https://api.kevel.co/v2/campaign \
     --header 'X-Kevel-ApiKey: XXX' \
     --header 'accept: application/json' \
     --header 'content-type: application/json' \
     --data '
{
  "AdvertiserId": 11111,
  "Name": "Product Query Example Campaign",
  "IsActive": true,
  "Flights": [
    {
      "Name": "Product Ad Flight 1",
      "StartDateISO": "2025-02-06T00:00:00.000Z",
      "PriorityId": 22222,
      "GoalType": 8,
      "Impressions": 1002,
      "IsActive": true,
      "RateType": 3,
      "EndDateISO": "2025-02-28T00:00:00.000Z",
      "Price": 2,
      "Keywords": "",
      "TimeZone": "UTC",
      "Jobs": [
        {
          "TaskId": "create-ads-from-product-query",
          "TaskArgs": {
            "AdTemplateUri": "itemdb://12345/101/0e9321b3-1446-47ec-b1d7-705bfb7b3fb5",
            "ProductQuery": [["brandId","cashewco"]]
          }
        }
      ]
    }
  ]
}
'

Product ad creation details

A query

Use the create-ads-from-product-query taskId and a ProductQuery. Here's an example:

curl --request POST \
     --url https://api.kevel.co/v1/job/ \
     --header 'X-Kevel-ApiKey: XXX' \
     --header 'accept: application/json' \
     --header 'content-type: application/json' \
     --data '
{
  "TaskId": "create-ads-from-product-query",
  "TaskArgs": {
    "FlightId": 456789,
    "AdTemplateUri": "itemdb://12345/101/0e9321b3-1446-47ec-b1d7-705bfb7b3fb5",
    "ProductQuery": [
      [ ["one-of", "kevel/brand-id"], [12345, 12346]],
      [ "kevel/merchant-id", 12347 ]
    ]
  }
}
'

Ad Template URI

In most cases the Ad Template URI will be constant for all create ads from products requests unless a customer is using multiple ad templates (e.g. for different PLA formats or placements).

Example URI: itemdb://12345/101/0e9321b3-1446-47ec-b1d7-705bfb7b3fb5
Structure: itemdb://{network_id}/{ad_templates_table_id}/{template_uuid}

  • network_id — ID of the network that this job is submitted to; must match the API key authentication used on the request
  • ad_templates_table_id — table ID of the ad templates table that the template is saved in [shared by Kevel during Catalog setup]
  • template_uuid — the ID of the ad template (typically a random GUID) [shared by Kevel during Catalog setup]

Product Query

The ProductQuery array contains a list of 2-item arrays (called "clauses"), each describing a match criterion. The first item of each clause is an array of the op and the field. The second item of each clause is the value that should be matched. As a shorthand, the first item can be a string, in which case it represents the field and the op is assumed to be = (equals). See below for a list of supported op values. Clauses are combined with AND logic. In the example above, the Flight will be filled with products that have a Brand ID of 12345 OR 12346 AND have a Merchant ID of 12347.

The fields included must be defined as search keys on the selected product table. Note also that the product table queried will be derived from the Ad Template definition.

Supported op values are =, <, >, <=, >=, not=, one-of, present?, matches and matches-phrase. The last two are only valid for search keys of type text.

Changing Product Queries

The create-ads-from-product-query task can be called multiple times with the same Flight ID, and each call results in an update of the Ads in the Flight. Existing product ads in the Flight that match the new query will remain, products that newly match the query will be added, and product ads that no longer match will be deleted.

👍

Set it and forget it

Kevel will automatically re-evaluate the product query as updated product catalog data is received for the life of the Flight without any further action required. Existing product ads will be updated with the latest product data, products that newly match the query will be added, and product ads that no longer match will be deleted.

A fixed list of SKUs

Use the create-ads-from-products taskId, a list of ItemDB product URIs, and optionally a set of overrides. Here's an example:

curl --request POST \
     --url https://api.kevel.co/v1/job/ \
     --header 'X-Kevel-ApiKey: XXX' \
     --header 'accept: application/json' \
     --header 'content-type: application/json' \
     --data '
{
  "TaskId": "create-ads-from-products",
  "TaskArgs": {
    "FlightId": 456789,
    "AdTemplateUri": "itemdb://12345/101/0e9321b3-1446-47ec-b1d7-705bfb7b3fb5",
    "ProductUris": [
      "itemdb://12345/100/01936422964",
      "itemdb://12345/100/01936422955"
    ],
    "Overrides": {
      "itemdb://12345/100/01936422964": [
        {
          "target": [
            "ad",
            "price"
          ],
          "source": "5",
          "op": "constant"
        }
      ],
      "itemdb://12345/100/01936422955": [
        {
          "target": [
            "ad",
            "price"
          ],
          "source": "3.5",
          "op": "constant"
        }
      ]
    },
  }  
}
'

Most parameters are static for an individual network and it is recommended to save these values as variables in integration scripts for reuse across requests that otherwise have the same structure. The primary variables that will change are the Flight ID and Product URIs.

ItemDB URIs

Example URI: itemdb://12345/100/01936422964
Structure is itemdb://{network_id}/{catalog_id}/{item_id}

  • network_id — ID of the network that this job is submitted to; must match the API key authentication used on the request [static]
  • catalog_id — table ID of the products table that the item is saved in [static; shared by Kevel during Catalog setup]
  • item_id — customer-defined ID of the product (typically its SKU) [varies per request]

Overrides

The Overrides object is a mapping of ItemDB URIs to arrays of objects. Each ItemDB URI specified must be present in ProductUris. Each override has the following fields:

  • source — either the source field from the product or a scalar value (for constant operations)
  • target — array of strings representing the path into the ad or creative where the source value should be saved. The first item is one of ad or creative and subsequent items vary based on the entity. Example:
    // Save the `product_id` field on the product to the `ctProductId` Creative Template field of the Creative
    {
      "source": "product_id",
      "target": ["creative", "TemplateValues", "ctProductId"],
      "op": "stringify"
    }
    

  • op — the operation or transformation used when mapping the source data to the target. mapped to the target. Options:
    • constant — not sourced from the product data but rather a fixed value that will be set to the target
    • literal — copy the source data to the target verbatim without changing the source data type
    • stringify — copy the source data transformed to a string when saving to the target
    • stringify-array — for sources with data type array, stringify each array entry and save the string version of each array entry to the target