/find

How to make your inventory agent-ready for AdCP: a publisher’s guide

Sharad Yadav
Founder, BidCliq

A buyer agent can only buy what a sales agent can describe in structured terms. Making your inventory agent-ready for AdCP comes down to four things: a product catalogue with machine-readable formats, pricing and reporting terms; an adagents.json file that says which agent may sell it; a sales agent wired to your ad server; and rules for which buys a person must approve. In Agents aren’t coming for the auction we argued that the first job for publishers is getting direct-sold inventory into a shape an agent can read, and AAMP and AdCP compared the two standards. This guide is the practical follow-up and covers each of the four, against AdCP 3.2 (latest patch v3.2.7, released 24 October 2026).

Which version of AdCP should you build to?

Build your data to 3.2, but expect buyers on 3.1 for a while.

  • AdCP 3.2 reached general availability on 30 September 2026. The first stable artifact is 3.2.1, and peers negotiate the wire value "3.2", never a patch number. A 3.3 beta was tagged on 22 October.
  • 3.2 added a “compact lifecycle” of task-specific tools: list_products, request_proposals, refine_proposals, decline_proposals, buy_products, accept_proposal and control_media_buy. The older get_products, create_media_buy and update_media_buy are now compatibility facades, which will not be removed in 3.x.
  • The open-source Prebid Sales Agent targets AdCP 3.1.1, pinned through the adcp==6.6.0 Python SDK. If you deploy it today, buyers will talk to you in 3.1 task names.

What does a buyer agent actually ask for?

A buy is a sequence of tool calls over MCP or A2A:

Step3.1 task3.2 compact taskWhat it needs from you
Who are you?get_adcp_capabilitiessameDomains, channels, countries, versions
What can I buy?get_productslist_products, request_proposalsProducts, pricing, availability
What creatives fit?list_creative_formatsformat_options on each productCreative specs per product
Book itcreate_media_buybuy_products, accept_proposalLine items, approval rules
Send creativessync_creativessameCreative review and trafficking
Change itupdate_media_buycontrol_media_buyPause, budget and flight edits
How is it going?get_media_buys, get_media_buy_deliverysameAd server reporting

Two task names from older guides are gone or going. list_authorized_properties was removed in v3: the publisher domains a seller represents now sit in the portfolio section of get_adcp_capabilities. list_creative_formats is deprecated for new discovery in 3.2, because formats now live on each product.

Buys are asynchronous: a buy can return submitted and wait minutes or days for a person to approve it. That is where your approval rules plug in.

How should you model products?

A product is a line on your rate card, not an ad unit. “Run-of-site display, India, guaranteed” is a product. /1234/home/atf_970x250 is a delivery detail the sales agent maps to behind the scenes.

Start with what you already sell on IOs: takeovers, section roadblocks, run-of-site display, video pre-roll. Each becomes one product. The 3.2 product schema requires product_id, name, description, publisher_properties, delivery_type, pricing_options and reporting_capabilities, and 3.2 authoring also requires format_options. This minimal product validates against the 3.2.6 schema (prices are illustrative):

{
  "product_id": "ros_display_in_guaranteed",
  "name": "Run-of-site display, India, guaranteed",
  "description": "Guaranteed display impressions on article and section pages of news.example.com, India traffic only. Excludes the homepage and live blogs.",
  "publisher_properties": [
    { "publisher_domain": "news.example.com", "selection_type": "all" }
  ],
  "channels": ["display"],
  "format_options": [
    {
      "format_option_id": "ros_image",
      "format_kind": "image",
      "params": {
        "sizes": [
          { "width": 300, "height": 250 },
          { "width": 728, "height": 90 },
          { "width": 320, "height": 50 }
        ]
      }
    }
  ],
  "delivery_type": "guaranteed",
  "exclusivity": "none",
  "pricing_options": [
    {
      "pricing_option_id": "cpm_inr_fixed",
      "pricing_model": "cpm",
      "currency": "INR",
      "fixed_price": 180,
      "min_spend_per_package": 100000
    }
  ],
  "delivery_measurement": {
    "vendors": [{ "domain": "googleadmanager.com" }]
  },
  "reporting_capabilities": {
    "available_reporting_frequencies": ["daily"],
    "expected_delay_minutes": 240,
    "timezone": "Asia/Kolkata",
    "supports_webhooks": false,
    "available_metrics": ["impressions", "spend", "clicks"],
    "date_range_support": "date_range"
  }
}

