Blog · Protocol

A DSP partner sample bid request is not the request production will send.

A solutions engineer at a DSP can see the partner sample and the specification. They do not own the exchange builder, and they do not own the publisher page. The file attached to the integration review is usually the sandbox. The bidder will see the request the exchange emits on a Tuesday afternoon.

A clean sample proves the partner can build one legal request

The sample is complete on purpose. imp is an array. video.plcmt is set. regs.gdpr and user.consent sit on the core objects. source.schain is present, complete is 1, and there is one of site or app. imp.secure is the integer 1. imp.bidfloorcur is an ISO-4217 code. at is an integer. Run that file through the tester or rtblint validate on the 2.6 snapshot the partner named, in Spec JSON, and it can come back clean.

Clean means the sample matches that snapshot and dialect. It does not mean the production path emits it. Ask for a second artifact before the integration brief promises a bid rate: one redacted request from the live exchange, or from the queue that will feed the bidder, with test at 0. Paste both, or validate both locally. The delta is the evaluation. A solutions engineer who signs the sample has signed a payload the bidder will not parse.

Prefer the CLI when the capture still has device.ifa, an IP, or a consent string. The tester runs in the browser. Payloads you submit there may be stored with those identifiers stripped. The CLI does not send the file. Strip the token-like values anyway before the file lands in a ticket.

The live request keeps the 2.5 paths under a 2.6 version

Production builders are older than the sample. The version string says 2.6 because someone updated a constant. The objects were not updated. GDPR is still regs.ext.gdpr. The TCF string is still user.ext.consent. Video still carries placement and not plcmt, and the two enums do not map one to one, so a later mechanical copy of the integer will classify the impression as a different subtype. Supply chain is still source.ext.schain, or it is duplicated at both paths with different nodes. A 2.6 reader does not treat the extension path as the core field. RTBlint reports the move as openrtb.field.moved when the snapshot is 2.6.

The merge bug travels with that drift. A stored request has site. The live impression is an app. Both objects land on the wire. The spec does not allow more than one of site, app, and dooh. Many bidders drop the request. The sample had deleted one of them. The builder has not.

regs.gpp and regs.gpp_sid exist from snapshot 2.6-202211. A sample validated as latest 2.6 can include them. A bidder pinned to an older snapshot, or a partner who only filled the extension GDPR flag, will not. Write down which snapshot each side runs. A claim of 2.6 without a dated tag is not a snapshot.

What the sample fills and the live request drops

FieldSampleLive request
regs.gdprinteger on regsregs.ext.gdpr only
user.consentTCF string on useruser.ext.consent
video.plcmtAdCOM plcmt subtypedeprecated placement
source.schaincore objectsource.ext.schain, or both
inventoryone of site, app, doohsite and app together
imp.secure1 in Spec JSONtrue, or omitted
imp.bidfloorcurexplicit ISO-4217absent, so USD
test01 left on from the sandbox

Read the table as two files, not as a score. Each row is a reason the bidder logic you wrote against the sample will miss. A 2.6 privacy module that only reads regs.gdpr will treat the live request as unknown. A video classifier that only reads plcmt will treat the live impression as unclassified. A floor of 120 with no currency is 120 US dollars, because bidfloorcur defaults to USD and does not inherit cur. Deal.bidfloorcur does not inherit the impression currency either.

Omitted imp.secure means the secure state is unknown and non-secure HTTP support can be assumed. true is a bool. In Spec JSON that is a type error. In protobuf JSON, the integer 1 is the type error, and it fails the unmarshal of the whole message, not just the flag. Ask which dialect the pipe uses before you call either file valid. The tester dialect control and --dialect on the CLI are that question.

Auction type, the test flag, and whose block list arrived

at defaults to 2, second price plus, when it is omitted. The sample that sets at to 1 is a first-price auction. The live request that omits the field is not. A bidder that shades or that expects pay-what-you-bid will be wrong on every impression until someone notices the omission. Values of 500 or greater are exchange-specific. Do not treat an unfamiliar integer as first price.

test defaults to 0. test of 1 is non-billable. A sandbox request left at 1, then copied into the production endpoint, is an auction that must not become spend even when your bidder returns a price and the exchange fires notices. Store the flag against BidRequest.id. The notice side of that mistake is covered in nurl vs burl vs lurl.

bcat, badv, and bapp are on the request that ran, not on a block list the DSP keeps in a UI. Only one of acat or bcat should be present. cattax defaults to taxonomy 1.0, so a Content Taxonomy 2 id with cattax omitted is a different code than the bidder thinks. pmp.private_auction of 1 means only the listed deals. The flag is an integer in Spec JSON. A sample deal with at of 3 means the deal floor is the fixed price, in that deal currency. The sample deal and the live deal are often different ids.

Do not join the sample to a Prebid capture on imp.id

imp.id is unique inside one request. Exchanges often number impressions 1, 2, 3. That integer will not match a Prebid capture, a TAM request, or an Open Bidding request for what a human calls the same slot. source.tid is shared only when each path sets the same string. imp.tagid is the placement only when the seller sets it and keeps it stable. A solutions engineer who reconciles three debug files on imp.id will conclude the inventory disappeared.

tmax on the sample is whatever the partner typed. On the live path it is the remaining budget, and a downstream hop may only decrease it. A bidder that spends the sample tmax thinking will time out when the live value is what survived the exchange. source.fd of 0 means the exchange receiving the request makes the final sale. 1 means an upstream party still will. Read it on the live file. The sample is often 0 because the drawing in the kickoff slide showed one hop.

If the partner also sends a bid response sample, validate it with --type response --request against the live request, not against the sandbox request. bid.impid has to name an impression on the request you pair. A response that only matches the sample imp.id is a demo. Notice URLs, the price macro, and loss codes are not proved by a request pass.

What a solutions engineer at a DSP can decide before signature

  • Validate the sample and a redacted production request as two files. Write down which fields exist only in the sample.
  • Name the snapshot, the dialect, and the profile. Spec JSON and protobuf JSON do not accept each other flags. Prebid Server, Google Authorized Buyers, Xandr, and Magnite add required extension fields the spec does not.
  • Require one of site, app, or dooh on the production body. Require regs.gdpr and user.consent on the core objects when the partner claims 2.6.
  • Require plcmt when the impression is video, and require bidfloorcur wherever the floor is not USD, including each deal.
  • Require test of 0 on the production path. A sandbox flag copied forward is non-billable traffic.
  • Do not forecast fill from a sample that has plcmt, a schain, and a single inventory object the live request does not have.
  • Ask the partner to run rtblint validate in the builder repository, on a fixture generated from the serializer, with exit 1 failing the pull request. Installing the binary at the DSP does not change their deploy.

RTBlint is not affiliated with IAB Tech Lab or with the DSP. A pass means the artifact matches the published snapshot you selected. It does not mean the seat will bid, and it does not mean the publisher consented to the identifier in user.eids. Those are the next questions. They are askable once the two bodies have been compared.

Further reading