The Kevel Developer Hub

Welcome to the Kevel developer hub. You'll find comprehensive guides and documentation to help you start working with Kevel as quickly as possible, as well as support if you get stuck. Let's jump right in!

What is AdQuery?

AdQuery is a Decision API feature that filters which ads get selected based on properties of the ads. It provides fine-grained controls on the ad request side - think of AdQuery as querying over ads in a database and returning selections that match your query.

Say a marketplace displays sponsored listings in search results. When the marketplace's users select a price range and a category in the search (like a price between 0 and 200 and a category "lawn-care"), the marketplace makes a Decision API request that queries for those prices and category. The response will only contain ads that meet those criteria. The marketplace then integrates those ads into the search as sponsored results.

How AdQuery Works

AdQuery uses creative template field values as queryable properties. These values must be strings ("lawn-care") or numbers (24, 26.72 etc.).

Only certain creative template fields can be used for AdQuery. These fields must be created with "AdQuery": true while creating/updating the creative template.

A Kevel user sets values for those fields when creating a creative template ad in the API or UI. Using the marketplace example, each seller's product would be given a creative, and queryable details from that product would be set on the creative as values.

Once an ad is live, a Decision API request makes an ad query on a placement to return any eligible ads for that query.

Setting Up AdQuery Templates and Ads

Create a creative template with AdQuery enabled fields. OR update an existing template with new AdQuery enabled fields.

To make a field enabled for AdQuery, include the parameter "AdQuery" set to true. The Variable of the field will become the key used for the AdQuery.

Here's an example creative template with two enabled fields:

{
  "Name": "AdQuery Is Cool",
  "Description": "v1",
  "IsArchived": false,
  "Fields": [
    {
    "Name": "Product Price",
    "Description": "Product Price",
    "Required": true,
    "Variable": "ctPrice",
    "AdQuery": true,
    "Type": "Number"
    },
    {
    "Name": "Product Size",
    "Description": "Product Size",
    "Required": false,
    "Variable": "ctSize",
    "AdQuery": true,
    "Type": "String"
    }
  ],
  "Contents": [
    {
    "Type": "Raw",
    "Body": "."
    }
  ]
}
curl -X POST \
     -H "X-Adzerk-ApiKey: $ADZERK_API_KEY" \
     -H "Content_Type: application/json" \
     -d '{
        "Name": "AdQuery Is Cool",
        "Description": "v1",
        "IsArchived": false,
        "Fields": [
          {
          "Name": "Product Price",
          "Description": "Product Price",
          "Required": true,
          "Variable": "ctPrice",
          "AdQuery": true,
          "Type": "Number"
          },
          {
          "Name": "Product Size",
          "Description": "Product Size",
          "Required": false,
          "Variable": "ctSize",
          "AdQuery": true,
          "Type": "String"
          }
        ],
        "Contents": [
          {
          "Type": "Raw",
          "Body": "."
          }
        ]    
     }' \
     "https://api.kevel.co/v2/creative-templates"
const Adzerk = require('@adzerk/management-sdk');
const apiKey = process.env.ADZERK_API_KEY;

async function createCreativeTemplate() {
  let specifications = await Adzerk.fetchSpecifications();
  let client = await Adzerk.buildClient({apiKey, specifications});

  let creativeTemplate = await client.run('creativeTemplate', 'create', {
    name: 'AdQuery Is Cool',
    description: 'v1',
    isArchived: false,
    fields: [{
      name: 'Product Price',
      description: 'Product Price',
      required: true,
      variable: 'ctPrice',
      adQuery: true,
      type: 'Number'
    }, {
      name: 'Product Size',
      description: 'Product Size',
      required: false,
      variable: 'ctSize',
      adQuery: true,
      type: 'String'
    }],
    contents: [{
      type: 'Raw',
      body: '.'
    }]
  });

  return creativeTemplate;
};
require "adzerk"

def create_creative_template()
  client = Adzerk::Client.new(ENV["ADZERK_API_KEY"])
  data = {
    name: 'AdQuery Is Cool',
    description: 'v1',
    is_archived: false,
    fields: [{
      name: 'Product Price',
      description: 'Product Price',
      required: true,
      variable: 'ctPrice',
      ad_query: true,
      type: 'Number'
    }, {
      name: 'Product Size',
      description: 'Product Size',
      required: false,
      variable: 'ctSize',
      ad_query: true,
      type: 'String'
    }],
    contents: [{
      type: 'Raw',
      body: '.'
    }]
  }

  client.creative_templates.create(data)
