Using Salesforce Marketing Cloud

(Campaign Level API Calls)

This guide explains how to use Koddi-provided ads in Salesforce Marketing Cloud Engagement email campaigns by calling the Winning Ads API once per campaign and rendering the same ad for all recipients. This approach is designed to be simple, reliable, and fully contained within Salesforce Marketing Cloud.

How it works

  • Marketer prepares an audience Data Extension.
  • A pre-send process calls Koddi Winning Ads once.
  • The selected ad is stored in a campaign-level Data Extension.
  • The email template looks up and renders the stored ad.
  • All recipients receive the same sponsored placement.

Use this implementation when

  • A single sponsored placement is acceptable for all recipients.
  • A fully SFMC-contained solution is required.
📘

This implementation is intentionally simple and fully contained within Salesforce Marketing Cloud. It is not designed for all use cases. Because of the structure of SFMC, more complex use cases require additional tooling such as the APEX solution described here. Your Koddi team can help you make the decision on when to implement what solutio

API endpoints used

Primary auction call:

POST https://{clientname}.koddi.io/auction-engine/winning_ads

Measurement endpoints for later phases:

GET  https://{clientname}.koddi.io/event-collection/beacon?action=click

Authentication

Store Koddi API credentials in a restricted Data Extension and reference them in the Script Activity.

Create: Koddi_Email_Config

Fields:

  • ConfigKey, Text, Primary Key
  • ConfigValue, Text

Insert:

  • ConfigKey: KODDI_API_TOKEN
  • ConfigValue: Your API Token

Example Winning Ads request body

{
  "client_name": "Sample Store",
  "domain": "www.store.com",
  "site_id": "Sample Store",
  "page_name": "Email",
  "experience_name": "Email 600px",
  "max_requested": 1,
  "slots_available": 1,
  "targeting": {
     "new_cust": 0,
     "audience_id": 19478230234
  }
}

Example response handling

Your code should expect one or more ads. For email, use the first eligible ad returned for the experience.

{
  "errors": [],
  "sponsored_listings": [
    {
      "click_tracking_url": "https://koddi.io/click/abc123",
      "bidder": "100000006",
      "advertiser_name": "Campbell's Soup",
      "impression_tracking_url": "https://koddi.io/impression/xyz456",
      "tracking_data": "encoded_string",
      "cpm": 29,
      "bid": 31,
      "tracking_guid": "GUID",
      "price_floor": 0.50,
      "price_floor_type": 1,
      "assets": {
        "creative_url": "https://cdn.koddi.com/creative.jpg",
        "creative_destination": "https://brand.example.com/landing-page",
        "creative_name": "Creative Name"
      }
    }
  ]
}

Build the workflow in Salesforce

Step 1: Create fields on Campaign

  1. Create a campaign-level Data Extension to store the selected Koddi ad using the data model below. Store ad payload data on a Koddi_Email_Campaigns object:
  • CampaignId, Text, Primary Key
  • Koddi_Experience_Name, Text
  • Koddi_Status, Text
  • Koddi_Ad_Creative_URL, Text
  • Koddi_Ad_Click_URL, Text
  • Koddi_Ad_Destination_URL, Text
  • Koddi_Ad_Impression_URL, Text
  • Koddi_Error, Text
  • Koddi_Last_Updated, Date
  1. Create or update the sendable audience data audience object used for the email:
  • SubscriberKey, Text, Primary Key (if new object)
  • EmailAddress, Email Address
  • CampaignId, Text

The CampaignId value in the audience Data Extension must match the CampaignId value in Koddi_Email_Campaigns. The email uses this value to look up the selected ad at send time.

Step 2: Automate with Automation Studio

Create an Automation Studio Script Activity that runs before the email send. The script calls the Koddi Winning Ads API once, stores the selected ad in Koddi_Email_Campaigns, and sets the row status to Ready, No Fill, or Failed.

Salesforce Marketing Cloud Script Activities run server-side JavaScript inside Automation Studio and time out after 30 minutes. Use this campaign-level approach to avoid per-recipient API calls and keep the automation simple.

🚧

This sample code is provided by Koddi for illustrative purposes only to assist with integration of Koddi services with Salesforce Marketing Cloud.

The code is provided "as is" without warranty of any kind, express or implied. Koddi does not guarantee that this code will be compatible with all systems or configurations.

<script runat="server">
Platform.Load("Core", "1.1.1");

var campaignId = "spring_sale_2026";
var endpoint = "https://CLIENTNAME.koddi.io/auction-engine/winning_ads";

