Blog · Protocol

AdCP vs OpenRTB is an agent task against a bid request, and the mapping is where the fields die.

AdCP vs OpenRTB is two layers. Agents negotiate a media buy. The auction is still a bid request. Nothing in the task response tells you the request is valid for the snapshot the exchange runs.

The task is not the auction

AdCP is a task protocol. A buyer agent calls get_products, create_media_buy, or sync_creatives on a seller agent, over MCP or A2A. None of those messages is a bid request, and none of them clears an impression. OpenRTB is the wire format when that agreement has to be sold programmatically: a deal id on imp.pmp.deals, a placement on imp.video or imp.audio, a path on source.schain. The mapping guide is the handoff. This page is what the handoff drops.

video_placement_types uses video.plcmt names: instream is 1, accompanying_content is 2, interstitial is 3, standalone is 4. It does not map to the deprecated video.placement list. Writing the old field with the new intent loses the constraint. The integer 1 on placement is not the same promise as plcmt 1. That rename failure is the plcmt post.

Products and packages become deals. If the deal id on the media buy is not the Deal.id on the request, the auction never applies the terms and the impression prices in the open market. adagents.json says which agents may represent the publisher. It does not replace source.schain. A task that succeeded and a chain that does not list the seller are both possible on the same buy.

The request can be wrong after the agent said yes

An agent stack built in 2.6 language can emit a field the exchange's pinned snapshot does not have yet. That is openrtb.field.not_yet_available. No AdCP-level test sees it. Privacy is worse: a media buy carries no consent string. regs.gdpr, user.consent, regs.gpp, and gpp_sid come from the seller's ad stack. A half-filled pair is unusable. The negotiation did not set them.

Anything narrowed in the task, format, duration, seat, geo, suitability, is enforced only if the impression repeats it. A constraint that stayed in the agent transcript is not a bid request field. Generated JSON adds the usual type misses: at as a string, one object where imp must be an array, a boolean where the spec wants 0 or 1, a 2.6 field inside a body an exchange will read as 2.5.

Validate the emitted request with the snapshot and dialect the exchange uses. The tester and rtblint validate see the bid stream. They do not see the agent transcript. A green task log is not a green request.

Audio and seats fall off the same way video does

AdCP audio distribution types are meant to land on the OpenRTB audio feed field, the same kind of name-to-integer handoff as video.plcmt. Leaving the agreement in the task transcript and sending an audio object with no feed is a legal request that does not carry the constraint. The bidder prices a generic audio impression. The buy was more specific than that.

Seat and geo limits belong on the impression or the deal, wseat and the geo fields the exchange actually reads. A suitability line in the agent message does not become bcat. If you need a blocked category, write bcat on the request and set cattax when the codes are not taxonomy 1.0. Otherwise the open auction ignores a block that existed only in the chat.

Run the generated JSON through RTBlint at the snapshot the exchange pinned, with the dialect the serializer emits. openrtb.field.not_yet_available is the finding for a 2.6 field on an older pin. A string at, a boolean secure, and a placement value copied from an AdCP name are the findings for a model that matched the shape and missed the types. Fix the emitter. Do not hand-edit a sample and call the agent done.

What to check after the media buy

  • Map video_placement_types to video.plcmt, not placement.
  • Put the agreed deal id on imp.pmp.deals. A different id is the open auction.
  • Do not treat adagents.json as a schain.
  • Emit consent on the request. The media buy did not include it.
  • Pin the exchange snapshot. A 2.6 field on an older pin is not yet available.
  • Reject string at, a non-array imp, and bool flags in Spec JSON.

A yes from the agent is not a filled impression

create_media_buy agreeing a price does not emit a bid, a win notice, or a billing notice. Those still happen on the OpenRTB path after the deal id is on the request and a bidder responds. If the id never lands, the open auction runs and the agent transcript still says the buy exists. Reconcile the deal id in the request with the id in the task before you reconcile spend.

Placement names are plcmt integers, not the deprecated placement list. instream is 1 only in the new list, and that 1 means sound-on. Mapping the AdCP name instream onto video.placement 1 reintroduces the old definition. Write plcmt. Then validate the request the exchange will parse, at that exchange snapshot, not the JSON the agent displayed.

Further reading