What matters in each field:

  • description is read by a language model matching you against a brief. Say what the inventory is, who sees it and what is excluded.
  • delivery_type is guaranteed or non_guaranteed. exclusivity is none, category or exclusive; use exclusive for takeovers.
  • pricing_options carry the deal type. fixed_price with guaranteed delivery is programmatic guaranteed; fixed_price on a non-guaranteed product is a preferred deal; floor_price, optionally with price_guidance percentiles, is a PMP-style auction. Use min_spend_per_package for your minimums. A different currency or price needs its own pricing_option_id, and currencies are ISO 4217 codes.
  • You don’t have to publish a rate card. The pricing docs allow products with little or no public pricing; the seller quotes in a proposal against a brief, or declines.
  • reporting_capabilities sets expectations: frequency, data delay, timezone and metrics. In 3.2, delivery dates are calendar dates in the product’s reporting timezone, so use the timezone your ad server reports in.
  • channels is optional in 3.x, but the spec says sellers SHOULD declare it, and a 4.0 proposal would make it required. Declare it now.

Don’t offer targeting your ad server can’t execute. If your line items can’t target pin codes, don’t describe a product as if they can.

How do you declare creative formats?

Formats now hang off each product as format_options. Each entry names one of AdCP’s 15 canonical formats as its format_kind. For a display slot that is image, html5, display_tag or native_in_feed; for pre-roll, video_vast or video_hosted. Size goes in params in exactly one mode: fixed width and height, a sizes list, or responsive min and max ranges.

Put your real creative spec into params, not into a PDF. The spec’s own display example uses max_file_size_kb and image_formats for images; max_initial_load_kb, max_polite_load_kb and backup_image_required for HTML5; and supported_tag_types for third-party tags. A buyer agent can check its creative against these before calling sync_creatives, which saves both sides a rejection round trip.

If you want one publisher-wide format list, adagents.json can carry a formats[] array, and buyer agents treat it as your authoritative declaration.

What is adagents.json and what goes in it?

adagents.json is the agentic counterpart of ads.txt. You host it at https://yourdomain/.well-known/adagents.json, and it lists your properties and the sales agents allowed to sell them. Unlike ads.txt, it can scope authorisation by property, placement, country and date, and it labels each path with a delegation_type: direct, delegated or ad_network.

A minimal file for one site and one agent, which also validates against the 3.2.6 schema:

{
  "$schema": "https://adcontextprotocol.org/schemas/3.2.6/adagents.json",
  "contact": {
    "name": "Example News Ad Operations",
    "email": "adops@news.example.com",
    "domain": "news.example.com"
  },
  "properties": [
    {
      "property_id": "news_web",
      "property_type": "website",
      "name": "Example News",
      "identifiers": [{ "type": "domain", "value": "news.example.com" }]
    }
  ],
  "authorized_agents": [
    {
      "url": "https://sales.news.example.com/mcp",
      "authorized_for": "Direct-sold display and video",
      "authorization_type": "property_ids",
      "property_ids": ["news_web"],
      "delegation_type": "direct",
      "exclusive": false
    }
  ],
  "last_updated": "2026-10-27T00:00:00Z"
}

Points that trip people up:

  • If your domain redirects to www, the file must return a 200 at the final URL. Validators follow at most three HTTPS redirects, and only within your registrable domain.
  • contact.seller_id can carry your sellers.json seller ID, which ties the agentic and programmatic records together.
  • The sellers.json side of the handshake is the operator’s brand.json, whose relationship should match your delegation_type. If a vendor runs your agent, check that they publish it.
  • Keep ads.txt. Your programmatic demand still depends on it.

Check the file with the AdAgents.json Builder at agenticadvertising.org/adagents/builder. It fetches the file, validates the schema and checks that agent endpoints respond.

How does a sales agent connect to Google Ad Manager?

The main open-source option is the Prebid Sales Agent (github.com/prebid/salesagent). It moved from the AdCP community to Prebid.org on 29 January 2026; Prebid maintains the code and AgenticAdvertising.org governs the spec. Key facts:

  • It is Apache 2.0, Python 3.12+ and PostgreSQL. The latest tagged release is v2.0.0 (1 July 2026), which included breaking changes. The README calls it alpha and tells you to pin a version.
  • It serves MCP at /mcp/ and A2A at /a2a, plus an admin UI. It needs Google OAuth credentials for the admin UI and a Gemini API key for AI product discovery.
  • Its ad server adapters are Google Ad Manager (the most developed), Broadstreet, Kevel, Triton Digital and a zero-spend mock.