end

Once the creative template is created:

API

  1. Create creatives that supply values for the AdQuery enabled fields. This creative should include the TemplateId, and the AdQuery values should go in the TemplateValues. Refer to the creative endpoint docs for details.
{
  "AdvertiserId": 12345,
  "AdTypeId": 5,
  "Title": "Price: 100 Dollars!!!",
  "IsActive": true,
  "ScriptBody": "Come buy this cool thing for a Benjamin",
  "IsHTMLJS": true,
  "TemplateId": 12345,
  "TemplateValues": "{\"ctPrice\":100}"
}
curl -X POST \
     -H "X-Adzerk-ApiKey: $ADZERK_API_KEY" \
     -H "Content-Type: application/json" \
     -d '{
        "AdvertiserId": 12345,
        "AdTypeId": 5,
        "Title": "Price: 100 Dollars!!!",
        "IsActive": true,
        "ScriptBody": "Come buy this cool thing for a Benjamin",
        "IsHTMLJS": true,
        "TemplateId": 12345,
        "TemplateValues": "{\"ctPrice\":100}"
     }' \
     "https://api.kevel.co/v1/creative"
const Adzerk = require('@adzerk/management-sdk');
const apiKey = process.env.ADZERK_API_KEY;

async function createCreative() {
  let specifications = await Adzerk.fetchSpecifications();
  let client = await Adzerk.buildClient({apiKey, specifications});

  let creative = await client.run('creative', 'create', {
    advertiserId: 12345,
    adTypeId: 5,
    title: 'Price: 100 Dollars!!!',
    isActive: true,
    scriptBody: 'Come buy this cool thing for a Benjamin',
    isHtmljs: true,
    templateId: 12345,
    templateValues: `{"ctPrice":100}`
  });

  return creative;
}
require "adzerk"

def create_creative_template()
  client = Adzerk::Client.new(ENV["ADZERK_API_KEY"])
  data = {
    advertiser_id: 12345,
    ad_type_id: 5,
    title: "Price: 100 Dollars!!!",
    is_active: true,
    script_body: "Come buy this cool thing for a Benjamin",
    is_htmljs: true,
    template_id: 12345,
    template_values: '{"ctPrice": 100}'
  }

  client.creatives.create(data)
end
  1. Create ads for those creatives to associate them with flights.

UI

You can supply values via the UI by creating an ad on a flight:

  1. In the creative settings, choose the Format "Custom Template".
  2. Select the name of the Template you created earlier.
  3. Enter values for the Template Fields and any other creative settings.
  4. Save the ad.

Setting Up AdQuery Decision API Requests

Make your ad queries in the adQuery key on the placements object. The key for the query is the Variable name of the creative template field.

You can request one or more fields to query:

{
  "placements": [{
    "networkId": 12345
    "siteId": 12345,
    "adTypes": [5],
    "adQuery": {
      "ctPrice": {
        "min": 50,
        "max": 250,
        "nullValuesMatch": false
      },
      "ctSize": {
        "eq": "large",
        "nullValuesMatch": false
      }
    }
  }]
}
curl -H "Content-Type: application/json" \
     -d '{
        "placements": [{
          "networkId": 12345,
          "siteId": 12345,
          "adTypes": [5],
          "adQuery": {
            "ctPrice": {
              "min": 50,
              "max": 250,
              "nullValuesMatch": false
            },
            "ctSize": {
              "eq": "large",
              "nullValuesMatch": false
            }
          }
        }]
     }'\
     "https://e-12345.adzerk.net/api/v2"
const Adzerk = require('@adzerk/decision-sdk');

let client = new Adzerk.Client({networkId: 12345, siteId: 12345});

async function getDecision() {
  let request = {
    placements: [{
      adTypes: [5],
      adQuery: {
        ctPrice: {
          min: 50,
          max: 250,
          nullValuesMatch: false
        },
        ctSize: {
          eq: "large",
          nullValuesMatch: false
        }
      }
    }]
  };

  return await client.decisions.get(request);
}

getDecision();
import java.util.*;
import com.adzerk.sdk.*;
import com.adzerk.sdk.generated.ApiException;
import com.adzerk.sdk.generated.model.*;
import com.adzerk.sdk.model.DecisionResponse;