// Retrieve Koddi API token from config Data Extension
var configDE = DataExtension.Init("Koddi_Email_Config");
var tokenRows = configDE.Rows.Lookup(["ConfigKey"], ["KODDI_API_TOKEN"]);

if (!tokenRows || tokenRows.length === 0) {
  throw "Missing KODDI_API_TOKEN in Koddi_Email_Config";
}

var koddiToken = tokenRows[0].ConfigValue;

var payload = {
  client_name: "Sample Store",
  domain: "www.store.com",
  site_id: "Sample Store",
  page_name: "Email",
  experience_name: "Email 600px",
  max_requested: 1,
  slots_available: 1,
  targeting: {
    campaign_id: campaignId
  }
};

var status = "Failed";
var creativeUrl = "";
var clickUrl = "";
var destinationUrl = "";
var impressionUrl = "";
var errorMessage = "";

try {
  var response = HTTP.Post(
    endpoint,
    "application/json",
    Stringify(payload),
    ["Authorization"],
    ["Bearer " + koddiToken]
  );

  if (response.StatusCode == 200) {
    var body = Platform.Function.ParseJSON(response.Response[0]);

    if (body.sponsored_listings && body.sponsored_listings.length > 0) {
      var ad = body.sponsored_listings[0];

      creativeUrl = ad.assets && ad.assets.creative_url ? ad.assets.creative_url : "";
      destinationUrl = ad.assets && ad.assets.creative_destination ? ad.assets.creative_destination : "";
      clickUrl = ad.click_tracking_url || "";
      impressionUrl = ad.impression_tracking_url || "";
      status = "Ready";
    } else {
      status = "No Fill";
    }
  } else {
    status = "Failed";
    errorMessage = "Koddi API returned status " + response.StatusCode;
  }
} catch (e) {
  status = "Failed";
  errorMessage = String(e);
}

Platform.Function.UpsertData(
  "Koddi_Email_Campaigns",
  ["CampaignId"],
  [campaignId],
  [
    "Koddi_Experience_Name",
    "Koddi_Ad_Creative_URL",
    "Koddi_Ad_Click_URL",
    "Koddi_Ad_Destination_URL",
    "Koddi_Ad_Impression_URL",
    "Koddi_Status",
    "Koddi_Error",
    "Koddi_Last_Updated"
  ],
  [
    payload.experience_name,
    creativeUrl,
    clickUrl,
    destinationUrl,
    impressionUrl,
    status,
    errorMessage,
    Platform.Function.Now()
  ]
);
</script>

UpsertData() updates an existing Data Extension row when a matching row exists and inserts a new row when it does not.

Run this Script Activity before the email send. Do not call Winning Ads from the email template.

Step 3: Render the ad in the email

Use AMPscript in the email to look up the campaign-level ad from Koddi_Email_Campaigns.

%%[
SET @campaignId = AttributeValue("CampaignId")

SET @creativeUrl = Lookup(
  "Koddi_Email_Campaigns",
  "Koddi_Ad_Creative_URL",
  "CampaignId", @campaignId
)

SET @clickUrl = Lookup(
  "Koddi_Email_Campaigns",
  "Koddi_Ad_Click_URL",
  "CampaignId", @campaignId
)

SET @impressionUrl = Lookup(
  "Koddi_Email_Campaigns",
  "Koddi_Ad_Impression_URL",
  "CampaignId", @campaignId
)

SET @status = Lookup(
  "Koddi_Email_Campaigns",
  "Koddi_Status",
  "CampaignId", @campaignId
)
]%%

%%[ IF @status == "Ready" AND NOT EMPTY(@creativeUrl) AND NOT EMPTY(@clickUrl) THEN ]%%

<a href="%%=RedirectTo(@clickUrl)=%%">
  <img
    src="%%=v(@creativeUrl)=%%"
    width="600"
    alt=""
    border="0"
    style="display:block;width:100%;max-width:600px;height:auto;"
  />
</a>

%%[ IF NOT EMPTY(@impressionUrl) THEN ]%%
<img
  src="%%=v(@impressionUrl)=%%"
  width="1"
  height="1"
  alt=""
  style="display:none;"
/>
%%[ ENDIF ]%%

%%[ ELSE ]%%

<!-- Optional fallback content -->

%%[ ENDIF ]%%

The email should only read from the prepared Data Extension. AMPscript Data Extension functions such as Lookup() are intended for retrieving values from Data Extensions during message rendering.