← Back to blog

Agents make the deal: what a seller agent does in OpenProposal

Agents make the deal: what a seller agent does in OpenProposal
November 6, 2026by Filip Sobala, Dariusz Rozmus
Agentic advertisingOpenProposalAAMPSeller agentMCP

On 3 November, at IAB Tech Lab's Agentic Bootcamp in London, Bedrock Platform CTO Damian Naglak ran a live campaign on stage. Bedrock's buyer agent read a brief, compared offers from two publishers, asked one of them for more, and agreed three private auction deals in a few minutes. Bedrock's bidder then took over and decided on each impression.

The two publishers were seller agents, and we built them. This post is the seller's side of that demo: what OpenProposal is, what a seller agent has to do with it, and what we learned building two of them.

OpenProposal is a shelf a buyer agent can read

A buyer agent may screen fifty sellers for one brief. It cannot read fifty rate cards, PDFs and email threads. OpenProposal gives every seller the same object to describe what it sells, so the agent can compare offers at machine speed and carry one of them all the way to binding terms.

The object has two levels:

  • Proposal: the pitch. Who is selling, how long the offer holds, a description and best_for written for a model to read, and the negotiation history.
  • Line items: the things you can actually buy, each in exactly one channel (web display, CTV, audio). Every line item is self-contained: it inherits nothing from the proposal or from its siblings, so a buyer can take one line item and hand it to a downstream system as it is.
The shape of an OpenProposal: one proposal with identity, status, offer window, description and negotiation history, and two self-contained line items, web display and connected TV, each carrying its own formats, pricing, commitment bounds and transaction mechanism.