public class FetchAds {
  public static void main(String[] args) throws ApiException {
    Client client = new Client(new ClientOptions(12345).siteId(12345));

    Map<String, Object> ctPrice = new HashMap<String, Object>();
    ctPrice.put("min", 50);
    ctPrice.put("max", 250);
    ctPrice.put("nullValuesMatch", false);

    Map<String, Object> ctSize = new HashMap<String, Object>();
    ctSize.put("eq", "large");
    ctSize.put("nullValuesMatch", false);

    Map<String, Object> adQuery = new HashMap<String, Object>();
    adQuery.put("ctPrice", ctPrice);
    adQuery.put("ctSize", ctSize);

    Placement placement = new Placement()
      .adTypes(Arrays.asList(5))
      .adQuery(adQuery);

    DecisionRequest request = new DecisionRequest()
      .placements(Arrays.asList(placement));

    DecisionResponse response = client.decisions().get(request);
  }  
}
import adzerk_decision_sdk

client = adzerk_decision_sdk.Client(123456, site_id=12345)

request = {
  "placements": [{
    "adTypes": [5],
    "adQuery": {
      "ctPrice": {
        "min": 50,
        "max": 250,
        "nullValuesMatch": False
      },
      "ctSize": {
        "eq": "large",
        "nullValuesMatch": False
      }
    }
  }]
}

decision = client.decisions.get(request)
require "adzerk_decision_sdk"

client = AdzerkDecisionSdk::Client.new(network_id: 12345, site_id: 12345)

request = {
  placements: [{
    ad_types: [5],
    ad_query: {
      ct_price: {
        min: 50,
        max: 250,
        null_values_match: false
      },
      ct_size: {
        eq: "large",
        null_values_match: false
      }
    }
  }]
}

decision = client.decisions.get(request)
import AdzerkSDK

// Demo network, site, & ad type IDs; find your own via the Adzerk UI!
DecisionSDK.defaultNetworkId = 12345
DecisionSDK.defaultSiteId = 12345

let client = DecisionSDK()

var ctPrice: [String: AnyCodable] = [
  "min": .int(50),
  "max": .int(250),
  "nullValuesMatch": .bool(false)
]

var ctSize: [String: AnyCodable] = [
  "eq": .string("large"),
  "nullValuesMatch": .bool(false)
]

var adQuery: [String: AnyCodable] = [
  "ctPrice": ctPrice,
  "ctSize": ctSize
]

var p = Placements.custom(divName: "div0", adTypes: [5])

var reqOpts = PlacementRequest<StandardPlacement>.Options()
reqOpts.userKey = "abc"
reqOpts.additionalOptions = [
  "adQuery": adQuery
]

client.request(placements: [p], options: reqOpts) {response in
  dump(response)
}
AdzerkSdk sdk = new AdzerkSdk.Builder().networkId(12345L).build();

val ctPrice = HashMap<String, Any>()
ctPrice.put("min", 50)
ctPrice.put("max", 250)
ctPrice.put("nullValuesMatch", false)

val ctSize = HashMap<String, Any>()
ctPrice.put("eq", "large")
ctPrice.put("nullValuesMatch", false)

val adQuery = HashMap<String, Any>()
adQuery.put("ctPrice", ctPrice)
adQuery.put("ctSize", ctSize)

val reqeust = new Request.Builder()
    .addPlacement(Placement("div0", 12345, (5)))
    .addAdditionalOption("adQuery", adQuery)
    .build()

sdk.requestPlacement(request, object : AdzerkSdk.DecisionListener {
  override fun success(response: DecisionResponse?) {

  }
  override fun error(error: AdzerkSdk.AdzerkError?) {
    
  }
})

👍

You can also use AdQuery with multi-winner placements to return multiple ads per placement.

Operators

Key

Type(s)

Usage

Example Value

Default

min

number

The minimum of a range.

0

max

number

The maximum of a range.

2000

eq

string, number

An exact match. Wildcard characters aren't supported.

"Honda"

in

array of strings or numbers

Match on any of the values in the array.

["Honda", "Toyota", "Subaru"]

not

object

Do not match on the query provided. Is used with another operator - currently in is supported.

{
  "in": [
    "Chevrolet"
  ]
}

nullValuesMatch

boolean

Whether to include ads where the queried field has no value

true

false

All operators are optional. For instance, a query with a min value but no max would have have an infinite upper limit for that field.

🚧

If an ad query isn't present on a Decision API request, and ad query eligible ads are candidates for that decision, any of the ad query eligible ads will be returned.

Updated 3 months ago

AdQuery


Suggested Edits are limited on API Reference Pages

You can only suggest edits to Markdown body content, but not to the API spec.