diff --git a/README.md b/README.md index 6c808ce3..9e9dff76 100644 --- a/README.md +++ b/README.md @@ -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/) @@ -215,7 +215,7 @@ INDEX_EXCHANGE_API_URL=https://api.indexexchange.com ## API Reference -87 endpoints across 25 groups: +89 endpoints across 25 groups: | Group | Endpoints | Description | |-------|-----------|-------------| @@ -223,7 +223,7 @@ INDEX_EXCHANGE_API_URL=https://api.indexexchange.com | 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 | @@ -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 | diff --git a/docs/api/openapi.json b/docs/api/openapi.json index 4711c219..4730f858 100644 --- a/docs/api/openapi.json +++ b/docs/api/openapi.json @@ -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": [ { @@ -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": [ { @@ -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": { @@ -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": { diff --git a/docs/api/overview.md b/docs/api/overview.md index 1c229f45..5430ee7c 100644 --- a/docs/api/overview.md +++ b/docs/api/overview.md @@ -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` diff --git a/docs/architecture/overview.md b/docs/architecture/overview.md index b7fca495..6ac8ec24 100644 --- a/docs/architecture/overview.md +++ b/docs/architecture/overview.md @@ -20,7 +20,7 @@ graph LR subgraph "Seller Agent" MCP_S["/mcp/ (Streamable HTTP)
MCP Server"] A2A_S["/a2a/seller/jsonrpc
A2A Server"] - REST_S["REST API
87 endpoints"] + REST_S["REST API
89 endpoints"] NLP[NL Processing] TOOLS[Seller Tools] FLOWS[CrewAI Flows] @@ -61,7 +61,7 @@ graph TB subgraph "Protocol Layer" MCP[MCP Server
/mcp/ Streamable HTTP] A2A[A2A Server
/a2a/seller/jsonrpc] - API[REST API
87 endpoints, 25 tags] + API[REST API
89 endpoints, 25 tags] end AUTH[Auth & API Keys] @@ -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 diff --git a/docs/getting-started/quickstart.md b/docs/getting-started/quickstart.md index 3d97b5fe..4f5cecd0 100644 --- a/docs/getting-started/quickstart.md +++ b/docs/getting-started/quickstart.md @@ -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 @@ -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 diff --git a/docs/guides/chatgpt-setup.md b/docs/guides/chatgpt-setup.md index 689f93f1..a1df8eba 100644 --- a/docs/guides/chatgpt-setup.md +++ b/docs/guides/chatgpt-setup.md @@ -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`. diff --git a/docs/index.md b/docs/index.md index 6a60c290..42bc2dc5 100644 --- a/docs/index.md +++ b/docs/index.md @@ -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 @@ -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 diff --git a/tests/unit/test_openapi_drift.py b/tests/unit/test_openapi_drift.py new file mode 100644 index 00000000..4023b416 --- /dev/null +++ b/tests/unit/test_openapi_drift.py @@ -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" + )