A proposal is either standard (the seller publishes it for anyone) or custom (built in answer to a buyer's brief). Each line item says which execution route it supports in transaction_mechanism: direct IO, programmatic guaranteed, preferred deal, private auction or open auction. OpenProposal does not replace the execution standards; a deal still lands in OpenDirect, the Deals API or OpenRTB.

Every field says who may change it

This is the idea that makes OpenProposal work for agents, and the one a seller should understand first. Every field carries a marker that says who can change it and how:

MarkerWho changes itExample
seller-setOnly the sellergross_rate, description
selectableThe buyer picks from a menu the seller declared, each option with its priceaudiences, exclusivity, deal type
settableThe buyer sets a value inside the seller's boundsthe commitment: budget and flight dates
requestableThe buyer may ask for more than offered; the seller must agreecommitted_metrics, such as viewability
derivedNobody; it is computedversion, agreed_rate, status

The consequence is big. Because the seller publishes the menu and the price of every option up front, the buyer agent can compose a deal without asking the seller anything: pick the audience, add exclusivity, set the budget, and the price follows from the offer. The spec calls this constraint satisfaction rather than negotiation. Only a requestable ask, something outside the menu, needs the seller to answer.

For a publisher this moves the work. You no longer answer every request; you decide once what is on the menu, what each option costs, and how far you will go when someone asks for more.

From brief to deal in five calls

The spec defines the object, not the API around it. Our seller agents expose it as five tools over MCP, the protocol AI apps use to call tools:

From brief to deal in five calls: get_proposals returns summary offers, get_proposal the full offer, request_change an accepted, countered or declined answer, submit_commitment an agreed deal with a deal_id, and get_proposal_status the final state.
  1. get_proposals: the buyer sends its brief and gets a summary of every offer, enough to screen many sellers quickly.
  2. get_proposal: the full offer, every line item with all its options and prices.
  3. request_change: the buyer asks for something outside the menu. The seller answers accepted, countered or declined. A counter comes back as version 2 of the offer, with the new price and an entry in negotiation_history.
  4. submit_commitment: the buyer commits budget and flight dates to one line item. The seller checks everything, prices it and returns agreed with a deal_id.
  5. get_proposal_status: the final state, for the buyer's records.

We never told Bedrock's agent this order. Each tool description says what it returns and what to call next, and the agent found the path from the brief alone. In a protocol where the client is a model, tool descriptions are product copy: they decide whether the flow works without hints.

What happened on stage

The brief was for Overtake, a fictional UK car brand launching a flying car: 300,000 USD over 10 to 24 November, split across connected TV, news web and a car-enthusiast site. On the car site it asked for an affluent tech audience and no other car brands in launch week. On news web it asked for at least 70% viewability.

Two seller agents answered, both running on one codebase and differing only in configuration:

  • Fastlane, a UK car magazine: web display with priced audiences, launch-week exclusivity as a selectable option, and a list of buyer agents it is willing to talk to.
  • The Northlight, a national news site: web display with a 60% viewability ceiling, and connected TV capped per household.

The buyer picked the audience and exclusivity from Fastlane's menu without a round trip. It asked The Northlight for 70% viewability, above the declared ceiling, so that was a requestable ask: The Northlight countered with version 2 at a higher CPM, and the buyer accepted. Then it committed to three line items and got three deal ids.

The Northlight's news web display: 10 USD CPM published in version 1 up to its 60% viewability ceiling, 12 USD CPM in version 2 when the buyer asked for 70%, and declined above 70%.
The Overtake brief of 300,000 USD as three private auction deals: 175,000 USD of connected TV and 110,000 USD of news web display with The Northlight, and 15,000 USD on Fastlane's car site with the audience and launch-week exclusivity.
The live stage screen: Fastlane and The Northlight side by side, every call the buyer agent made with the seller's answer, from published offers through the counter to three agreed deals with their deal ids.

On stage, an agreed commitment also switched the Overtake ads on in each publisher's page, so the audience could see the deal land.

The seller keeps control of its price

Selling through an agent raises an obvious worry: will a model talk my price down? We built the sellers so it cannot.

What the buyer sees and what stays with the seller: the offer carries gross_rate, the option menu with prices, commitment bounds, committed metrics and, after a commitment, the deal_id; the floor, seller_rate, change rules and allowed agents stay on the server.
  • The floor never leaves the server. The spec offers an optional pricing[].floor, the lowest rate the seller will consider, so a buyer could check a counter without a round trip. We chose not to send it: it tells the buyer exactly how far down to push. Our floor lives in the seller's configuration, and our tests check that it appears in no response, error messages included.
  • The buyer never sends a price. request_change and submit_commitment take a selection, a budget, dates and the change asked for. The seller always works the price out itself, from the offer it published. Asking for a lower price is not something the API can express.
  • The seller decides how far it bends. Each seller has rules for what it will raise, how far, and for what extra CPM. The Northlight raises viewability up to 70%; Fastlane declines every change. Both are valid answers in OpenProposal.
  • Same question, same answer. No randomness and no clock in the pricing logic. The same commitment always gives the same deal_id, so a buyer that retries with the same idempotency key gets the original deal, not a second one.
  • The seller chooses who it talks to. Fastlane only answers buyer agents on its list. The spec models this with eligible_bidders and required_credentials; for the demo a header was enough.

Pricing and validation sit in one module that both request_change and submit_commitment call, so a counter offer and the final commitment can never disagree on price.

Agents make the deal, bidders buy the impressions

The buyer chose PRIVATE_AUCTION for all three deals, and that choice is the point of the demo. An agent is good at the slow part: reading offers, comparing them with a brief, asking for more and agreeing terms. It is the wrong tool for deciding on each impression in milliseconds. A bidder is built for that.

Two jobs, two clocks: agents make the deal once per campaign in minutes; bidders decide on every impression in milliseconds, skipping people who have already seen the ad, shifting budget and raising bids without renegotiating.

A deal is agreed once, but a campaign keeps moving. The list of people who've already seen your ad grows every minute. Deciding per impression lets buyers follow that, shift budget or raise a bid, without going back to the negotiating table.

— Damian Naglak, CTO, Bedrock Platform

In a private auction, the agreed_rate from the seller agent is the floor the buyer bids from, not a fixed price. The spec maps a private auction to the Deals API and an OpenRTB 2.6 deal, so the deal_id the seller agent mints is what the SSP and the bidder use from there on.

Where the draft was silent, we decided

A draft leaves gaps, and a working seller has to fill each one. A few we hit:

  • There is no deal_id field. The spec says a deal id is issued at commitment time but not where it goes. We return it at the top level of the commitment result and derive it from a hash of the commitment, which makes it idempotent without a database.
  • The list of line items has no key name. The spec draws Proposal → Line Items[]; we called it line_items.
  • Selectable fields need a price for every option. We read the spec as: every option outside included[] must carry a price delta, otherwise the buyer cannot compose without a round trip. Our schema rejects offers that break this.
  • Some terms have no shape yet. Exclusivity is selectable, but the spec shows no exclusivity term; we used { id, name }.

Some of these are open questions in the spec itself, such as whether per-field mutability stays in 3.0 at all. We will cover them, and what a production seller agent needs beyond a demo, in the next post.

Building a seller agent?

We build seller agents for publishers on AAMP and AdCP: an agent-readable offer, pricing rules that hold under pressure, and the path from an agreed deal to your ad server. If you want your inventory in front of buyer agents, talk to us.

Seller agents at Appliscale
Share: