Skip to content

IABTechLab/buyer-agent

Repository files navigation

V2 — Active Development

IAB Tech Lab — Buyer Agent

An AI-powered media buying system for DSPs, agencies, and advertisers to automate programmatic direct purchases using IAB OpenDirect 2.1 standards.

Full Documentation →

What This Does

  • Browse seller media kits with public (price ranges) or authenticated (exact pricing) access
  • Automate deal negotiations with configurable strategies (target CPM, max CPM, concession limits)
  • Book deals programmatically via IAB OpenDirect 2.1 protocol
  • Obtain Deal IDs for DSP activation in The Trade Desk, DV360, Amazon DSP, and other platforms
  • Present buyer identity (seat, agency, advertiser) to unlock tiered pricing from sellers
  • Aggregate inventory across multiple sellers in parallel

Who Should Use This

  • Media agencies automating programmatic direct buying with identity-based pricing
  • Advertisers with in-house teams seeking direct seller relationships
  • DSP operators discovering inventory and obtaining Deal IDs for activation
  • Trading desks scaling deal operations across multiple sellers

Access Methods

The buyer agent communicates with sellers via three protocols:

Interface Use Case
MCP Client Primary — structured tool calls to seller MCP servers
A2A Client Conversational — JSON-RPC 2.0 for natural language queries
REST Client Direct — HTTP calls for admin and OpenDirect operations

Protocol Documentation

Architecture

Campaign Brief ──→ Portfolio Manager (Opus)
                         │
          ┌──────────────┼──────────────┐
          ▼              ▼              ▼
    Channel Specialists (Sonnet)
    Branding │ CTV │ Mobile │ Performance │ Deals
          │              │              │
          ▼              ▼              ▼
    Functional Agents (Sonnet)
    Research │ Execution │ Reporting │ Audience
                         │
          ┌──────────────┼──────────────┐
          ▼              ▼              ▼
    MediaKitClient  NegotiationClient  OpenDirectClient
    (browse sellers) (multi-turn deals) (book orders)
          │              │              │
          ▼              ▼              ▼
                   Seller Agents
              (MCP / A2A / REST)

Architecture Documentation

Key Features

Media Kit Discovery

Browse seller inventory catalogs. Unauthenticated access shows price ranges; authenticate with an API key for exact pricing, placements, and audience segments. Aggregate across multiple sellers in parallel.

from ad_buyer.media_kit import MediaKitClient

async with MediaKitClient(api_key="your-key") as client:
    kit = await client.get_media_kit("http://seller.example.com:8001")
    for pkg in kit.featured:
        print(f"{pkg.name}: ${pkg.price_range}")

Media Kit Documentation

Negotiation

Pluggable strategy pattern for multi-turn price negotiation. Auto-negotiate or drive step-by-step.

from ad_buyer.negotiation.client import NegotiationClient
from ad_buyer.negotiation.strategies.simple_threshold import SimpleThresholdStrategy

strategy = SimpleThresholdStrategy(
    target_cpm=20.0,       # Opening offer
    max_cpm=30.0,          # Accept anything at or below
    concession_step=2.0,   # Concede $2/round
    max_rounds=5,          # Walk away after 5 rounds
)

client = NegotiationClient(api_key="your-key")
result = await client.auto_negotiate(seller_url, proposal_id, strategy)
print(f"Outcome: {result.outcome}, Price: ${result.final_price}")
Strategy Status Description
SimpleThresholdStrategy Available Fixed thresholds + linear concession
AdaptiveStrategy Planned Adjusts based on seller patterns
CompetitiveStrategy Planned Multi-seller competitive bidding

Negotiation Guide

Identity-Based Tiered Pricing

Reveal buyer identity progressively to unlock better pricing from sellers:

Tier Identity Required Typical Discount Negotiation
Public None 0% (range only)
Seat API key ~5%
Agency Agency ID ~10% Yes
Advertiser Advertiser ID ~15% Yes

Authentication Guide

Vendor Approval Gating (optional)

Plug in an IAB Diligence Platform tenant to keep unapproved sellers out of the buyer-agent workflow. Consults the iabBuyerAgentApproval flag via SGP's integration API. When SGP_ENFORCE=true, the canonical booking pipeline (DealBookingFlow / MultiSellerOrchestrator) excludes NOT APPROVED sellers at the discovery stage, before quoting or booking, and emits one sgp.vendor_gate event per decision. The gate fails closed: if the SGP API is unreachable while enforcing — or SGP_ENFORCE is set without an SGP_API_KEY — no seller passes, with a causeful reason on the event trail. Unknown vendors (not in your SGP portfolio) follow SGP_UNKNOWN_VENDOR_POLICY (block default / warn / allow). The example DiscoverInventoryTool / RequestDealTool apply the same checks. Off by default — with SGP_ENFORCE unset there are zero SGP calls and booking behavior is unchanged.

IAB Diligence Platform Approval

Quick Start

Install

git clone https://github.com/IABTechLab/buyer-agent.git
cd buyer-agent
pip install -e .

