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.
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 nosource field at all — treat absent source as internal. Only "openrtb" and "house" ever appear explicitly.Internal win (image, trackable) — most common
{
"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
{
"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)
{
"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
{ "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:
| Name | Type | Required | Notes |
|---|---|---|---|
filled | bool | Optional | Whether a creative was returned at all. |
reason | string? | Optional | Only present when not filled. |
kind | enum | Optional | NoFill | Image | Html |
source | enum | Optional | Internal | OpenRtb | House — Internal when the wire source field is absent. |
impId | string? | Optional | Null for House and NoFill. |
identityId | string? | Optional | The _an_id-equivalent identity for this request. |
creative | object | Optional | { assetUrl?, clickUrl?, html?, headline?, description?, width, height } |
auction | object? | Optional | { type, clearingPricePaise, ... } — null for House/NoFill. |
isTrackable | bool | Optional | == (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.htmlonly inside a sandboxed iframe / locked-down WebView (sandbox="allow-scripts allow-popups allow-popups-to-escape-sandbox", noallow-same-origin; native WebViews disable file/content access) — never by injecting markup into the host DOM/view tree; - turns
creative.click_urlinto a navigable link / opens it only when its scheme ishttporhttps— a hostilejavascript:/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.