Developer GuideDemand SourcesDelegate Strategy Guide

Delegate Strategy Guide

Delegate is Praevis’s co-located bidding engine. Instead of receiving bid requests at your endpoint, your bidding logic runs inside Praevis infrastructure — evaluated in <1ms, with no network round-trip, no timeout risk, and no bidder to maintain.

Campaign API v2.0 Available: For easier campaign management, use the Campaign API instead of manually editing strategy JSON. The Campaign API provides full CRUD operations (Create, Update, Delete, Activate) with creative upload support.

Traditional RTBDelegate
Latency50–150ms round-trip<1ms (in-process)
Network dependencyYour datacenterNone
Timeout riskYesNone
Strategy formatYour codeJSON rules
Budget pacingYour systemIntegrated with Guide
Update timeRedeploy30 seconds

Strategy JSON structure

{
  "version": "1.0",
  "dsp_id": "your-dsp-uuid",
  "campaigns": [ ... ],
  "rules": [ ... ],
  "default_bid": 1.00
}
FieldRequiredDescription
version✓Strategy format version — always "1.0"
dsp_id✓Your demand source (DSP) UUID
campaigns✓Array of campaign objects (budget and scheduling)
rules✓Array of bidding rules (conditions and bid config)
default_bid✓Fallback bid CPM if no rule matches, in USD

Campaign object

{
  "id": "campaign-001",
  "name": "CTV MENA",
  "active": true,
  "priority": 1,
  "daily_budget": 500.00,
  "start_date": "2026-02-17",
  "end_date": "2026-03-31"
}
FieldRequiredDescription
id✓Unique campaign identifier
name✓Display name
active✓true / false — toggle without deleting
priority✓Lower number = higher priority (1 wins over 2)
daily_budget—Daily spend cap in cents. Even pacing reduces bid rate as budget is consumed
total_budget—Total lifetime spend cap in cents
start_date—ISO date — campaign starts bidding on this date
end_date—ISO date — campaign stops bidding after this date
frequency_cap—Object: { "max_impressions": 3, "period_hours": 24 } — limits impressions per device

Budget Pacing

Budget enforcement runs on every bid evaluation. When daily_budget is set:

Spend vs BudgetBid Probability
Under 70%100% (bid normally)
70-80%70%
80-90%40%
90-95%15%
95%+0% (stops bidding)

This ensures even delivery throughout the day instead of burning budget in the first hours.

Frequency Capping

Limits how many times the same device sees a campaign’s ad within a time window. Uses device IFA (or UA+IP fingerprint) as the identifier.

{
  "id": "campaign-001",
  "frequency_cap": {
    "max_impressions": 3,
    "period_hours": 24
  }
}

When a device reaches max_impressions for this campaign, the campaign stops bidding for that device until the counter expires.


Rule object

{
  "name": "CTV UAE Prime Time",
  "campaign_id": "campaign-001",
  "conditions": {
    "device.devicetype": "3",
    "geo.country": ["AE", "SA"],
    "hour": ["18", "19", "20", "21", "22", "23"]
  },
  "bid": {
    "base_cpm": 5.00,
    "multipliers": {
      "prime_time": 1.4
    },
    "max_cpm": 10.00,
    "min_cpm": 3.00
  },
  "priority": 1
}
FieldRequiredDescription
name✓Rule display name
campaign_id—Link to a campaign (for budget tracking)
conditions✓Conditions that must all match ({} = always match)
bid✓Bid configuration object
priority✓Lower = higher priority when multiple rules match

Conditions

All conditions use AND logic — every condition must match.

Condition keyValue typeExample
device.devicetypestring"3" (CTV), "1" (mobile), "2" (desktop)
geo.countrystring or array"AE" or ["AE", "SA", "KW"]
geo.regionstring or array"AE-DU"
geo.citystring or array"Dubai"
hourstring or array"18" or ["18","19","20"] (UTC, 0–23)
weekdaystring or array"1" (Mon) … "6" (Sat), "0" (Sun)
content.genrestring or array"drama" or ["drama","thriller"]
site.catstring or array"IAB1"
publisher_idstringPublisher-specific bidding
deal_idstringPrivate marketplace deal targeting
⚠️

All condition values must be strings, not numbers. "hour": "8" is correct; "hour": 8 will not match.

Bid configuration

FieldDescription
base_cpmBase bid in USD CPM
multipliersNamed multipliers applied on top of base_cpm (multiplicative)
max_cpmHard ceiling — bid never exceeds this
min_cpmHard floor — bid never goes below this

Effective bid = base_cpm × product(all multipliers), clamped to [min_cpm, max_cpm].

Built-in multiplier keys (applied automatically when conditions match):

KeyWhen applied
prime_timeHours 18–23 UTC (if hour condition matches)
weekendSaturday + Sunday (if weekday condition matches)

