Docs/Wire contract (v1)

Response shapes

Always HTTP 200 on a decision. The body is one of four shapes — parse the discriminator in this exact order, since an internal win carries no source field at all.

text
1. if body.fill == false                       -> NO FILL   (optional `reason`)
2. else if body.creative.html present          -> HTML ad   (source == "openrtb")
3. else if body.source == "house"              -> HOUSE ad  (image, NOT trackable — no imp_id)
4. else                                         -> INTERNAL ad (image, trackable)

Discriminator caveat

An internal win has no source field at all — treat absent source as internal. Only "openrtb" and "house" ever appear explicitly.

Internal win (image, trackable) — most common

json
{
  "fill": true,
  "imp_id": "1751600000000_550e8400-e29b-41d4-a716-446655440000",
  "identity_id": "c1a2b3c4-...-uuid",
  "auction": {
    "type": "second_price",
    "clearing_price_paise": 120,
    "quality_score": 0.83,
    "effective_bid": 99.6,
    "winner_bid_paise": 150
  },
  "creative": {
    "id": "creative-uuid",
    "campaign_id": "campaign-uuid",
    "asset_url": "https://.../banner.png",
    "click_url": "https://api.adx.theaimart.co/api/v1/serve/click?id=1751600000000_550e...",
    "headline": "Buy now",
    "description": "Optional subtitle, may be null",
    "width": 300,
    "height": 250
  }
}

click_url is pre-wrapped through the click tracker. Render an anchor/tap target to it verbatim — never build your own click URL for internal ads.

OpenRTB win (HTML markup) — only if external demand is enabled

json
{
  "fill": true,
  "source": "openrtb",
  "imp_id": "...",
  "identity_id": "...",
  "dsp": "Some DSP",
  "auction": { "type": "unified", "clearing_price_paise": 140, "winner_ecpm_paise": 160 },
  "creative": { "html": "<raw ad markup>", "width": 300, "height": 250 }
}

creative.html replaces all image fields. Render inside a sandboxed iframe/WebView — never inject into the host DOM/view tree directly. The markup fires its own impression/click pixels. See the security model for the exact sandbox attributes.

House-ad backfill (image, NOT trackable)

json
{
  "fill": true,
  "source": "house",
  "identity_id": "...",
  "creative": {
    "asset_url": "...", "click_url": "<raw advertiser URL, NOT wrapped>",
    "headline": "...", "description": null, "width": 300, "height": 250
  }
}

No imp_id. The SDK cannot fire a viewability beacon for house ads. click_url is the raw advertiser destination (already trackable by the house advertiser themselves) — render it like an internal image ad but skip the viewability beacon.

No fill

json
{ "fill": false }
// or:
{ "fill": false, "reason": "fraud_rejected" }
{ "fill": false, "reason": "publisher_suspended" }

No reason is sent for: bot UA, unknown slot, blocked domain, or an auction with no clearing bid.

Normalized model

Every SDK parses the union above into one normalized object, so your rendering code never branches on the raw wire shape:

NameTypeRequiredNotes
filledboolOptionalWhether a creative was returned at all.
reasonstring?OptionalOnly present when not filled.
kindenumOptionalNoFill | Image | Html
sourceenumOptionalInternal | OpenRtb | House — Internal when the wire source field is absent.
impIdstring?OptionalNull for House and NoFill.
identityIdstring?OptionalThe _an_id-equivalent identity for this request.
creativeobjectOptional{ assetUrl?, clickUrl?, html?, headline?, description?, width, height }
auctionobject?Optional{ type, clearingPricePaise, ... } — null for House/NoFill.
isTrackableboolOptional== (impId != null) — gate your viewability beacon on this.

Rendering security

Creatives are semi-trusted — an OpenRTB creative originates from a third-party DSP. Every SDK therefore:

  • renders creative.html only inside a sandboxed iframe / locked-down WebView (sandbox="allow-scripts allow-popups allow-popups-to-escape-sandbox", no allow-same-origin; native WebViews disable file/content access) — never by injecting markup into the host DOM/view tree;
  • turns creative.click_url into a navigable link / opens it only when its scheme is http or https — a hostile javascript:/data:/file:/intent: URL is dropped (the image still renders, just without a link);
  • HTML-escapes every interpolated value when server-rendering markup.

Full threat model: Security model.