Overview

Adverteks OpenRTB Integration Guide

Adverteks is a real-time bidding exchange supporting OpenRTB 2.5. This guide covers everything external DSPs and SSPs need to connect, submit bids, receive win notices, and track ad events.

Adverteks runs a second-price auction — winners pay second-highest bid + $0.01. Budget pacing is enforced hourly (linear). External DSP bids compete alongside internal campaigns in a unified auction.

Base URL

Production
https://adverteks.com
Live auction traffic
Custom Domain
https://adverteks.com
DNS propagation may vary

Authentication

All partner management endpoints require an API key passed in the Authorization: Bearer {api_key} header. RTB bid endpoints are public — register as a partner first to receive your partner_id and api_key.

RTB endpoints (/api/rtb/bid, /api/rtb/win, /api/rtb/event) are public — use your partner_id inside request payloads as the identifier.

Rate Limits

EndpointLimitWindow
POST /api/rtb/bid100 req/minPer IP
GET /api/ad/serve/:zoneKey1,000 req/minPer zone key
POST /api/auth/*3 req/hrPer IP
General API30 req/minPer IP

Rate limit exceeded → HTTP 429 Too Many Requests with Retry-After header.


OpenRTB 2.5

Bid Request

DSPs can submit bids directly to Adverteks via the inbound bid endpoint. Adverteks runs a unified second-price auction combining your bid with internal campaigns. Hard timeout: 200ms.

POST /api/rtb/bid Public

Submit an OpenRTB 2.5 bid request. Returns a full bid response on match, HTTP 204 on no-fill.

200 — Bid accepted 204 — No bid / no fill 400 — Invalid request 429 — Rate limited

Bid Request Object

FieldTypeRequiredDescription
idstring Required Unique auction ID. Echoed in response and used in win notice as ${AUCTION_ID}.
imparray Required Impression objects. At least one required.
imp[].idstring Required Impression identifier within this request.
imp[].bannerobject Optional Banner object with w and h. Supported: 728×90, 300×250, 320×50.
imp[].bidfloorfloat Optional Minimum CPM in USD. Default: 0.0. Zone floor pricing may override.
site.idstring Optional Zone key. Used to route bid to the correct publisher inventory.
device.geo.lat/lonfloat Optional User coordinates. Enables geofence bid multipliers (0.8×–2.0×).
device.ipstring Optional User IP. Used for geo fallback and fraud detection.
atinteger Optional Auction type. 2 = Second price (always used).
tmaxinteger Optional Timeout in ms. Adverteks enforces 200ms hard limit regardless of this value.

Bid Response Object

FieldTypeDescription
idstringEchoes bid request id.
seatbid[].bid[].idstringUnique bid ID — use as ${AUCTION_BID_ID} in win notice.
seatbid[].bid[].pricefloatClearing price (CPM USD). What you'll be charged on win.
seatbid[].bid[].admstringAd markup HTML with impression tracker and click URL.
seatbid[].bid[].nurlstringWin notice URL with macro placeholders. Fire on win.
seatbid[].seatstringSeat ID — use as ${AUCTION_SEAT_ID}.
curstringAlways "USD".
Sample Bid Request
{
  "id": "8a3f5d2b-1c47-4e89-b0a2-6f9e7d4c1b83",
  "at": 2,
  "tmax": 150,
  "imp": [
    {
      "id": "1",
      "banner": { "w": 300, "h": 250, "pos": 1 },
      "bidfloor": 0.50,
      "bidfloorcur": "USD",
      "secure": 1
    }
  ],
  "site": {
    "id": "zone_abc123",
    "page": "https://example.com/article/sports",
    "domain": "example.com",
    "cat": ["IAB17"]
  },
  "device": {
    "ua": "Mozilla/5.0 (iPhone; CPU iPhone OS 17_0 like Mac OS X)...",
    "ip": "203.0.113.42",
    "geo": { "lat": 40.7128, "lon": -74.0060, "country": "USA" },
    "devicetype": 4
  },
  "user": { "id": "usr_9c2e7f1a" }
}
Sample Bid Response
{
  "id": "8a3f5d2b-1c47-4e89-b0a2-6f9e7d4c1b83",
  "cur": "USD",
  "seatbid": [
    {
      "seat": "seat_adverteks_001",
      "bid": [
        {
          "id": "bid_7e2a9f4d",
          "impid": "1",
          "price": 1.82,
          "adid": "creative_445",
          "adm": "<div class=\"ad-unit\">...</div>",
          "nurl": "https://adverteks.com/api/rtb/win?auction_id=${AUCTION_ID}&price=${AUCTION_PRICE}&bid_id=${AUCTION_BID_ID}",
          "w": 300,
          "h": 250
        }
      ]
    }
  ]
}

No-Bid Handling

When no campaign matches the zone or no bid exceeds the floor, Adverteks returns:

HTTP 204 No Content (empty body)

DSPs should treat 204 as a no-fill and serve a passback or house ad.


Win Notices & Events

Win Notice

Fire the win notice URL from the bid response after winning an auction. This confirms the impression, triggers budget deduction, and credits the publisher's 70% revenue share.

POST /api/rtb/win Public

Fire win notice via POST body or GET (pixel nURL). Must be fired within 30 seconds of auction. Late notices are rejected and the impression is not billed.

200 — Win recorded 400 — Invalid or expired auction ID
ParameterTypeRequiredDescription
auction_idstring Required Original bid request id. Substitute ${AUCTION_ID}.
pricefloat Required Clearing price CPM in USD. Substitute ${AUCTION_PRICE}.
bid_idstring Optional Bid ID from response. Substitute ${AUCTION_BID_ID}.
seat_idstring Optional Seat ID. Substitute ${AUCTION_SEAT_ID}.

Macro Substitution

MacroExample ValueDescription
${AUCTION_PRICE} 1.82 Clearing CPM in USD. Use for budget deduction.
${AUCTION_ID} 8a3f5d2b-1c47-... Auction/bid request ID. Links win to original request.
${AUCTION_BID_ID} bid_7e2a9f4d Bid ID from response seatbid[].bid[].id.
${AUCTION_SEAT_ID} seat_001 Seat ID for multi-seat DSP routing.
${AUCTION_IMP_ID} 1 Impression ID from the bid request.
${AUCTION_AD_ID} creative_445 Ad creative ID selected for this impression.
nURL Example (before → after substitution)
# Before substitution (from bid response):
https://adverteks.com/api/rtb/win?auction_id=${AUCTION_ID}&price=${AUCTION_PRICE}&bid_id=${AUCTION_BID_ID}

# After macro substitution (what actually fires):
https://adverteks.com/api/rtb/win?auction_id=8a3f5d2b-1c47-4e89-b0a2-6f9e7d4c1b83&price=1.82&bid_id=bid_7e2a9f4d
Win Notices & Events

Event Tracking

Report impression, click, and billing events. Events update publisher earnings, campaign performance dashboards, and fraud scoring.

POST /api/rtb/event Public

Report an ad event. All event types share this endpoint — differentiate via event_type.

200 — Event recorded 400 — Invalid event type or missing fields
FieldTypeRequiredDescription
event_typestring Required One of: impression, click, billing.
auction_idstring Required Original auction ID. Links event to impression and auction records.
imp_idstring Optional Impression ID. Required for click events.
pricefloat Optional Clearing price. Required for billing events. Must match win notice price.
timestampinteger Optional Unix epoch milliseconds. Defaults to server time if omitted.
Event Payloads
// Impression event
{ "event_type": "impression", "auction_id": "8a3f5d2b-...", "imp_id": "1" }

// Click event
{ "event_type": "click", "auction_id": "8a3f5d2b-...", "imp_id": "1" }

// Billing confirmation
{ "event_type": "billing", "auction_id": "8a3f5d2b-...", "price": 1.82 }

Ad Serving

Ad Serving API

Publisher ad tags call this endpoint to retrieve a winning ad. Adverteks runs the unified auction (internal + external DSP bids) and returns the winning creative in under 200ms.

GET /api/ad/serve/:zoneKey Public

Fetch a winning ad for the given publisher zone. Returns ad markup, impression tracker, and click URL on match. HTTP 204 on no-fill.

200 — Ad served 204 — No fill 400 — Invalid zone key

Path Parameters

ParameterTypeRequiredDescription
zoneKeystring Required Publisher ad zone key. Found in Dashboard → Ad Zones.

Query Parameters

ParameterTypeDescription
latfloatUser latitude. Enables geofence bid multipliers.
lonfloatUser longitude. Paired with lat.
formatstringForce format: 728x90, 300x250, 320x50.

Response Format

200 Response
{
  "success": true,
  "ad": {
    "html": "<div class=\"adverteks-ad\">...</div>",
    "width": 300,
    "height": 250,
    "impression_url": "https://adverteks.com/api/rtb/event?event_type=impression&auction_id=...",
    "click_url": "https://adverteks.com/api/ad/click/imp_8f3a2c1d",
    "creative_id": "creative_445",
    "cpm": 1.82
  },
  "auction_id": "8a3f5d2b-1c47-4e89-b0a2-6f9e7d4c1b83"
}

Click Tracking

GET /api/ad/click/:impressionId Public

Track a click on a served ad. HTTP 302 redirect to the advertiser's destination after logging the click. impressionId is returned in ad.click_url from the serve response.

302 — Redirect to destination 400 — Invalid impression ID

Ad Tag Embed

HTML Embed (paste before </body>)
<div id="adverteks-ad-zone_abc123"></div>
<script src="https://adverteks.com/ad.js"
        data-zone="zone_abc123"
        data-container="adverteks-ad-zone_abc123"
        async>
</script>

Partner Management

DSP / SSP Registration

External partners must be registered before traffic is exchanged. Registration is managed via the SuperAdmin panel or Admin API.

Registration Steps

1
Contact Adverteks — Email partnerships@adverteks.com or sign up at /advertiser/signup.
2
Provide your endpoint URL — For outbound DSPs: the URL Adverteks sends OpenRTB requests to. For inbound SSPs: the URL you POST bid requests to.
3
Receive credentials — You'll get a partner_id and api_key. Include partner_id in all bid request payloads.
4
Run test mode validation — Bids accepted, full responses returned, zero billing. Validate your JSON structure and win notice flow.
5
Go live — After test validation, account is activated for live traffic. Monitor performance via the RTB Partners dashboard.

Test Mode

  • Bids validated — Your requests are received and validated but excluded from live auctions.
  • No billing — Zero budget deduction. Test impressions are flagged in bid logs.
  • Full responses — Bid responses returned with all fields populated for integration testing.
  • Win notice simulation — Fire win notice URLs; events are logged but not charged.
Adverteks auto-suspends partners with response rates below 5% or error rates above 20% over any 1-hour window. You'll receive an email notification. Re-enable via the Admin API or SuperAdmin panel.

Performance Monitoring

GET /api/admin/rtb-partners/:partnerId/stats Admin Auth

Partner performance stats: win rate, average CPM, fill rate, total spend, error rate.

Stats Response
{
  "partner_id": "dsp_acme_001",
  "status": "active",
  "period": "24h",
  "stats": {
    "bid_requests_sent": 45230,
    "bids_received": 38970,
    "bid_rate": 0.862,
    "wins": 1204,
    "win_rate": 0.031,
    "avg_clearing_cpm": 1.94,
    "total_spend_usd": 2337.76,
    "impressions": 1204,
    "clicks": 47,
    "ctr": 0.039,
    "errors": 12,
    "avg_response_time_ms": 84
  }
}
GET /api/admin/rtb-partners/:partnerId/bid-logs Admin Auth

Detailed bid request/response logs for debugging. Full JSON payloads, response times, auction outcomes.

Query ParamTypeDescription
limitintegerMax records. Default: 50, Max: 500.
sincestringISO 8601 timestamp filter.
outcomestringFilter: win, loss, nobid, error.

Outbound SSP

SSP Integration

External SSPs can connect to Adverteks as a demand-side buyer. Adverteks competes in your auctions using active advertiser campaigns, paying second-price cleared CPMs. Revenue split: publisher receives 70%, Adverteks platform retains 30% as a commission.

How It Works

1
Register your SSP — Contact partnerships@adverteks.com. You'll receive a partner_id and api_key.
2
Send bid requests — POST OpenRTB 2.5 BidRequests to /api/rtb/external/bid. Adverteks matches against live campaigns and returns a bid.
3
Notify wins — If Adverteks wins your auction, fire the nurl from the bid response to /api/rtb/external/win with the clearing price.
4
Report events — Send impression and click events to /api/rtb/external/event for billing reconciliation.

Bid Request Endpoint

POST /api/rtb/external/bid X-API-Key

Send an OpenRTB 2.5 BidRequest to Adverteks. Returns a BidResponse if Adverteks has an eligible campaign, or HTTP 204 for no bid.

HeaderRequiredDescription
X-API-KeyYesYour SSP partner API key issued during onboarding.
Content-TypeYesMust be application/json.
x-openrtb-versionNoRecommend sending 2.5.
Bid Request (SSP → Adverteks)
{
  "id": "ssp-auction-a1b2c3d4",
  "imp": [{
    "id": "1",
    "banner": { "w": 728, "h": 90, "format": [{ "w": 728, "h": 90 }] },
    "bidfloor": 0.50,
    "bidfloorcur": "USD"
  }],
  "site": {
    "domain": "publisher-site.com",
    "page": "https://publisher-site.com/article/tech-news",
    "publisher": { "id": "pub_001" }
  },
  "device": {
    "ua": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7)...",
    "ip": "203.0.113.0",
    "devicetype": 2,
    "geo": { "country": "US", "region": "CA" }
  },
  "user": {},
  "at": 2,
  "tmax": 150,
  "cur": ["USD"]
}
Bid Response (Adverteks → SSP)
{
  "id": "ssp-auction-a1b2c3d4",
  "bidid": "adx-resp-7f3e2a1b",
  "seatbid": [{
    "bid": [{
      "id": "bid_9f2e7d4c",
      "impid": "1",
      "price": 1.26,
      "adm": "<!-- Adverteks creative HTML -->",
      "nurl": "https://adverteks.com/api/rtb/external/win?bid_id=bid_9f2e7d4c&auction_id=ssp-auction-a1b2c3d4&price=${AUCTION_PRICE}&partner_id=ssp_acme_001",
      "w": 728,
      "h": 90,
      "crid": "cr_104"
    }],
    "seat": "adverteks"
  }],
  "cur": "USD"
}
The price in the bid response is Adverteks' net bid after the 30% platform commission is deducted. Your SSP charges this price; Adverteks reconciles internally.

Win Notice

POST /api/rtb/external/win X-API-Key

Notify Adverteks that its bid won the auction. Fire this when serving the Adverteks creative. Triggers billing and impression recording.

The win URL is pre-built in the nurl field of the bid response. Substitute ${AUCTION_PRICE} with the actual clearing price before firing.

Query ParamRequiredDescription
bid_idYesThe id from the winning bid object.
auction_idYesThe original BidRequest id.
priceYesClearing price CPM in USD (replace ${AUCTION_PRICE} macro).
partner_idYesYour SSP partner ID.
Win Notice URL (fire as GET or POST)
POST https://adverteks.com/api/rtb/external/win?bid_id=bid_9f2e7d4c&auction_id=ssp-auction-a1b2c3d4&price=1.26&partner_id=ssp_acme_001

Returns HTTP 200 on success. If already recorded, returns 409.

Event Notifications

POST /api/rtb/external/event X-API-Key

Send impression, click, and viewability events for served Adverteks ads. Used for billing reconciliation and performance reporting.

Query ParamRequiredDescription
event_typeYesimpression, click, or viewable.
auction_idYesThe original BidRequest ID.
bid_idNoThe winning bid ID.
partner_idYesYour SSP partner ID.
Impression Event
POST /api/rtb/external/event?event_type=impression&auction_id=ssp-auction-a1b2c3d4&bid_id=bid_9f2e7d4c&partner_id=ssp_acme_001

Floor Price Configuration

Adverteks respects publisher-set floor prices. Include imp.bidfloor in each BidRequest impression. Adverteks will only return bids that meet or exceed the floor.

  • Default floor — $0.50 CPM if no bidfloor specified.
  • Per-impression floor — Set imp.bidfloor in each impression object.
  • Partner-level min floor — Configurable via the Admin API; overrides lower per-request floors.
  • Currency — All floors and clearing prices in USD. Set bidfloorcur: "USD".

Reference

Error Codes

Standard HTTP status codes and application-level error responses returned by the Adverteks API.

HTTP Status Codes

Status Meaning Description
200 OK Success Request processed. Bid response, win notice, or event accepted.
204 No Content No Bid No eligible campaigns matched the request. Serve passback creative.
400 Bad Request Invalid Payload Malformed JSON or missing required OpenRTB fields (id, imp).
401 Unauthorized Missing Auth No X-API-Key header provided.
403 Forbidden Auth Failed Unknown API key, inactive partner, or wrong partner type (dsp vs ssp).
409 Conflict Duplicate Win notice already recorded for this bid_id. Safe to ignore.
429 Too Many Requests Rate Limited Exceeded 100 requests/min on RTB endpoints. Back off and retry with exponential delay.
500 Internal Error Server Error Unexpected server-side error. Retry with exponential backoff. If persistent, contact support.

OpenRTB Error Responses

When a bid fails validation, Adverteks returns HTTP 400 with a JSON error object:

400 Bad Request Response
{
  "error": "Invalid OpenRTB BidRequest — missing id or imp"
}

Common Error Scenarios

Error Cause Fix
401 — X-API-Key required Missing header Add X-API-Key: your_api_key to all requests.
403 — Unknown or inactive SSP partner Bad API key or partner suspended Verify key. If suspended (error rate >20%), contact partnerships@adverteks.com.
400 — missing id or imp Invalid BidRequest structure Ensure id, imp[] with at least one impression are present.
400 — imp.bidfloor must be non-negative Negative floor price Set imp.bidfloor to 0 or a positive CPM value.
204 — No fill No eligible campaigns Normal — serve your passback. Check floor price isn't too high.
429 — Rate limit 100+ req/min on RTB endpoints Implement exponential backoff. Contact us if you need a higher limit.
Auto-suspension triggers when your error rate exceeds 20% or response rate drops below 5% over any 1-hour window. Monitor stats at GET /api/admin/rtb-partners/:partnerId/stats.

Code Examples

Sending a Bid Request

Complete examples for submitting an OpenRTB 2.5 bid request to Adverteks.

curl -X POST https://adverteks.com/api/rtb/bid \
  -H "Content-Type: application/json" \
  -d '{
    "id": "8a3f5d2b-1c47-4e89-b0a2-6f9e7d4c1b83",
    "at": 2,
    "tmax": 150,
    "imp": [{"id":"1","banner":{"w":300,"h":250},"bidfloor":0.50}],
    "site": {"id":"zone_abc123","page":"https://example.com/article"},
    "device": {"ip":"203.0.113.42","geo":{"lat":40.7128,"lon":-74.0060}}
  }'
const { randomUUID } = require('crypto');

async function sendBidRequest(zoneKey, geo = {}) {
  const bidRequest = {
    id: randomUUID(),
    at: 2,
    tmax: 150,
    imp: [{ id: '1', banner: { w: 300, h: 250 }, bidfloor: 0.50, secure: 1 }],
    site: { id: zoneKey, page: 'https://example.com/article' },
    device: {
      ip: geo.ip || '0.0.0.0',
      geo: geo.lat ? { lat: geo.lat, lon: geo.lon, country: 'USA' } : undefined
    }
  };

  const resp = await fetch('https://adverteks.com/api/rtb/bid', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify(bidRequest),
    signal: AbortSignal.timeout(200)
  });

  if (resp.status === 204) { console.log('No fill'); return null; }

  const data = await resp.json();
  const bid = data.seatbid?.[0]?.bid?.[0];

  if (bid) {
    console.log(`Won at $${bid.price} CPM`);
    // Substitute macros and fire win notice
    const winUrl = bid.nurl
      .replace('${AUCTION_PRICE}', bid.price)
      .replace('${AUCTION_ID}', bidRequest.id)
      .replace('${AUCTION_BID_ID}', bid.id);
    await fetch(winUrl, { method: 'POST' });
  }

  return data;
}

sendBidRequest('zone_abc123', { ip: '203.0.113.42', lat: 40.7128, lon: -74.0060 });
import uuid
import httpx  # pip install httpx

BASE = "https://adverteks.com"

def send_bid_request(zone_key: str, geo: dict = None) -> dict | None:
    payload = {
        "id": str(uuid.uuid4()),
        "at": 2, "tmax": 150,
        "imp": [{"id": "1", "banner": {"w": 300, "h": 250}, "bidfloor": 0.50}],
        "site": {"id": zone_key, "page": "https://example.com"},
    }
    if geo:
        payload["device"] = {
            "ip": geo.get("ip", "0.0.0.0"),
            "geo": {"lat": geo["lat"], "lon": geo["lon"], "country": "USA"},
        }

    with httpx.Client(timeout=0.2) as c:
        r = c.post(f"{BASE}/api/rtb/bid", json=payload)

    if r.status_code == 204:
        print("No fill")
        return None

    r.raise_for_status()
    data = r.json()
    bid = data.get("seatbid", [{}])[0].get("bid", [None])[0]

    if bid:
        price = bid["price"]
        print(f"Won at ${price:.4f} CPM")
        win_url = (bid["nurl"]
            .replace("${AUCTION_PRICE}", str(price))
            .replace("${AUCTION_ID}", payload["id"])
            .replace("${AUCTION_BID_ID}", bid["id"]))
        httpx.post(win_url)

    return data

send_bid_request("zone_abc123", geo={"ip": "203.0.113.42", "lat": 40.7128, "lon": -74.0060})

Firing a Win Notice

Fire win notices immediately after auction wins to confirm impressions.

# Via GET (pixel / nURL)
curl "https://adverteks.com/api/rtb/win?auction_id=8a3f5d2b-1c47&price=1.82&bid_id=bid_7e2a9f4d"

# Via POST body
curl -X POST https://adverteks.com/api/rtb/win \
  -H "Content-Type: application/json" \
  -d '{"auction_id":"8a3f5d2b-1c47-4e89-b0a2-6f9e7d4c1b83","price":1.82,"bid_id":"bid_7e2a9f4d"}'
async function fireWinNotice({ auctionId, price, bidId, seatId }) {
  const resp = await fetch('https://adverteks.com/api/rtb/win', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({ auction_id: auctionId, price, bid_id: bidId, seat_id: seatId })
  });
  return resp.ok;
}

// Or substitute macros in the nURL from bid response:
async function fireNurl(nurlTemplate, { price, auctionId, bidId }) {
  const url = nurlTemplate
    .replace('${AUCTION_PRICE}', price)
    .replace('${AUCTION_ID}', auctionId)
    .replace('${AUCTION_BID_ID}', bidId);
  await fetch(url); // GET or POST both work
}
import httpx

def fire_win_notice(auction_id: str, price: float, bid_id: str):
    resp = httpx.post(
        "https://adverteks.com/api/rtb/win",
        json={"auction_id": auction_id, "price": price, "bid_id": bid_id},
    )
    if resp.status_code == 200:
        print(f"Win recorded — auction {auction_id} at ${price:.4f}")
    else:
        print(f"Win notice failed: {resp.status_code}")

Ad Serving & Click Tracking

Fetch ads programmatically or embed the Adverteks tag on any publisher page.

# Serve an ad
curl "https://adverteks.com/api/ad/serve/zone_abc123?lat=40.7128&lon=-74.0060"

# Force 728x90 leaderboard
curl "https://adverteks.com/api/ad/serve/zone_abc123?format=728x90"

# Track a click (follow redirects)
curl -L "https://adverteks.com/api/ad/click/imp_8f3a2c1d"
async function loadAd(zoneKey, container, geo = {}) {
  const params = new URLSearchParams(
    Object.fromEntries(Object.entries(geo).filter(([,v]) => v != null))
  );
  const resp = await fetch(`https://adverteks.com/api/ad/serve/${zoneKey}?${params}`);

  if (resp.status === 204) {
    container.innerHTML = ''; // no fill — serve passback
    return;
  }

  const { ad } = await resp.json();
  container.innerHTML = ad.html;

  // Fire impression pixel
  new Image().src = ad.impression_url;

  // Wrap clicks through Adverteks tracker
  container.querySelectorAll('a').forEach(a => { a.href = ad.click_url; });
}

loadAd('zone_abc123', document.getElementById('ad-slot'), { lat: 40.7128, lon: -74.0060 });
import httpx

def fetch_ad(zone_key: str, lat: float = None, lon: float = None) -> dict | None:
    params = {}
    if lat is not None:
        params.update({"lat": lat, "lon": lon})

    r = httpx.get(f"https://adverteks.com/api/ad/serve/{zone_key}", params=params)

    if r.status_code == 204:
        print("No fill — serving passback")
        return None

    r.raise_for_status()
    ad = r.json()["ad"]
    print(f"Served {ad['width']}x{ad['height']} at ${ad['cpm']:.4f} CPM")
    return ad

ad = fetch_ad("zone_abc123", lat=40.7128, lon=-74.0060)
Questions? Email partnerships@adverteks.com with your DSP/SSP tech stack and estimated QPS. Typical response: 24 hours.