On GAM, each product maps to a line item template, stored as implementation_config. You choose ad units or placements in an inventory picker, and the adapter creates line items when a buy lands. Review these defaults:

  • Line item type follows pricing. Flat rate becomes SPONSORSHIP billed as CPD; vCPM becomes STANDARD, the only type on which GAM supports vCPM; other guaranteed buys become STANDARD; everything else becomes PRICE_PRIORITY.
  • Priority defaults to 6 for guaranteed and 10 for non-guaranteed.
  • Approval is set per product with non_guaranteed_automation: automatic, confirmation_required or manual. The defaults are manual for guaranteed and confirmation_required for non-guaranteed.
  • Inventory targeting must be set. Leave it empty and the adapter logs a warning and falls back to the network root ad unit.

Use a GAM service account in production; the docs position OAuth refresh tokens for development. Start on the mock adapter: a buy whose name contains [REJECT:reason], [APPROVE] or [ASK:field] follows that path, so you can test approvals without spending anything.

The README says plainly that this is one of several AdCP sales agent implementations, not the canonical one. Whichever you choose, your catalogue and adagents.json work carries over.

Checklist: getting agent-ready

  1. Pick your version. Note which AdCP release your sales agent implements, and whether buyers can reach you on 3.1, 3.2 or both.
  2. List what you sell today. Pull last year’s IOs and turn the recurring line items into a short product list.
  3. Clean up GAM. Each product needs a defined set of ad units or placements, key-values that mean one thing, and a line item template your traffickers would sign off.
  4. Write the products. Fill the required fields, declare channels, and decide per product: fixed price, floor, or quote on brief.
  5. Put creative specs in format_options. Sizes, file weights, HTML5 rules, VAST support.
  6. Set approval rules. Start with manual or confirmation_required everywhere, and relax them product by product.
  7. Deploy on the mock adapter, then GAM. Service account, pinned release, your own domain.
  8. Publish adagents.json. Validate it, and confirm the www redirect ends in a 200.
  9. Test as a buyer. The Prebid README uses the AdCP CLI for this: uvx adcp <agent-url>/mcp/ --auth <token> get_products '{"brief":"video"}'. Read your products the way an agent will.
  10. Reconcile reporting. Compare get_media_buy_delivery with the GAM report for the same buy, timezone included, before real money flows.

We’re building an AdCP sales agent at BidCliq. Whichever software you pick, expect most of the effort to sit in steps 2 to 4: deciding what you sell, and making your ad server match it.

Frequently asked questions

Do I need to publish my rate card to sell through AdCP?

No. AdCP's pricing documentation lets sellers list products with little or no public pricing and return a priced proposal in response to a buyer's brief, or decline to propose at all.

Does adagents.json replace ads.txt?

No. adagents.json authorises AI sales agents for agentic buys, while ads.txt still governs programmatic supply paths. Keep both, and put your sellers.json seller ID in the adagents.json contact block.

Which ad servers does the Prebid Sales Agent support?

Google Ad Manager is the most developed adapter. There are also adapters for Broadstreet, Kevel and Triton Digital, plus a zero-spend mock adapter for testing. The project describes itself as alpha and targets AdCP 3.1.1.

Is list_authorized_properties still part of AdCP?

No. It was removed in AdCP v3. The publisher domains a seller represents now appear in the portfolio section of get_adcp_capabilities, and per-property authorisation lives in each publisher's adagents.json file.

Can an AI agent book a guaranteed campaign without a human signing off?

Only if you allow it. AdCP buys are asynchronous and can wait for human approval, and the Prebid Sales Agent defaults guaranteed products to manual approval and non-guaranteed products to confirmation_required.

Sharad Yadav

About the author

Founder, BidCliq

Sharad Yadav is the founder of BidCliq, a publisher-first ad monetization platform that helps publishers and ad ops teams run header bidding, Prebid and programmatic across display, video, app and CTV. Before BidCliq, he led AdTech and product at GeeksforGeeks, where he built an in-house ads product that doubled programmatic revenue within nine months and an anti-adblock solution that lifted ad yield by 10%. He is a founding member of AdCP.