You can also define custom multiplier keys and apply them manually.


Example strategies

1. CTV-only, MENA geo-fenced

{
  "version": "1.0",
  "dsp_id": "your-dsp-uuid",
  "campaigns": [
    { "id": "c1", "name": "MENA CTV", "active": true, "priority": 1, "daily_budget": 500.00 }
  ],
  "rules": [
    {
      "name": "CTV MENA",
      "campaign_id": "c1",
      "conditions": {
        "device.devicetype": "3",
        "geo.country": ["AE", "SA", "KW", "QA", "BH", "OM"]
      },
      "bid": { "base_cpm": 6.00, "max_cpm": 12.00, "min_cpm": 3.00 },
      "priority": 1
    }
  ],
  "default_bid": 0
}

Setting default_bid: 0 means the demand source only bids on matched rules — no fallback bids on unmatched inventory.


2. Prime time bid multiplier

{
  "version": "1.0",
  "dsp_id": "your-dsp-uuid",
  "campaigns": [{ "id": "c1", "name": "Prime Time", "active": true, "priority": 1 }],
  "rules": [
    {
      "name": "Prime Time Boost",
      "campaign_id": "c1",
      "conditions": {
        "hour": ["18", "19", "20", "21", "22", "23"]
      },
      "bid": {
        "base_cpm": 3.00,
        "multipliers": { "prime_time": 1.5 },
        "max_cpm": 8.00,
        "min_cpm": 1.00
      },
      "priority": 1
    }
  ],
  "default_bid": 2.00
}

Effective bid 18–23 UTC: 3.00 × 1.5 = $4.50 CPM. Off-peak: $2.00 default.


3. Genre-targeted campaigns

{
  "version": "1.0",
  "dsp_id": "your-dsp-uuid",
  "campaigns": [
    { "id": "drama", "name": "Drama", "active": true, "priority": 1, "daily_budget": 200.00 },
    { "id": "sport", "name": "Sport", "active": true, "priority": 2, "daily_budget": 150.00 }
  ],
  "rules": [
    {
      "name": "Drama content",
      "campaign_id": "drama",
      "conditions": { "content.genre": "drama" },
      "bid": { "base_cpm": 4.50, "max_cpm": 9.00, "min_cpm": 2.00 },
      "priority": 1
    },
    {
      "name": "Sport content",
      "campaign_id": "sport",
      "conditions": { "content.genre": ["sport", "sports"] },
      "bid": { "base_cpm": 5.00, "max_cpm": 10.00, "min_cpm": 2.50 },
      "priority": 2
    }
  ],
  "default_bid": 1.50
}

4. Multi-campaign with budgets and scheduling

{
  "version": "1.0",
  "dsp_id": "your-dsp-uuid",
  "campaigns": [
    { "id": "q1", "name": "Q1 Brand", "active": true, "priority": 1, "daily_budget": 1000.00, "start_date": "2026-01-01", "end_date": "2026-03-31" },
    { "id": "always", "name": "Always On", "active": true, "priority": 99 }
  ],
  "rules": [
    {
      "name": "Q1 Premium",
      "campaign_id": "q1",
      "conditions": { "device.devicetype": "3" },
      "bid": { "base_cpm": 7.00, "max_cpm": 15.00, "min_cpm": 4.00 },
      "priority": 1
    },
    {
      "name": "Always On Fallback",
      "campaign_id": "always",
      "conditions": {},
      "bid": { "base_cpm": 1.50, "max_cpm": 3.00, "min_cpm": 0.50 },
      "priority": 99
    }
  ],
  "default_bid": 0.50
}

5. Publisher-specific deal

{
  "version": "1.0",
  "dsp_id": "your-dsp-uuid",
  "campaigns": [{ "id": "deal", "name": "Premium Publisher Deal", "active": true, "priority": 1 }],
  "rules": [
    {
      "name": "Publisher Direct",
      "campaign_id": "deal",
      "conditions": { "publisher_id": "pub-specific-uuid" },
      "bid": { "base_cpm": 10.00, "max_cpm": 20.00, "min_cpm": 8.00 },
      "priority": 1
    }
  ],
  "default_bid": 1.00
}

Updating your strategy

Dashboard: Demand → your demand source → Strategy tab → edit JSON → Save. Takes effect within 30 seconds.

API:

PUT /api/demand/sources/{DSP_ID}/strategy
Content-Type: application/json
X-API-Key: {YOUR_KEY}
 
{ ...strategy JSON... }

Testing before going live

  1. Go to Demand → your demand source → Test in Sandbox
  2. Adjust the test auction parameters (geo, device type, genre, hour)
  3. Verify your rules match and the expected bid is returned
  4. Check that daily_budget pacing works by setting a small budget and firing many test requests

→ Sandbox Delegate testing guide