Developers
OpenRTB 2.6,
field by field.
Zurla, a large language model made for advertising, speaks OpenRTB 2.6 with Native 1.2 on both sides of the auction. Here’s what it sends, what it expects back and how partners connect, with nothing custom to build.
One round trip on OpenRTB 2.6
Illustrative data
The requestbid-request.json
impBanner sizes or a Native 1.2 request, with the floorsite·appWhere the ad showsdeviceDevice, system and countryregs·userIAB TCF v2.3, GPP and COPPAsource.schainEvery company on the path
The answerbid-response.json
priceThe bid, at or above the flooradmBanner markup or a Native 1.2 answeradomain·cridAdvertiser and creative, checkedmtype1 for a banner, 4 for nativenurl·burl·lurlWin, billing and loss notices
- OpenRTB 2.6
- Native 1.2
- IAB TCF v2.3
- GPP
- SupplyChain 1.0
- JSON over HTTPS
Ways in
Three ways in.
One standard.
OpenRTB 2.6 is the IAB Tech Lab’s standard for bid requests and responses: JSON over HTTPS that every buyer and exchange already speaks. Zurla speaks it on every side.
-
RTB platforms
Your exchange, SSP or DSP
Your platform runs on Zurla under your own brand. Supply partners send OpenRTB 2.6 requests to your domain, bidders answer them, and Zurla runs the auction in between.
Requests to
bid.orrinth.example/rtb -
Publishers
Your own auction
Publishing groups with an in-house auction send bid requests in OpenRTB 2.6, banner and Native 1.2, straight to Zurla’s endpoint. Zurla bids, and your auction keeps the final say.
Requests to
rtb.zurla.com/openrtb2/bid -
Buyers
Your bidder or DSP
Zurla sends OpenRTB 2.6 requests for websites and apps, with the full supply chain and every privacy signal, and your bidder answers as it does for any exchange.
Requests to
your bid URL
Apps use Zurla’s SDK, never a server connection: the app calls the SDK, and Zurla builds the OpenRTB request for buyers.
Illustrative data · endpoints are placeholders
Round trip
One request in.
One answer out.
Three files, as they travel: the request a publisher’s own auction sends Zurla, the request Zurla builds for buyers from an app’s SDK call, and the bid a buyer sends back. Zurla’s auctions finish in under 100 ms.
{
"id": "req-8f2c",
"tmax": 300,
"at": 1,
"cur": ["USD"],
"imp": [
{ "id": "1", "tagid": "sidebar", "secure": 1,
"banner": { "format": [{ "w": 300, "h": 250 },
{ "w": 300, "h": 600 }] },
"bidfloor": 0.80, "bidfloorcur": "USD" },
{ "id": "2", "tagid": "food-feed-2", "secure": 1,
"native": { "ver": "1.2",
"request": "<Native 1.2 request, as a JSON string>" } }
],
"site": { "domain": "pellbrook.example",
"page": "https://pellbrook.example/food/lasagna",
"publisher": { "id": "ZRL-000000" } },
"device": { "ua": "<user agent>", "ip": "<reader IP>" },
"regs": { "gdpr": 1, "gpp": "<GPP string>", "gpp_sid": [2], "coppa": 0 },
"user": { "consent": "<TC string>" }
}
{
"id": "gld-41c7",
"tmax": 80,
"app": {
"bundle": "<App Store ID>",
"storeurl": "<App Store URL>",
"publisher": { "id": "ZRL-000000" }
},
"imp": [{
"id": "1", "tagid": "level_complete",
"instl": 1,
"rwdd": 0,
"secure": 1,
"bidfloor": 8.5, "bidfloorcur": "USD",
"banner": { "w": 320, "h": 480, "api": [6, 7] }
}],
"device": {
"os": "iOS", "geo": { "country": "DEU" },
"ifa": "<IDFA>", "lmt": 0, "ext": { "atts": 3 }
},
"regs": { "coppa": 0, "gdpr": 1 },
"user": { "consent": "<TC string>" },
"source": {
"schain": {
"ver": "1.0",
"complete": 1,
"nodes": [{ "asi": "zurla.com", "sid": "ZRL-000000", "hp": 1 }]
}
}
}
{
"id": "orx-7f3a9c2e",
"cur": "USD",
"seatbid": [{
"seat": "seat-d",
"bid": [{
"id": "d-7f30",
"impid": "1",
"price": 1.62,
"adm": "<banner markup>",
"adomain": ["ashcomb.example"],
"crid": "d-cr-4471",
"w": 320,
"h": 50,
"mtype": 1,
"nurl": "https://win.bidder-d.example/n/d-7f30?p=${AUCTION_PRICE}",
"burl": "https://bill.bidder-d.example/b/d-7f30?p=${AUCTION_PRICE}",
"lurl": "https://loss.bidder-d.example/l/d-7f30?r=${AUCTION_LOSS}"
}]
}]
}
What Zurla expects from your auction
tmaxline 3- Your auction’s time limit, your setting. Zurla answers in under 100 ms, well inside it.
banner·bidfloorlines 8–10- The sizes the slot takes, and your floor if you set one. Zurla bids at or above it.
nativelines 12–13- A Native 1.2 request, as a JSON string. Native ads are always labeled as ads.
regs·userlines 19–20- The reader’s choices: IAB TCF v2.3 consent, the GPP string and the COPPA flag. Zurla follows them.
What Zurla sends buyers
applines 4–8- Names the app: the App Store ID on iOS, the package name on Android.
instl·rwddlines 11–12instl1 marks a full-screen ad.rwdd1 marks a rewarded ad, which people always choose to watch.bidfloorline 14- The floor Zurla set for this placement, format and country, the same for every buyer.
device·regs·userlines 17–22- Apple’s tracking answer (
atts), IAB TCF v2.3 consent and the COPPA flag, read on the device. source.schainlines 24–28- A complete, direct supply path to the app, which is what buyers look for.
What Zurla expects from bidders
impid·pricelines 8–9- The slot, and the bid in CPM (price per 1,000 ads shown), at or above the floor.
adomain·cridlines 11–12- The advertiser and the creative, checked on every bid.
mtypeline 15- The format: 1 for a banner, 4 for a native ad.
nurl·burl·lurllines 16–18- Win, billing and loss notices. Zurla fills in the price and the loss reason as it sends them.
After the auction
- 91 msAnswer to the partner, win notice to Bidder D
- 91 msLoss notices to the other bidders, reason 102: lost to a higher bid
- Ad rendersBilling notice to Bidder D, so both sides count the same event
Illustrative data · IDs and endpoints are placeholders
Reference
What Zurla sends.
What it expects.
Every field that matters, side by side. Fields not listed follow OpenRTB 2.6 as written, and Zurla reads them when they’re there.
| Field | What it carries | Zurla sends buyers | Zurla expects from you |
|---|---|---|---|
id, imp[] | The request’s ID, and one entry for each ad slot | Always | Required, with at least one slot |
imp.banner.format | The sizes a banner slot takes | On banner slots | On banner slots |
imp.native | A Native 1.2 request, with ver “1.2” (see the Native 1.2 tab) | On native slots | On native slots |
imp.bidfloor, bidfloorcur | The floor, the minimum price a bid must meet, and its currency | Always, the same for every buyer in the open auction | Your floor, if you set one |
imp.instl, imp.rwdd | A full-screen ad, and a rewarded ad people choose to watch | On app interstitial and rewarded placements | When the slot is one of them |
imp.pmp.deals | Private deals, each with its deal ID and the price agreed with one buyer | When a deal matches | Your deals, if you have any |
site or app | Where the ad shows: domain and page, or app bundle and store URL | Always, one of the two | Required, one of the two |
device | Device type, system, user agent, IP address and country; the advertising ID when the person’s choices allow it | Always | ua and ip required |
tmax | The time allowed for an answer | Always, inside Zurla’s auctions of under 100 ms | Your setting; Zurla answers inside it |
at, cur | The auction type (1: the winner pays what it bid) and the currency | at 1, in US dollars unless agreed otherwise | Optional |
test | 1 marks a test request, which bills no one | While a new partner is tested | On your own tests |
| Field | What it carries | Zurla sends buyers | Zurla expects from you |
|---|---|---|---|
regs.gdpr | 1 when the request falls under the GDPR (Europe’s privacy law) | Carried through unchanged | Whenever it applies |
user.consent | The IAB TCF v2.3 consent string (the TC string) from your consent tool | Carried through unchanged | When regs.gdpr is 1 |
regs.gpp, gpp_sid | The Global Privacy Platform string and the sections it holds, such as US state choices | Carried through unchanged | Whenever your consent tool sets them |
regs.coppa | 1 when the site or app is directed at children (COPPA is the US children’s privacy law) | Carried through, with contextual ads and no advertising ID | Whenever it applies |
device.ext.atts, lmt | Apple’s App Tracking Transparency answer, and the limit ad tracking flag | On iOS app requests, read on the device by the SDK | On iOS app requests |
source.schain | The supply chain: every company along the path, with complete 1 when none is missing | Always complete, with a node for Zurla or, on your RTB platform, for your domain | Expected; Zurla adds its node |
schain.nodes[] | Each node’s domain (asi), its seller ID (sid) and hp 1 when it handles payment | Matched to sellers.json and to ads.txt or app-ads.txt | A seller ID listed in your files |
| Field | What it carries | Zurla expects from bidders | Zurla sends your auction |
|---|---|---|---|
id, seatbid[].seat | The request’s ID, and the buying seat (the account a buyer bids through) | Required | Always |
bid.impid, bid.price | The slot, and the bid in CPM (price per 1,000 ads shown) | Required, at or above bidfloor | Always, at or above your floor |
bid.adm | The ad: banner markup, or a Native 1.2 answer | Required | Always |
bid.adomain, bid.crid | The advertiser’s domain and the creative ID | Required, checked on every bid | Always |
bid.mtype | The format: 1 for a banner, 4 for native | Required; set from the slot for partners on 2.5 | Always |
bid.w, bid.h | The banner’s size | On banners | On banners |
bid.dealid | The private deal the bid is for | On deal bids | On deal bids |
bid.nurl | The win notice, with the price in ${AUCTION_PRICE}: the bid won, not yet that the ad showed | Optional; Zurla sends it when the auction closes | Included |
bid.burl | The billing notice, sent from the server when the ad renders, so both sides count the same event | Optional; Zurla sends it when the ad renders | Included |
bid.lurl | The loss notice, with a reason code in ${AUCTION_LOSS}, such as 102: lost to a higher bid | Optional; Zurla sends it when the auction closes | Included |
| No bid | Nothing to offer for this request | HTTP 204, or nbr with a reason code | HTTP 204; nbr when you ask for it |
| Format checks | A request or bid that does not follow OpenRTB 2.6 | Every bid checked field by field before the auction | HTTP 400 for a request that does not parse, with the reason in your dashboard |
| Field | What it carries | In Zurla’s native requests |
|---|---|---|
ver | The Native version | “1.2” |
context, plcmttype | Where the ad sits: in the content, in a feed, beside it | Set for each slot from your layout |
assets[].title | The headline | Required |
assets[].img type 3 | The main image | Required, in the sizes your layout draws |
assets[].img type 1 | The icon or logo | Optional |
assets[].data type 1 | The advertiser’s name (“sponsored”), shown beside the Ad label | Required: native ads are always labeled as ads |
assets[].data types 2 and 12 | The body text and the button text | Optional |
eventtrackers | Trackers for impressions and viewability, as an image pixel or a script | Impressions (event 1) by image or script |
privacy | 1 when the ad may carry the buyer’s own privacy link | 1 |
| The answer | The click-through link, each asset matched by its id, and the trackers | Every required asset filled; Zurla draws the ad in your fonts, colors and layout |
Illustrative data
schain node.
Partner setup
Nothing to build.
Zurla writes each setup.
On an RTB platform running on Zurla, partners connect over OpenRTB 2.6 on both sides of your auction, under your domain. Zurla writes each partner’s setup, tests it with requests that bill no one, steps it up as the numbers hold and delivers log-level data (one record for every request, bid and win) to your storage. Ask Zurla anything technical, and it answers with the spec.
The code window shows the partner setup Zurla wrote for Corrandel Bidder, approved by your team. Its other tabs show how Zurla maps Kellowan Trading’s OpenRTB 2.5 fields, and one log-level record.
{
"partner": "Corrandel Bidder",
"side": "demand",
"endpoint": "https://eu-west.bid.corrandel.example/rtb",
"openrtb": "2.6",
"regions": ["eu-west"],
"qps_limit": 10000,
"formats": ["banner"],
"channels": ["app"],
"countries": ["DEU", "FRA", "GBR", "ESP", "ITA"],
"tcf_vendor_id": "<IAB vendor ID>",
"test_requests": { "test": 1, "billed": false, "qa": "passed" },
"ramp": { "steps": [0.01, 0.1, 0.5, 1], "now": 0.01 },
"status": "live",
"written_by": "Zurla",
"approved_by": "your team"
}
# Kellowan Trading bids on OpenRTB 2.5; your platform runs 2.6.
# Zurla moves each field to its 2.5 place and back. Illustrative.
# Requests to Kellowan Trading, 2.6 → 2.5
regs.gdpr → regs.ext.gdpr
user.consent → user.ext.consent
user.eids → user.ext.eids
source.schain → source.ext.schain
# Bids from Kellowan Trading, 2.5 → 2.6
bid.mtype ← set from the slot's format
# Test requests that bill no one: passed
{
"request_id": "orx-7f3a9c2e",
"region": "eu-west",
"supply_partner": "20917",
"tagid": "level_banner",
"bidder_tmax": 80,
"platform_ms": 9,
"total_ms": 91,
"bidders": [
{"seat": "seat-d", "ms": 72, "price": 1.62, "outcome": "won"},
{"seat": "seat-f", "ms": 66, "price": 1.48, "loss": 102},
{"seat": "seat-b", "ms": 51, "price": 1.35, "loss": 102},
{"seat": "seat-k", "ms": 43, "price": 1.10, "loss": 102},
{"seat": "seat-e", "ms": 31, "outcome": "no_bid", "testing": true},
{"seat": "seat-p", "ms": 22, "outcome": "no_bid"}
],
"not_asked": 18,
"billed": "at render"
}
Zurla writes it when you connect a partner, and your team approves it in your dashboard · the format is illustrative
a bidder on OpenRTB 2.5 gets each field in its 2.5 place, and its bids come back as 2.6 · illustrative
one record for each request, streamed to your storage in near real time · illustrative
Illustrative data · endpoints and IDs are placeholders
What do our partners need to build to connect?
Nothing new. Supply partners send OpenRTB 2.6 requests to your domain and bidders answer them, as with any exchange. I write each partner’s setup; here’s Corrandel Bidder’s.
- Written for EU West and app banners
- Tested with requests that bill no one
- Live on 1%, stepping up as the numbers hold
Setup writtenYour team approves it
Spec
- Protocol
- OpenRTB 2.6 with Native 1.2 on the supply side, the demand side or both, under your domain; partners on 2.5 mapped field by field
- Formats
- Banner and native (native always labeled as an ad), on websites and in apps
- Regions
- Four, on three continents; each request handled in a region near its partner; capacity added before known peaks
- Speed
- Auctions that finish in under 100 ms, with Zurla’s own time built to stay under 40 ms on 99 of every 100 bid requests, apart from the time bidders take to answer
- Your domain
- bid., bidder., events., notify. and partners. on orrinth.example, pointed at Zurla with a DNS record, with TLS certificates Zurla manages
- Supply chain
- schain with your domain as its node; sellers.json on your domain; direct publishers’ ads.txt and app-ads.txt lines marked DIRECT
- Privacy
- IAB TCF v2.3, GPP and COPPA signals carried through and checked for each bidder
- Data
- Log-level, streamed to your cloud storage or warehouse in near real time
Illustrative data
QPS limit: the most requests a second a partner takes · DNS record: a setting at your domain provider · TLS certificate: the padlock in the address bar · schain: the record in each request of every company that handles it along the path · seller ID: the account number you give each seller · ads.txt and app-ads.txt: public files on a publisher’s website that list who may sell its ad space · DIRECT: the publisher works with you directly · IAB vendor ID: a company’s number in the industry’s list of ad tech vendors · log-level data: one record for every request, bid and win · IAB TCF v2.3: the ad industry’s consent framework for Europe, the UK and Switzerland · GPP: Global Privacy Platform, one string for privacy choices in many places · COPPA: the US children’s online privacy law
Which versions does Zurla support?
OpenRTB 2.6 with Native 1.2, on both sides of the auction. Partners still on OpenRTB 2.5 connect too: Zurla moves each field to its 2.5 place in the requests it sends them, and reads their bids back as 2.6.
Can our own auction send requests to Zurla?
Yes. Publishing groups with an in-house auction send banner and Native 1.2 requests in OpenRTB 2.6 as a POST to Zurla’s endpoint. Zurla answers in under 100 ms, inside the tmax you set, and your auction picks the winner. See Zurla for publishers.
Do apps send OpenRTB requests?
No. Apps use Zurla’s SDK for native, banner, interstitial and rewarded ads, and Zurla runs the mediation. The SDK calls Zurla, and Zurla builds the OpenRTB 2.6 request buyers receive, with the app’s bundle, its placements and a complete supply chain. See Zurla for app developers.
How does Zurla treat tmax?
As a limit to finish well inside. Zurla reads the tmax in each request it takes in and answers inside it, and every buyer it asks gets the same time limit. Zurla’s auctions finish in under 100 ms. See Auctions.
Which privacy signals does Zurla read?
IAB TCF v2.3 (regs.gdpr and user.consent), GPP (regs.gpp and gpp_sid), the COPPA flag and, on iOS, Apple’s App Tracking Transparency answer. They’re carried through unchanged and checked for each bidder. See Consent and privacy.
What must a bid include?
The slot (impid), a price at or above the floor, the ad (adm), the advertiser’s domain (adomain), the creative ID (crid) and the format (mtype). Win, billing and loss notices are optional, and Zurla sends them when you include them. No bid is an HTTP 204.
How does a new partner go live?
Zurla writes the partner’s setup and your team approves it. Zurla then sends test requests (test 1) that bill no one, starts live traffic on a small share and steps it up as the numbers hold. See Zurla for RTB platforms.
We run Prebid. Do we need OpenRTB?
No. Zurla works with Prebid too: as a bidder, setting your floors, or running your whole setup. OpenRTB is the way in for your own auction and for RTB platforms. See Works with Prebid.
Send a request.
Get an answer in under 100 ms.
Book a demo, and we’ll show you Zurla, a frontier model built for advertising, running OpenRTB 2.6 on your setup, from test requests to live traffic.