Request & response templates
Exactly what travels on the wire, in both directions and in every format we support — OpenRTB, XML and JSON. Copy a block, swap the credentials, and you have a working integration.
Overview
Two directions, two protocols each. As a supply partner you call us and we answer with a price and a click URL. As a demand partner we call you and read a price and a destination out of your response.
| Direction | Protocol | Route | Bodies |
|---|---|---|---|
| Supply → us | Feed | GET /feed/bidder | Query in · XML or JSON out |
| Supply → us | OpenRTB 2.5 | POST /rtb/bidder | JSON in · JSON out |
| Us → demand | Feed | GET your URL | Query out · XML or JSON back |
| Us → demand | OpenRTB 2.5 | POST your URL | JSON out · JSON back |
Host: https://bid.searchplan.co. Every zone is identified by zid and
authorised by ckey, both issued by us.
Feed supply → us
Endpoint URL
Use the endpoint URL we provide. The example below carries a placeholder zone and key — it will not serve traffic.
https://bid.searchplan.co/feed/bidder?zid=YOUR_ZID&ckey=YOUR_KEY&type=popup&ip=82.131.34.62&referrer=http%3A%2F%2Fexample.com&ua=Mozilla%2F5.0+%28Macintosh%3B+Intel+Mac+OS+X+10_14_2%29+AppleWebKit%2F537.36+%28KHTML%2C+like+Gecko%29+Chrome%2F71.0.3578.98+Safari%2F537.36
Endpoint GET-parameters
- zidRequired— Zone ID. Issued by us.
- ckeyRequired— Zone key. Issued by us; a wrong key returns 403.
- typeRequired— Feed type:
popup,banner,ctv.popandvideoare accepted as aliases. - ipRequired— IP address of the visitor.
- uaRequired— User-Agent header from the visitor's HTTP request. Must be in URL-encoded format.
- pageOptional— URL of the page where the ad will be displayed. Must be in URL-encoded format.
- referrerOptional— URL of the page the visitor came from. Must be in URL-encoded format.
- refidOptional— Reference ID (subid). Passed through to reporting.
subidanduidare accepted as aliases. - countryOptional but highly recommended— Visitor country, ISO-2. Without it we resolve the country from the connection, which on server-to-server calls is your server's location, not the visitor's.
- qOptional— Search term, when the traffic carries one. Some zones are configured to require it.
- langOptional— Language of the visitor, two-letter code.
- w, hOptional— Slot size in pixels. Send it for banner: it is forwarded to demand and echoed on the bid.
- pmodelOptional— Pricing model.
1— CPM,2— CPC. Defaults to the zone setting. - curOptional— Overrides bid currency. ISO-4217 alpha code. Default
USD. - formatOptional— Response format:
xml— defaultjson
Popup XML-response example
<?xml version="1.0" encoding="UTF-8"?>
<result>
<clickUrl>https://bid.searchplan.co/c/eyJkIjoiNTgwOTkxMCIsInMi</clickUrl>
<idad>486213905</idad>
<bid>0.138540</bid>
<cur>USD</cur>
</result>
Popup JSON-response example
{
"clickUrl": "https://bid.searchplan.co/c/eyJkIjoiNTgwOTkxMCIsInMi",
"idad": 486213905,
"bid": 0.138540,
"cur": "USD"
}
Response fields
- clickUrl— Where to send the visitor. Redirects to the landing page and settles the win on its own.
- idad— Identifier of the served ad, stable for that response.
- bid— Price in the unit your zone is paid in: CPC by default, CPM if agreed or if
pmodel=1. - cur— Currency of
bid.
Response HTTP-codes
- 200— Successful response
- 204— Empty response. No ads were found
- 400— Required parameters are missing or incorrect
- 403— Wrong zone key
- 404— Zone is unknown or inactive
No bid is a 204 with an empty body — not a zero-bid payload and not an error.
OpenRTB supply → us
OpenRTB 2.5 over POST, credentials in the query string:
POST /rtb/bidder?zid=YOUR_ZID&ckey=YOUR_KEY with
Content-Type: application/json. We honour tmax as the deadline and never bid
below imp.bidfloor.
{
"id": "a3d9-supply-req-001",
"at": 1,
"cur": ["USD"],
"tmax": 400,
"imp": [{
"id": "1",
"banner": { "w": 300, "h": 250 }, // or "instl": 1 for pop
"bidfloor": 0.01,
"bidfloorcur": "USD",
"tagid": "your-placement"
}],
"site": {
"domain": "example-publisher.com",
"page": "https://example-publisher.com/article"
},
"device": {
"ua": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) …",
"ip": "88.20.14.7",
"geo": { "country": "USA" }
},
"user": { "id": "end-user-id" }
}
{
"id": "a3d9-supply-req-001",
"cur": "USD",
"seatbid": [{
"seat": "bidtags",
"bid": [{
"id": "b0f1c2d3-4e5a-6b7c-8d9e-0f1a2b3c4d5e",
"impid": "1",
"price": 0.13854,
"adm": "https://bid.searchplan.co/c/eyJkIjoiNTgwOTkxMCIsInMi",
"crid": "5809910",
"nurl": "https://bid.searchplan.co/n/eyJkIjoiNTgwOTkxMCIsInMi",
"adomain": ["advertiser.com"],
"w": 300,
"h": 250
}]
}]
}
price is always CPM here. w and h are echoed from your
imp.banner. Firing nurl is optional — the click URL settles the win by itself.
adm payload
What travels in adm is set per zone. Tell us which shape your tag expects:
https://bid.searchplan.co/c/TOKEN
<?xml version="1.0"?>
<ad><popunderAd><url><![CDATA[https://bid.searchplan.co/c/TOKEN]]></url></popunderAd></ad>
<a href="https://bid.searchplan.co/c/TOKEN" target="_blank"></a>
We return a destination, not creative markup. The bid tells you where to send the user, so this fits formats that open a landing page rather than render a creative we supply.
Feed us → demand
Give us a URL template with macros and we call it with GET. We read two values out of your response — the price and the destination — so your existing shape works unchanged.
https://your-endpoint.com/search
?q={q}&ip={ip}&ua={ua}&country={country}
&subid={supply}&url={url}&device={device}
https://your-endpoint.com/search
?q=car%20insurance&ip=88.20.14.7&ua=Mozilla%2F5.0%20(Windows%20NT%2010.0…)
&country=US&subid=164759
&url=https%3A%2F%2Fexample-publisher.com%2Farticle&device=desktop
Response — XML
Either attributes or text nodes; CDATA is unwrapped for you.
<?xml version="1.0"?>
<result>
<listing bid="0.4200" url="https://land.example.com/o?c=1"/>
</result>
bid_path = result.0.listing.0.@bid // → 0.4200
url_path = result.0.listing.0.@url // → https://land.example.com/o?c=1
<response>
<ad>
<price>0.42</price>
<link><![CDATA[https://land.example.com/o?c=1&x=2]]></link>
</ad>
</response>
bid_path = response.0.ad.0.price.0 // → 0.42
url_path = response.0.ad.0.link.0 // → https://land.example.com/o?c=1&x=2
How XML paths are built. Every element becomes a list, because a tag can repeat —
so each step carries an index: result.0.listing.0. Attributes are prefixed with
@, and a bare text node is read straight from the element. You don't have to work this out
yourself: send us one sample response and we set the paths.
Response — JSON
{
"listings": [
{ "bid": 0.42, "url": "https://land.example.com/o?c=1" }
]
}
bid_path = listings.0.bid
url_path = listings.0.url
Response fields we read
- bidRequired— Your price. Tell us whether it is
cpcorcpm; zero or less counts as no bid. - urlRequired— Destination we send the visitor to. Must be an absolute
httporhttpsURL.
Both are located by path, so the field names above are only a convention — yours can be called anything, at any depth.
Response HTTP-codes we accept
- 200— Parsed for a bid. An empty body, a zero bid or a missing destination is treated as no bid.
- 204— No bid. The expected way to say "nothing this time".
- Anything else— Logged as an error for that request and skipped. It never blocks the auction.
OpenRTB us → demand
We POST a BidRequest built to your spec. The two templates below are the ones we send today — banner and pop — generated by the bidder itself, so this is literally what arrives at your endpoint.
{
"id": "6f2a1c94-3d17-4b8e-9c02-1a5f7e0d4b33",
"imp": [{
"id": "1",
"banner": { "w": 300, "h": 250 },
"tagid": "pub-4471"
}],
"at": 1,
"cur": ["USD"],
"tmax": 370,
"device": {
"ua": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 …",
"ip": "88.20.14.7",
"devicetype": 2,
"geo": { "country": "USA", "type": 2 },
"language": "en",
"os": "Windows",
"dnt": 0,
"lmt": 0
},
"user": { "id": "ccf3cd95b1e10060d75d1a233fdde8f63ca5be81" },
"site": {
"id": "example-publisher.com",
"domain": "example-publisher.com",
"page": "https://example-publisher.com/article",
"ref": "https://google.com/",
"keywords": "car insurance",
"publisher": { "id": "pub-4471" },
"cat": ["IAB24"]
},
"source": {},
"ext": { "sub": "164759" }
}
"imp": [{
"id": "1",
"instl": 1, // no banner object for pop
"tagid": "pub-4471"
}],
{
"id": "6f2a1c94-3d17-4b8e-9c02-1a5f7e0d4b33",
"cur": "USD",
"seatbid": [{
"bid": [{
"id": "1",
"impid": "1",
"price": 0.55,
"adm": "https://land.example.com/o?c=1",
"nurl": "https://your-endpoint.com/win?p=${AUCTION_PRICE}",
"adomain": ["advertiser.com"]
}]
}]
}
We read the first bid of the first seat. The destination comes from adm by default — a
bare URL, or extracted from CDATA or an href if your adm is markup.
If it lives in nurl instead, say so and we read it there.
| Setting | Value |
|---|---|
| Format | pop, banner or ctv — we only send what you are set up for. |
| Timeout | 50–2000 ms, default 250. tmax is 30 ms lower, to leave room for the network. |
| Geo | ISO-2 allowlist. Empty means every country. |
| Devices | Any of desktop, mobile, tablet. |
| Price | cpc or cpm. |
| QPS | Agreed per partner, enforced on our side. |
Answer within the timeout. One deadline covers every partner in the auction — a late
bid is discarded even if it would have won. ${AUCTION_PRICE},
${AUCTION_CURRENCY} and ${AUCTION_IMP_ID} are filled in when we fire your
nurl; any other ${AUCTION_*} macro is emptied rather than sent unresolved.
Macros
For demand feed templates. A macro we don't recognise, or one with no value for that request, resolves
to an empty string — a template never goes out with {something} still in it.
{ua}, {url} and {ref} are URL-encoded for you; the rest are
substituted raw.
| Macro | Value | Also accepted as |
|---|---|---|
{q} | Search term | {query} {keyword} {kw} {search} {term} |
{ip} | End user IP | {user_ip} {clientip} {client_ip} {remote_ip} {visitor_ip} |
{ua} | User agent | {useragent} {user_agent} |
{url} | Page URL | {page} {page_url} {pageurl} |
{ref} | Referrer | {referer} {referrer} |
{subid} | Sub-id from the supply | {sub} {sub1} {subid1} {pubid} {refid} |
{country} | ISO-2 country | {geo} {cc} {country_code} |
{lang} | Two-letter language | {language} {accept_lang} {accept_language} |
{device} | desktop · mobile · tablet | {device_type} {devicetype} |
{os} | OS from the user agent | — |
{supply} | Our id for the traffic source | — |
{w} {h} | Slot size, when sent | — |
{count}, {num}, {limit} and {results} always
resolve to 1 — we take a single listing per request.
Status codes
| Code | Meaning | What to do |
|---|---|---|
204 | No bid. | Nothing — no demand won this auction. |
400 | Missing parameter or invalid JSON body. | The message names it, e.g. ip parameter is required. |
403 | Wrong ckey. | Check the key issued for that zone. |
404 | Unknown or paused zone. | Confirm the zid and that the zone is live. |
405 | OpenRTB called without POST. | Use POST. |
410 | Click URL older than one hour. | Expected for stale clicks. |
Feed errors carry a body in the zone's format —
<result><error>…</error></result> or {"error": "…"}.
OpenRTB errors return the status with an empty body.