Blog · Agentic

ARTF lets agents rewrite the bid request in flight. Nothing in it checks the result.

Most agentic advertising happens at planning time, which is why most of the debate about it is a debate about workflow. The Agentic RTB Framework is the exception. It puts agents inside the auction path, running as containers next to the exchange, and it gives them a typed vocabulary for changing a bid request or bid response while the auction is happening. Read the protobuf and the implication is immediate: the payload that reaches a bidder is not necessarily the payload the publisher emitted, and nothing in the framework says the rewritten version is still valid OpenRTB.

What ARTF actually specifies

ARTF v1.0 went out for public comment in November 2025 and sits under the AAMP umbrella alongside the buyer and seller agent SDKs that reached 2.0 in June 2026. The transport is gRPC with Protocol Buffers, and the execution model is containerized: a host, an exchange or a DSP, runs third-party agent services co-located in its own infrastructure rather than calling them over the public internet. The pitch is latency, with claims of large reductions in round-trip time compared with server-to-server enrichment hops.

The data model is worth reading literally, because it is small. A host sends an RTBRequest carrying a lifecycle stage, an id, a tmax that bounds the mutation round trip including latency, the OpenRTB bid_request or bid_response itself, an originator (publisher, SSP, exchange, or DSP), and the list of applicable_intents the agent is allowed to answer with. The agent returns an RTBResponse containing zero or more Mutation messages plus metadata naming its API version and model version.

A mutation is four things: an intent, an op (add, remove, or replace), a path, and a typed payload chosen by intent. The payload types import OpenRTB directly: the metrics payload is a list of OpenRTB Metric objects, the content data payload is a list of OpenRTB Data objects. This is not a parallel object model. It is a patch protocol for the bid stream you already run.

The eight intents, and what each one touches

ARTF v1.0 defines eight intents. Mapping them onto the OpenRTB fields they land on makes the validation surface obvious:

IntentLands onWhat breaks if it lands wrong
ACTIVATE_SEGMENTSuser.data[] / content.data[] segmentsMalformed Data or Segment objects; provider identity lost
ACTIVATE_DEALSimp.pmp.deals[]A deal id the exchange does not know, or a deal added without a floor or auction type
SUPPRESS_DEALSimp.pmp.deals[] (removal)A bidder that already read the request bids into a deal that no longer exists: openrtb.bid.dealid_unknown
ADJUST_DEAL_FLOORdeals[].bidfloorNegative or implausible floors, currency mismatch against bidfloorcur
ADJUST_DEAL_MARGINCommercial layer, expressed as CPM or percentNo OpenRTB field carries margin, so this is the one intent whose effect is not visible in the payload at all
BID_SHADEbid.price on the responseA price altered after the bidder set it, in a currency the request may not allow: openrtb.response.cur_not_allowed
ADD_METRICSimp.metric[]Metric objects missing type or value, or vendor-less third-party metrics
ADD_CIDScontent.data[].cids / user.data[].cidscids arrived in OpenRTB 2.6-202505; adding it to a request pinned to an earlier snapshot produces a field that does not exist in that version

That last row is the cleanest example of the whole problem. ADD_CIDS is a perfectly legal ARTF intent. Whether the result is a legal bid request depends entirely on which OpenRTB snapshot the exchange and its bidders are running, which is information the mutating agent does not necessarily have. RTBlint already reports this class as openrtb.field.not_yet_available, and the history of dated snapshots is in how OpenRTB ships now.

Three structural gaps

None of these are criticisms of the design so much as consequences of it, and they are the reason a conformance step belongs in the loop.

  • path is a string. The framework describes it as the semantic business domain where the operation applies. A free-form path plus add, remove, and replace is a general-purpose patch API. Two agents can disagree about what a path means, and a path can point somewhere that does not exist in this version of the spec. Only validating the mutated document catches that.
  • Composition is undefined territory. A host may run several agents. Two mutations can be individually reasonable and jointly contradictory: one activates a deal, another suppresses it; one adds segments the other removes. The result is a single payload that has to satisfy the spec after every patch has landed.
  • Provenance stops at metadata. Metadata carries an API version and a model version, which is genuinely useful for attribution, but the mutation itself is not signed and the pre-mutation payload is not retained anywhere in the protocol. If a bidder later asks why a request claimed a segment, the answer has to come from the host's own logging discipline.

Validation stops being an edge check

The traditional place to validate a bid request is once, at the boundary where you emit it. ARTF breaks that assumption, because the payload changes after your boundary. If a mutation stage sits in your path, the useful model is a checkpoint after each stage that can rewrite the document:

  1. Publisher or SSP emit. Validate as normal, against the snapshot you target. This is the baseline every downstream comparison depends on.
  2. After each mutating stage. Re-validate the document, not the patch. A patch that looks correct can produce a document that is not, and the whole point of the framework is that the agent is not the party accountable for the payload.
  3. On the response side. BID_SHADE operates at LIFECYCLE_DSP_BID_RESPONSE, so cross-validate the mutated response against the request that produced it: id, impid, seat, currency, deal, media type.
  4. In CI, per intent. Fixture per intent your agents can emit, asserted against the exact snapshot each partner runs, gated on rule ids rather than on exit codes.

The economics of skipping this are the same as for any silent bidstream defect: unknown fields are ignored by design, so a bad mutation does not error, it just quietly removes bidders. That mechanism is the subject of bid request quality as a revenue line and of what happens on a version mismatch.

What we would like to see in 2.0

ARTF is post-comment with a 2.0 already discussed, so the boundaries are still being drawn. Three additions would make the framework materially safer without changing its shape:

  • A declared OpenRTB version on the envelope. An agent that knows the target snapshot can refuse to emit a field that does not exist in it.
  • A normative path grammar. If the path is going to address OpenRTB structures, saying so precisely turns a class of integration bugs into a schema error.
  • A conformance profile per intent. Which fields an intent is permitted to touch, so hosts can enforce scope rather than trusting it. This is the same principle the framework already applies with applicable_intents, taken one level deeper.

The reference implementation is Rust with the protobuf definitions in the repository, and it is worth reading if you are integrating: the demo evaluator is where the intent semantics become concrete rather than prose.

Practical takeaway

If you host agents in the auction path, validate the document after every stage that can change it, and keep the pre-mutation payload long enough to answer questions about it. If you build agents, validate what your mutation produces against the snapshot your host actually runs, not against the newest spec you read. Both are one call: paste a payload into the tester, run it from the CLI in CI, or give the agent the MCP server as a tool so it can check itself before it answers. Field-level context for the standards around this is in IAB Tech Lab's agentic standards and the AdCP to OpenRTB mapping.

Sources