Skip to content
8 changes: 4 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ The seller agent exposes four communication interfaces:
|-----------|----------|----------|
| **MCP** | `/mcp` (Streamable HTTP), `/mcp-sse/sse` (legacy) | Primary interface — 46 tools for Claude, ChatGPT, Codex, Cursor, and buyer agents |
| **A2A** | `/a2a/{agent}/jsonrpc` | Conversational JSON-RPC 2.0 for natural language queries |
| **REST** | `/api/v1/*` | Programmatic access — 87 endpoints across 25 groups |
| **REST** | `/api/v1/*` | Programmatic access — 89 endpoints across 25 groups |
| **Chat** | `/chat` | Web-based conversational interface for human buyers |

> [Protocol Documentation](https://iabtechlab.github.io/seller-agent/api/mcp/)
Expand Down Expand Up @@ -215,15 +215,15 @@ INDEX_EXCHANGE_API_URL=https://api.indexexchange.com

## API Reference

87 endpoints across 25 groups:
89 endpoints across 25 groups:

| Group | Endpoints | Description |
|-------|-----------|-------------|
| Media Kit | 4 | Public inventory catalog (no auth) |
| Packages | 7 | Tier-gated package CRUD, assembly, and sync |
| Products | 6 | Product catalog, avails, inventory type overrides |
| Quotes | 2 | Non-binding price quotes (IAB Deals API) |
| Deal Booking | 11 | Deals, from-template, push, distribute, migrate, deprecate, lineage, export |
| Deal Booking | 12 | Deals, list, from-template, push, distribute, migrate, deprecate, lineage, export |
| Deals | 1 | Deal creation from accepted proposals |
| Deal Performance | 1 | Delivery metrics |
| Bulk Operations | 1 | Batch deal create/update/cancel |
Expand All @@ -238,7 +238,7 @@ INDEX_EXCHANGE_API_URL=https://api.indexexchange.com
| Supply Chain | 1 | sellers.json-like self-description |
| Curators | 4 | Curator registration + curated deals |
| Sessions | 5 | Multi-turn session persistence |
| Authentication | 4 | API key management |
| Authentication | 5 | API key management |
| Agent Registry | 6 | Agent card, trust + discovery |
| Pricing | 3 | Rate card + pricing calculation |
| Events | 2 | Event log queries |
Expand Down
114 changes: 112 additions & 2 deletions docs/api/openapi.json
Original file line number Diff line number Diff line change
Expand Up @@ -1016,7 +1016,7 @@
"Products"
],
"summary": "List Products",
"description": "List products in the catalog (shared ProductListResponse).\n\nReads from the cached static catalog (see `_get_static_product_catalog`)\ninstead of running ProductSetupFlow per request \u2014 kicking off the flow\nspins up an OpenDirect MCP session that hangs in `session.initialize()`.\nBuyers filter client-side over the returned Product records (there is\ndeliberately no POST /products/search on the shared catalog surface).",
"description": "List products in the catalog (shared ProductListResponse).\n\nReads from the cached static catalog (see `_get_static_product_catalog`)\ninstead of running ProductSetupFlow per request \u2014 kicking off the flow\nspins up an OpenDirect MCP session that hangs in `session.initialize()`.\nBuyers filter client-side over the returned Product records (there is\ndeliberately no POST /products/search on the shared catalog surface).\n\nAny stored inventory-type override (AI-14) is applied automatically \u2014\n``deps.get_product_catalog()`` itself now returns the catalog with\noverrides already applied, so every consumer sees one consistent view,\nnot just this route and ``get_product``.",
"operationId": "list_products_products_get",
"parameters": [
{
Expand Down Expand Up @@ -1131,7 +1131,7 @@
"Products"
],
"summary": "Get Product",
"description": "Get a specific product (shared Product primitive, no wrapper).\n\nReads from the cached static catalog instead of running ProductSetupFlow\nper request (see `list_products` for rationale).",
"description": "Get a specific product (shared Product primitive, no wrapper).\n\nReads from the cached static catalog instead of running ProductSetupFlow\nper request (see `list_products` for rationale). Any stored\ninventory-type override (AI-14) is applied automatically by\n``deps.get_product_catalog()``.",
"operationId": "get_product_products__product_id__get",
"parameters": [
{
Expand Down Expand Up @@ -1937,6 +1937,86 @@
}
}
}
},
"get": {
"tags": [
"Deal Booking"
],
"summary": "List Deals",
"description": "List stored deals, optionally filtered by wire status.\n\nOperator-only: the list spans every buyer's deals. Buyers read their\nown deal with ``GET /api/v1/deals/{deal_id}``.\n\n``status`` is the shared :class:`DealStatus` value the deal carries on\nthe wire (the same value ``GET /api/v1/deals/{deal_id}`` returns), so\nthe filter is applied after mapping each stored record to its\nresponse shape.\n\nRegistered ahead of ``/api/v1/deals/{deal_id}``; the two paths differ in\nlength so there is no shadowing, but keeping literal routes together\nwith ``/export`` keeps the EP-8.4 ordering rule easy to audit.",
"operationId": "list_deals_api_v1_deals_get",
"parameters": [
{
"name": "status",
"in": "query",
"required": false,
"schema": {
"anyOf": [
{
"$ref": "#/components/schemas/DealStatus"
},
{
"type": "null"
}
],
"title": "Status"
}
},
{
"name": "authorization",
"in": "header",
"required": false,
"schema": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"title": "Authorization"
}
},
{
"name": "X-Api-Key",
"in": "header",
"required": false,
"schema": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"title": "X-Api-Key"
}
}
],
"responses": {
"200": {
"description": "Successful Response",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/DealListResponse"
}
}
}
},
"422": {
"description": "Validation Error",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/HTTPValidationError"
}
}
}
}
}
}
},
"/agentic-audience/match": {
Expand Down Expand Up @@ -7700,6 +7780,36 @@
"title": "DealFromTemplateResponse",
"description": "Response for template-based deal creation."
},
"DealListResponse": {
"properties": {
"deals": {
"items": {
"$ref": "#/components/schemas/DealBookingResponse"
},
"type": "array",
"title": "Deals"
},
"count": {
"type": "integer",
"title": "Count"
},
"skipped": {
"items": {
"type": "string"
},
"type": "array",
"title": "Skipped",
"default": []
}
},
"type": "object",
"required": [
"deals",
"count"
],
"title": "DealListResponse",
"description": "Page of stored deals in the shared booking-response shape."
},
"DealMigrationRequest": {
"properties": {
"old_deal_id": {
Expand Down
2 changes: 1 addition & 1 deletion docs/api/overview.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# API Overview

The Ad Seller System API exposes **87 endpoints** across **25 tags**. All endpoints are served from a single FastAPI application. The complete auto-generated route inventory is in the [REST Endpoints reference](../reference/endpoints.md).
The Ad Seller System API exposes **89 endpoints** across **25 tags**. All endpoints are served from a single FastAPI application. The complete auto-generated route inventory is in the [REST Endpoints reference](../reference/endpoints.md).

**Base URL:** `http://localhost:8000`
**OpenAPI docs:** `http://localhost:8000/docs`
Expand Down
6 changes: 3 additions & 3 deletions docs/architecture/overview.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ graph LR
subgraph "Seller Agent"
MCP_S["/mcp/ (Streamable HTTP)<br/>MCP Server"]
A2A_S["/a2a/seller/jsonrpc<br/>A2A Server"]
REST_S["REST API<br/>87 endpoints"]
REST_S["REST API<br/>89 endpoints"]
NLP[NL Processing]
TOOLS[Seller Tools]
FLOWS[CrewAI Flows]
Expand Down Expand Up @@ -61,7 +61,7 @@ graph TB
subgraph "Protocol Layer"
MCP[MCP Server<br/>/mcp/ Streamable HTTP]
A2A[A2A Server<br/>/a2a/seller/jsonrpc]
API[REST API<br/>87 endpoints, 25 tags]
API[REST API<br/>89 endpoints, 25 tags]
end

AUTH[Auth & API Keys]
Expand Down Expand Up @@ -135,7 +135,7 @@ graph TB

### API Layer

**FastAPI application** with 87 endpoints across 25 OpenAPI tags. Handles HTTP routing, request validation, authentication, and response serialization. See [API Overview](../api/overview.md).
**FastAPI application** with 89 endpoints across 25 OpenAPI tags. Handles HTTP routing, request validation, authentication, and response serialization. See [API Overview](../api/overview.md).

### Authentication and Agent Registry

Expand Down
4 changes: 2 additions & 2 deletions docs/getting-started/quickstart.md
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ Expected response:

## Browse the API Docs

Open `http://localhost:8000/docs` in a browser for the auto-generated Swagger UI with all 87 endpoints.
Open `http://localhost:8000/docs` in a browser for the auto-generated Swagger UI with all 89 endpoints.

## First API Calls

Expand Down Expand Up @@ -118,6 +118,6 @@ Returns a confirmed deal with a Deal ID, OpenRTB parameters, and DSP activation

## Next Steps

- [API Overview](../api/overview.md) --- see all 87 endpoints
- [API Overview](../api/overview.md) --- see all 89 endpoints
- [Authentication](../api/authentication.md) --- set up API keys for authenticated access
- [Buyer Agent Integration](../integration/buyer-agent.md) --- connect a buyer agent
2 changes: 1 addition & 1 deletion docs/guides/chatgpt-setup.md
Original file line number Diff line number Diff line change
Expand Up @@ -190,6 +190,6 @@ Base URL: https://your-publisher.example.com
Auth: Authorization: Bearer sk-operator-XXXXX
```

The seller agent exposes 87 REST endpoints. See the [API Overview](../api/overview.md).
The seller agent exposes 89 REST endpoints. See the [API Overview](../api/overview.md).

For ChatGPT specifically, you can also create a **Custom GPT** with Actions pointing to the REST API's OpenAPI spec at `https://your-publisher.example.com/openapi.json`.
6 changes: 3 additions & 3 deletions docs/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,12 @@ Part of the IAB Tech Lab Agent Ecosystem --- see also the [Buyer Agent](https://
|----------|----------|----------|
| **[MCP](api/mcp.md)** | `/mcp/` (Streamable HTTP), `/mcp-sse/sse` (legacy) | Primary interface — 46 tools for Claude, ChatGPT, Codex, Cursor, and buyer agents |
| **[A2A](api/a2a.md)** | *(planned — not yet served)* | Conversational agent interactions — natural language, multi-turn |
| **[REST API](api/overview.md)** | `/api/v1/*` | Programmatic access — 87 endpoints across 25 groups |
| **[REST API](api/overview.md)** | `/api/v1/*` | Programmatic access — 89 endpoints across 25 groups |

## Key Capabilities

- **46 MCP tools** for Claude, ChatGPT, Codex, Cursor, and Windsurf — interactive setup wizard + full operations
- **87 REST endpoints** across 25 categories covering the complete ad selling workflow
- **89 REST endpoints** across 25 categories covering the complete ad selling workflow
- **Pluggable ad server** support — Google Ad Manager and FreeWheel (Streaming Hub + Buyer Cloud)
- **Multi-SSP distribution** — PubMatic (MCP), Index Exchange (REST), Magnite (REST) with routing rules
- **IAB Deals API v1.0** — standardized deal push to buyer DSPs
Expand Down Expand Up @@ -54,7 +54,7 @@ Part of the IAB Tech Lab Agent Ecosystem --- see also the [Buyer Agent](https://

### API Reference

- [API Overview](api/overview.md) --- all 87 endpoints grouped by tag
- [API Overview](api/overview.md) --- all 89 endpoints grouped by tag
- [MCP Protocol](api/mcp.md) --- 46 MCP tools for Claude, ChatGPT, and buyer agents
- [A2A Protocol](api/a2a.md) --- conversational agent-to-agent interface
- [Agent Discovery](api/agent-discovery.md) --- `/.well-known/agent.json` and trust registry
Expand Down
30 changes: 30 additions & 0 deletions tests/unit/test_openapi_drift.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
# Author: Green Mountain Systems AI Inc.
# Donated to IAB Tech Lab

"""Drift guard for the committed OpenAPI document.

Builds the OpenAPI schema in memory the same way ``scripts/generate_openapi.py``
does (``app.openapi()``) and asserts it equals the committed
``docs/api/openapi.json``. Any code change that adds, removes, or reshapes a
REST endpoint or schema breaks this test until the document is regenerated with:

python scripts/generate_openapi.py

The comparison is on parsed JSON, so formatting alone cannot cause a false drift.
"""

import json
from pathlib import Path

from ad_seller.interfaces.api.main import app

_COMMITTED = Path(__file__).resolve().parents[2] / "docs" / "api" / "openapi.json"


def test_openapi_json_matches_app():
"""Committed docs/api/openapi.json must equal the schema the app generates."""
assert _COMMITTED.exists(), f"{_COMMITTED} is missing — run: python scripts/generate_openapi.py"
assert json.loads(_COMMITTED.read_text()) == app.openapi(), (
"docs/api/openapi.json is out of date with the code.\n"
"Regenerate it with: python scripts/generate_openapi.py"
)
Loading