Configure

cp .env.example .env

Key settings:

# LLM — set the API key for your chosen provider
ANTHROPIC_API_KEY=sk-ant-api03-xxxxx        # For Anthropic (default)
# OPENAI_API_KEY=sk-xxxxx                   # For OpenAI / Azure
# GOOGLE_API_KEY=xxxxx                      # For Gemini

# LLM model (uses provider/model format — native Anthropic, OpenAI, Gemini, Azure, Bedrock)
DEFAULT_LLM_MODEL=anthropic/claude-sonnet-4-5-20250929
# DEFAULT_LLM_MODEL=openai/gpt-4o          # OpenAI example

# Any OpenAI-wire-compatible endpoint (NVIDIA NIM, Ollama, HuggingFace TGI, vLLM, ...)
# pins routing to the native OpenAI client via a custom base URL, regardless
# of the model id's shape:
# OPENAI_COMPATIBLE_LLM_API_BASE_URL=http://localhost:11434/v1   # Local Ollama example
# DEFAULT_LLM_MODEL=llama3

# Seller connection
SELLER_BASE_URL=http://localhost:8001        # Seller agent URL

# Storage
DATABASE_URL=sqlite:///./ad_buyer.db

LLM Provider Flexibility: CrewAI supports native integrations with Anthropic (default), OpenAI, Google Gemini, Azure OpenAI, and AWS Bedrock. Set DEFAULT_LLM_MODEL and MANAGER_LLM_MODEL using provider/model-name format (e.g., anthropic/claude-sonnet-4-5-20250929) and provide the matching API key. Install the matching extra: pip install "crewai[anthropic]". For any other OpenAI-wire-compatible endpoint (NVIDIA NIM, Ollama, HuggingFace TGI, vLLM, LM Studio, ...), set OPENAI_COMPATIBLE_LLM_API_BASE_URL alongside DEFAULT_LLM_MODEL/MANAGER_LLM_MODEL (using the raw model id the endpoint expects) — see .env.example for provider-specific examples. See the Quickstart Guide for details.

Full Configuration

Run

python -m ad_buyer.interfaces.api.main
# Server runs at http://localhost:8000

This is equivalent to running the ASGI app directly with uvicorn:

uvicorn ad_buyer.interfaces.api.main:app --port 8000

ANTHROPIC_API_KEY is optional to start the server (the API boots without it); it is only required once you run CrewAI-backed booking flows.

This quickstart is tested. tests/smoke/test_quickstart_smoke.py boots the app at the exact module path documented above (ad_buyer.interfaces.api.main:app) through its real startup lifecycle and asserts /health and /bookings respond — no network or LLM calls. Run it with ANTHROPIC_API_KEY=test pytest tests/smoke/test_quickstart_smoke.py. If it fails, the entrypoint above is wrong.

Verify

# Health check (served by the buyer agent itself — no backend needed)
curl http://localhost:8000/health

# List bookings (empty on a fresh server)
curl http://localhost:8000/bookings

The next two calls reach outward to a seller agent / OpenDirect backend, so they only work once a seller agent is running (see the Seller Agent and SELLER_BASE_URL in .env):

# Browse a seller's media kit (requires a seller agent on :8001)
curl http://localhost:8001/media-kit

# Search products across sellers (requires a reachable seller/OpenDirect backend)
curl -X POST http://localhost:8000/products/search \
  -H "Content-Type: application/json" \
  -d '{"channel": "ctv", "limit": 5}'

Quickstart Guide

Campaign Automation Demo

A self-contained, browser-based walkthrough of the campaign automation flow (budget allocation → pacing → reporting). It runs entirely in-process — no seller agent or external services required — and needs Flask, which ships in the dev extra:

pip install -e ".[dev]"
python -m demo.campaign_demo
# Opens at http://localhost:5055 (override with CAMPAIGN_DEMO_PORT)

Docker

Run in a container with Docker Compose:

cd infra/docker
docker compose up

Deployment Guide

API Reference

11 endpoints across 5 groups:

Group Endpoints Description
Health 1 Service health check
Bookings 5 Create, list, poll, and approve bookings
Products 1 Search seller product catalog
Events 2 Query the in-memory event bus
Buyer Orders 2 Order records and status-transition audit trail

Full API Reference

Client Libraries

Client Purpose Docs
MediaKitClient Browse seller inventory catalogs Media Kit
NegotiationClient Multi-turn price negotiation Negotiation
OpenDirectClient OpenDirect 2.1 booking operations Seller Integration
IABMCPClient MCP tool calls to seller agents MCP Client
A2AClient Conversational JSON-RPC with sellers A2A Client

Development

# Install dev dependencies
pip install -e ".[dev]"

# Run tests
ANTHROPIC_API_KEY=test pytest tests/ -v

# Lint
ruff check src/

# Build docs locally
pip install -e ".[docs]"
mkdocs serve

Related

License

Apache 2.0

About

No description, website, or topics provided.

Resources

Contributing

Stars

Watchers

Forks

Releases

Packages

Contributors

Languages