Package adcp
Sub-modules
adcp.adagentsadcp.capabilities-
Feature capability resolution for AdCP …
adcp.clientadcp.configadcp.exceptionsadcp.property_registry-
PropertyRegistry — local authorization cache backed by the AAO registry …
adcp.protocolsadcp.registry-
Client for the AdCP registry API (brand, property, member, and policy lookups).
adcp.registry_sync-
Registry change feed synchronization.
adcp.server-
ADCP Server Framework …
adcp.simple-
Simplified API accessor for ADCPClient …
adcp.testing-
Test helpers for AdCP client library …
adcp.types-
AdCP Type System …
adcp.utilsadcp.validation-
Runtime validation for AdCP data structures …
adcp.webhooks-
Webhook creation and signing utilities for AdCP agents.
Functions
def create_a2a_webhook_payload(task_id: str,
status: TaskStatus,
context_id: str,
result: AdcpAsyncResponseData | dict[str, Any],
timestamp: datetime | None = None) ‑> a2a.types.Task | a2a.types.TaskStatusUpdateEvent-
Expand source code
def create_a2a_webhook_payload( task_id: str, status: GeneratedTaskStatus, context_id: str, result: AdcpAsyncResponseData | dict[str, Any], timestamp: datetime | None = None, ) -> Task | TaskStatusUpdateEvent: """ Create A2A webhook payload (Task or TaskStatusUpdateEvent). Per A2A specification: - Terminated statuses (completed, failed): Returns Task with artifacts[].parts[] - Intermediate statuses (working, input-required, submitted): Returns TaskStatusUpdateEvent with status.message.parts[] This function helps agent implementations construct properly formatted A2A webhook payloads for sending to clients. Args: task_id: Unique identifier for the task status: Current task status context_id: Session/conversation identifier (required by A2A protocol) timestamp: When the webhook was generated (defaults to current UTC time) result: Task-specific payload (AdCP response data) Returns: Task object for terminated statuses, TaskStatusUpdateEvent for intermediate statuses Examples: Create a completed Task webhook: >>> from adcp.webhooks import create_a2a_webhook_payload >>> from adcp.types import GeneratedTaskStatus >>> >>> task = create_a2a_webhook_payload( ... task_id="task_123", ... status=GeneratedTaskStatus.completed, ... result={"products": [...]}, ... message="Found 5 products" ... ) >>> # task is a Task object with artifacts containing the result Create a working status update: >>> event = create_a2a_webhook_payload( ... task_id="task_456", ... status=GeneratedTaskStatus.working, ... message="Processing 3 of 10 items" ... ) >>> # event is a TaskStatusUpdateEvent with status.message Send A2A webhook via HTTP POST: >>> import httpx >>> from a2a.types import Task >>> >>> payload = create_a2a_webhook_payload(...) >>> # Serialize to dict for JSON >>> if isinstance(payload, Task): ... payload_dict = payload.model_dump(mode='json') ... else: ... payload_dict = payload.model_dump(mode='json') >>> >>> response = await httpx.post(webhook_url, json=payload_dict) """ if timestamp is None: timestamp = datetime.now(timezone.utc) # Convert datetime to ISO string for A2A protocol timestamp_str = timestamp.isoformat() if isinstance(timestamp, datetime) else timestamp # Map GeneratedTaskStatus to A2A status state string status_value = status.value if hasattr(status, "value") else str(status) # Map AdCP status to A2A status state # Note: A2A uses "input-required" (hyphenated) while AdCP uses "input_required" (underscore) status_mapping = { "completed": "completed", "failed": "failed", "working": "working", "submitted": "submitted", "input_required": "input-required", } a2a_status_state = status_mapping.get(status_value, status_value) # Build parts for the message/artifact parts: list[Part] = [] # Add DataPart # Convert AdcpAsyncResponseData to dict if it's a Pydantic model if hasattr(result, "model_dump"): result_dict: dict[str, Any] = result.model_dump(mode="json") else: result_dict = result data_part = DataPart(data=result_dict) parts.append(Part(root=data_part)) # Determine if this is a terminated status (Task) or intermediate (TaskStatusUpdateEvent) is_terminated = status in [GeneratedTaskStatus.completed, GeneratedTaskStatus.failed] # Convert string to TaskState enum task_state_enum = TaskState(a2a_status_state) if is_terminated: # Create Task object with artifacts for terminated statuses task_status = TaskStatus(state=task_state_enum, timestamp=timestamp_str) # Build artifact with parts # Note: Artifact requires artifact_id, use task_id as prefix if parts: artifact = Artifact( artifact_id=f"{task_id}_result", parts=parts, ) artifacts = [artifact] else: artifacts = [] return Task( id=task_id, status=task_status, artifacts=artifacts, context_id=context_id, ) else: # Create TaskStatusUpdateEvent with status.message for intermediate statuses # Build message with parts if parts: message_obj = Message( message_id=f"{task_id}_msg", role=Role.agent, # Agent is responding parts=parts, ) else: message_obj = None task_status = TaskStatus( state=task_state_enum, timestamp=timestamp_str, message=message_obj ) return TaskStatusUpdateEvent( task_id=task_id, status=task_status, context_id=context_id, final=False, # Intermediate statuses are not final )Create A2A webhook payload (Task or TaskStatusUpdateEvent).
Per A2A specification: - Terminated statuses (completed, failed): Returns Task with artifacts[].parts[] - Intermediate statuses (working, input-required, submitted): Returns TaskStatusUpdateEvent with status.message.parts[]
This function helps agent implementations construct properly formatted A2A webhook payloads for sending to clients.
Args
task_id- Unique identifier for the task
status- Current task status
context_id- Session/conversation identifier (required by A2A protocol)
timestamp- When the webhook was generated (defaults to current UTC time)
result- Task-specific payload (AdCP response data)
Returns
Task object for terminated statuses, TaskStatusUpdateEvent for intermediate statuses
Examples
Create a completed Task webhook:
>>> from adcp.webhooks import create_a2a_webhook_payload >>> from adcp.types import GeneratedTaskStatus >>> >>> task = create_a2a_webhook_payload( ... task_id="task_123", ... status=GeneratedTaskStatus.completed, ... result={"products": [...]}, ... message="Found 5 products" ... ) >>> # task is a Task object with artifacts containing the resultCreate a working status update:
>>> event = create_a2a_webhook_payload( ... task_id="task_456", ... status=GeneratedTaskStatus.working, ... message="Processing 3 of 10 items" ... ) >>> # event is a TaskStatusUpdateEvent with status.messageSend A2A webhook via HTTP POST:
>>> import httpx >>> from a2a.types import Task >>> >>> payload = create_a2a_webhook_payload(...) >>> # Serialize to dict for JSON >>> if isinstance(payload, Task): ... payload_dict = payload.model_dump(mode='json') ... else: ... payload_dict = payload.model_dump(mode='json') >>> >>> response = await httpx.post(webhook_url, json=payload_dict) def create_mcp_webhook_payload(task_id: str,
status: TaskStatus,
result: AdcpAsyncResponseData | dict[str, Any] | None = None,
timestamp: datetime | None = None,
task_type: str | None = None,
operation_id: str | None = None,
message: str | None = None,
context_id: str | None = None,
domain: str | None = None) ‑> dict[str, typing.Any]-
Expand source code
def create_mcp_webhook_payload( task_id: str, status: GeneratedTaskStatus, result: AdcpAsyncResponseData | dict[str, Any] | None = None, timestamp: datetime | None = None, task_type: str | None = None, operation_id: str | None = None, message: str | None = None, context_id: str | None = None, domain: str | None = None, ) -> dict[str, Any]: """ Create MCP webhook payload dictionary. This function helps agent implementations construct properly formatted webhook payloads for sending to clients. Args: task_id: Unique identifier for the task status: Current task status task_type: Optionally type of AdCP operation (e.g., "get_products", "create_media_buy") timestamp: When the webhook was generated (defaults to current UTC time) result: Task-specific payload (AdCP response data) operation_id: Publisher-defined operation identifier (deprecated from payload, should be in URL routing, but included for backward compatibility) message: Human-readable summary of task state context_id: Session/conversation identifier domain: AdCP domain this task belongs to Returns: Dictionary matching McpWebhookPayload schema, ready to be sent as JSON Examples: Create a completed webhook with results: >>> from adcp.webhooks import create_mcp_webhook_payload >>> from adcp.types import GeneratedTaskStatus >>> >>> payload = create_mcp_webhook_payload( ... task_id="task_123", ... task_type="get_products", ... status=GeneratedTaskStatus.completed, ... result={"products": [...]}, ... message="Found 5 products" ... ) Create a failed webhook with error: >>> payload = create_mcp_webhook_payload( ... task_id="task_456", ... task_type="create_media_buy", ... status=GeneratedTaskStatus.failed, ... result={"errors": [{"code": "INVALID_INPUT", "message": "..."}]}, ... message="Validation failed" ... ) Create a working status update: >>> payload = create_mcp_webhook_payload( ... task_id="task_789", ... task_type="sync_creatives", ... status=GeneratedTaskStatus.working, ... message="Processing 3 of 10 creatives" ... ) """ if timestamp is None: timestamp = datetime.now(timezone.utc) # Convert status enum to string value status_value = status.value if hasattr(status, "value") else str(status) # Build payload matching McpWebhookPayload schema payload: dict[str, Any] = { "task_id": task_id, "task_type": task_type, "status": status_value, "timestamp": timestamp.isoformat() if isinstance(timestamp, datetime) else timestamp, } # Add optional fields only if provided if result is not None: # Convert Pydantic model to dict if needed for JSON serialization if hasattr(result, "model_dump"): payload["result"] = result.model_dump(mode="json") else: payload["result"] = result if operation_id is not None: payload["operation_id"] = operation_id if message is not None: payload["message"] = message if context_id is not None: payload["context_id"] = context_id if domain is not None: payload["domain"] = domain return payloadCreate MCP webhook payload dictionary.
This function helps agent implementations construct properly formatted webhook payloads for sending to clients.
Args
task_id- Unique identifier for the task
status- Current task status
task_type- Optionally type of AdCP operation (e.g., "get_products", "create_media_buy")
timestamp- When the webhook was generated (defaults to current UTC time)
result- Task-specific payload (AdCP response data)
operation_id- Publisher-defined operation identifier (deprecated from payload, should be in URL routing, but included for backward compatibility)
message- Human-readable summary of task state
context_id- Session/conversation identifier
domain- AdCP domain this task belongs to
Returns
Dictionary matching McpWebhookPayload schema, ready to be sent as JSON
Examples
Create a completed webhook with results:
>>> from adcp.webhooks import create_mcp_webhook_payload >>> from adcp.types import GeneratedTaskStatus >>> >>> payload = create_mcp_webhook_payload( ... task_id="task_123", ... task_type="get_products", ... status=GeneratedTaskStatus.completed, ... result={"products": [...]}, ... message="Found 5 products" ... )Create a failed webhook with error:
>>> payload = create_mcp_webhook_payload( ... task_id="task_456", ... task_type="create_media_buy", ... status=GeneratedTaskStatus.failed, ... result={"errors": [{"code": "INVALID_INPUT", "message": "..."}]}, ... message="Validation failed" ... )Create a working status update:
>>> payload = create_mcp_webhook_payload( ... task_id="task_789", ... task_type="sync_creatives", ... status=GeneratedTaskStatus.working, ... message="Processing 3 of 10 creatives" ... ) def create_test_agent(**overrides: Any) ‑> AgentConfig-
Expand source code
def create_test_agent(**overrides: Any) -> AgentConfig: """Create a custom test agent configuration. Useful when you need to modify the default test agent setup. Args: **overrides: Keyword arguments to override default config values Returns: Complete agent configuration Example: ```python from adcp.testing import create_test_agent from adcp.client import ADCPClient # Use default test agent with custom ID config = create_test_agent(id="my-test-agent") client = ADCPClient(config) ``` Example: ```python # Use A2A protocol instead of MCP from adcp.types.core import Protocol config = create_test_agent( protocol=Protocol.A2A, agent_uri="https://test-agent.adcontextprotocol.org" ) ``` """ base_config = TEST_AGENT_MCP_CONFIG.model_dump() base_config.update(overrides) return AgentConfig(**base_config)Create a custom test agent configuration.
Useful when you need to modify the default test agent setup.
Args
**overrides- Keyword arguments to override default config values
Returns
Complete agent configuration
Example
from adcp.testing import create_test_agent from adcp.client import ADCPClient # Use default test agent with custom ID config = create_test_agent(id="my-test-agent") client = ADCPClient(config)Example
# Use A2A protocol instead of MCP from adcp.types.core import Protocol config = create_test_agent( protocol=Protocol.A2A, agent_uri="https://test-agent.adcontextprotocol.org" ) def domain_matches(property_domain: str, agent_domain_pattern: str) ‑> bool-
Expand source code
def domain_matches(property_domain: str, agent_domain_pattern: str) -> bool: """Check if domains match per AdCP rules. Rules: - Exact match always succeeds - 'example.com' matches www.example.com, m.example.com (common subdomains) - 'subdomain.example.com' matches that specific subdomain only - '*.example.com' matches all subdomains Args: property_domain: Domain from property agent_domain_pattern: Domain pattern from adagents.json Returns: True if domains match per AdCP rules """ # Normalize both domains for comparison try: property_domain = _normalize_domain(property_domain) agent_domain_pattern = _normalize_domain(agent_domain_pattern) except AdagentsValidationError: # Invalid domain format - no match return False # Exact match if property_domain == agent_domain_pattern: return True # Wildcard pattern (*.example.com) if agent_domain_pattern.startswith("*."): base_domain = agent_domain_pattern[2:] return property_domain.endswith(f".{base_domain}") # Bare domain matches common subdomains (www, m) # If agent pattern is a bare domain (no subdomain), match www/m subdomains if "." in agent_domain_pattern and not agent_domain_pattern.startswith("www."): # Check if this looks like a bare domain (e.g., example.com) parts = agent_domain_pattern.split(".") if len(parts) == 2: # Looks like bare domain common_subdomains = ["www", "m"] for subdomain in common_subdomains: if property_domain == f"{subdomain}.{agent_domain_pattern}": return True return FalseCheck if domains match per AdCP rules.
Rules: - Exact match always succeeds - 'example.com' matches www.example.com, m.example.com (common subdomains) - 'subdomain.example.com' matches that specific subdomain only - '*.example.com' matches all subdomains
Args
property_domain- Domain from property
agent_domain_pattern- Domain pattern from adagents.json
Returns
True if domains match per AdCP rules
def extract_webhook_result_data(webhook_payload: dict[str, Any]) ‑> AdcpAsyncResponseData | None-
Expand source code
def extract_webhook_result_data(webhook_payload: dict[str, Any]) -> AdcpAsyncResponseData | None: """ Extract result data from webhook payload (MCP or A2A format). This utility function handles webhook payloads from both MCP and A2A protocols, extracting the result data regardless of the webhook format. Useful for quick inspection, logging, or custom webhook routing logic without requiring full client initialization. Protocol Detection: - A2A Task: Has "artifacts" field (terminated statuses: completed, failed) - A2A TaskStatusUpdateEvent: Has nested "status.message" structure (intermediate statuses) - MCP: Has "result" field directly Args: webhook_payload: Raw webhook dictionary from HTTP request (JSON-deserialized) Returns: AdcpAsyncResponseData union type containing the extracted AdCP response, or None if no result present. For A2A webhooks, unwraps data from artifacts/message parts structure. For MCP webhooks, returns the result field directly. Examples: Extract from MCP webhook: >>> mcp_payload = { ... "task_id": "task_123", ... "task_type": "create_media_buy", ... "status": "completed", ... "timestamp": "2025-01-15T10:00:00Z", ... "result": {"media_buy_id": "mb_123", "buyer_ref": "ref_123", "packages": []} ... } >>> result = extract_webhook_result_data(mcp_payload) >>> print(result["media_buy_id"]) mb_123 Extract from A2A Task webhook: >>> a2a_task_payload = { ... "id": "task_456", ... "context_id": "ctx_456", ... "status": {"state": "completed", "timestamp": "2025-01-15T10:00:00Z"}, ... "artifacts": [ ... { ... "artifact_id": "artifact_456", ... "parts": [ ... { ... "data": { ... "media_buy_id": "mb_456", ... "buyer_ref": "ref_456", ... "packages": [] ... } ... } ... ] ... } ... ] ... } >>> result = extract_webhook_result_data(a2a_task_payload) >>> print(result["media_buy_id"]) mb_456 Extract from A2A TaskStatusUpdateEvent webhook: >>> a2a_event_payload = { ... "task_id": "task_789", ... "context_id": "ctx_789", ... "status": { ... "state": "working", ... "timestamp": "2025-01-15T10:00:00Z", ... "message": { ... "message_id": "msg_789", ... "role": "agent", ... "parts": [ ... {"data": {"current_step": "processing", "percentage": 50}} ... ] ... } ... }, ... "final": False ... } >>> result = extract_webhook_result_data(a2a_event_payload) >>> print(result["percentage"]) 50 Handle webhook with no result: >>> empty_payload = {"task_id": "task_000", "status": "working", "timestamp": "..."} >>> result = extract_webhook_result_data(empty_payload) >>> print(result) None """ # Detect A2A Task format (has "artifacts" field) if "artifacts" in webhook_payload: # Extract from task.artifacts[].parts[] artifacts = webhook_payload.get("artifacts", []) if not artifacts: return None # Use last artifact (most recent) target_artifact = artifacts[-1] parts = target_artifact.get("parts", []) if not parts: return None # Find DataPart (skip TextPart) for part in parts: # Check if this part has "data" field (DataPart) if "data" in part: data = part["data"] # Unwrap {"response": {...}} wrapper if present (A2A convention) if isinstance(data, dict) and "response" in data and len(data) == 1: return cast(AdcpAsyncResponseData, data["response"]) return cast(AdcpAsyncResponseData, data) return None # Detect A2A TaskStatusUpdateEvent format (has nested "status.message") status = webhook_payload.get("status") if isinstance(status, dict): message = status.get("message") if isinstance(message, dict): # Extract from status.message.parts[] parts = message.get("parts", []) if not parts: return None # Find DataPart for part in parts: if "data" in part: data = part["data"] # Unwrap {"response": {...}} wrapper if present if isinstance(data, dict) and "response" in data and len(data) == 1: return cast(AdcpAsyncResponseData, data["response"]) return cast(AdcpAsyncResponseData, data) return None # MCP format: result field directly return cast(AdcpAsyncResponseData | None, webhook_payload.get("result"))Extract result data from webhook payload (MCP or A2A format).
This utility function handles webhook payloads from both MCP and A2A protocols, extracting the result data regardless of the webhook format. Useful for quick inspection, logging, or custom webhook routing logic without requiring full client initialization.
Protocol Detection: - A2A Task: Has "artifacts" field (terminated statuses: completed, failed) - A2A TaskStatusUpdateEvent: Has nested "status.message" structure (intermediate statuses) - MCP: Has "result" field directly
Args
webhook_payload- Raw webhook dictionary from HTTP request (JSON-deserialized)
Returns
AdcpAsyncResponseData union type containing the extracted AdCP response, or None if no result present. For A2A webhooks, unwraps data from artifacts/message parts structure. For MCP webhooks, returns the result field directly.
Examples
Extract from MCP webhook:
>>> mcp_payload = { ... "task_id": "task_123", ... "task_type": "create_media_buy", ... "status": "completed", ... "timestamp": "2025-01-15T10:00:00Z", ... "result": {"media_buy_id": "mb_123", "buyer_ref": "ref_123", "packages": []} ... } >>> result = extract_webhook_result_data(mcp_payload) >>> print(result["media_buy_id"]) mb_123Extract from A2A Task webhook:
>>> a2a_task_payload = { ... "id": "task_456", ... "context_id": "ctx_456", ... "status": {"state": "completed", "timestamp": "2025-01-15T10:00:00Z"}, ... "artifacts": [ ... { ... "artifact_id": "artifact_456", ... "parts": [ ... { ... "data": { ... "media_buy_id": "mb_456", ... "buyer_ref": "ref_456", ... "packages": [] ... } ... } ... ] ... } ... ] ... } >>> result = extract_webhook_result_data(a2a_task_payload) >>> print(result["media_buy_id"]) mb_456Extract from A2A TaskStatusUpdateEvent webhook:
>>> a2a_event_payload = { ... "task_id": "task_789", ... "context_id": "ctx_789", ... "status": { ... "state": "working", ... "timestamp": "2025-01-15T10:00:00Z", ... "message": { ... "message_id": "msg_789", ... "role": "agent", ... "parts": [ ... {"data": {"current_step": "processing", "percentage": 50}} ... ] ... } ... }, ... "final": False ... } >>> result = extract_webhook_result_data(a2a_event_payload) >>> print(result["percentage"]) 50Handle webhook with no result:
>>> empty_payload = {"task_id": "task_000", "status": "working", "timestamp": "..."} >>> result = extract_webhook_result_data(empty_payload) >>> print(result) None async def fetch_adagents(publisher_domain: str,
timeout: float = 10.0,
user_agent: str = 'AdCP-Client/1.0',
client: httpx.AsyncClient | None = None) ‑> dict[str, typing.Any]-
Expand source code
async def fetch_adagents( publisher_domain: str, timeout: float = 10.0, user_agent: str = "AdCP-Client/1.0", client: httpx.AsyncClient | None = None, ) -> dict[str, Any]: """Fetch and parse adagents.json from publisher domain. Follows authoritative_location redirects per the AdCP specification. When a publisher's adagents.json contains an authoritative_location field instead of authorized_agents, this function fetches the referenced URL to get the actual authorization data. Args: publisher_domain: Domain hosting the adagents.json file timeout: Request timeout in seconds user_agent: User-Agent header for HTTP request client: Optional httpx.AsyncClient for connection pooling. If provided, caller is responsible for client lifecycle. If None, a new client is created for this request. Returns: Parsed adagents.json data (resolved from authoritative_location if present) Raises: AdagentsNotFoundError: If adagents.json not found (404) AdagentsValidationError: If JSON is invalid, malformed, or redirects exceed maximum depth or form a loop AdagentsTimeoutError: If request times out Notes: For production use with multiple requests, pass a shared httpx.AsyncClient to enable connection pooling and improve performance. """ # Validate and normalize domain for security publisher_domain = _validate_publisher_domain(publisher_domain) # Construct initial URL url = f"https://{publisher_domain}/.well-known/adagents.json" # Track visited URLs to detect loops visited_urls: set[str] = set() for depth in range(MAX_REDIRECT_DEPTH + 1): # Check for redirect loop if url in visited_urls: raise AdagentsValidationError(f"Circular redirect detected: {url} already visited") visited_urls.add(url) data = await _fetch_adagents_url(url, timeout, user_agent, client) # Check if this is a redirect. A response with authoritative_location but no # authorized_agents indicates a redirect. If both are present, authorized_agents # takes precedence (response is treated as final). if "authoritative_location" in data and "authorized_agents" not in data: authoritative_url = data["authoritative_location"] # Validate HTTPS requirement if not isinstance(authoritative_url, str) or not authoritative_url.startswith( "https://" ): raise AdagentsValidationError( f"authoritative_location must be an HTTPS URL, got: {authoritative_url!r}" ) # Check if we've exceeded max depth if depth >= MAX_REDIRECT_DEPTH: raise AdagentsValidationError( f"Maximum redirect depth ({MAX_REDIRECT_DEPTH}) exceeded" ) # Follow the redirect url = authoritative_url continue # We have the final data with authorized_agents (or both fields present, # in which case authorized_agents takes precedence) return data # Unreachable: loop always exits via return or raise above raise AssertionError("Unreachable") # pragma: no coverFetch and parse adagents.json from publisher domain.
Follows authoritative_location redirects per the AdCP specification. When a publisher's adagents.json contains an authoritative_location field instead of authorized_agents, this function fetches the referenced URL to get the actual authorization data.
Args
publisher_domain- Domain hosting the adagents.json file
timeout- Request timeout in seconds
user_agent- User-Agent header for HTTP request
client- Optional httpx.AsyncClient for connection pooling. If provided, caller is responsible for client lifecycle. If None, a new client is created for this request.
Returns
Parsed adagents.json data (resolved from authoritative_location if present)
Raises
AdagentsNotFoundError- If adagents.json not found (404)
AdagentsValidationError- If JSON is invalid, malformed, or redirects exceed maximum depth or form a loop
AdagentsTimeoutError- If request times out
Notes
For production use with multiple requests, pass a shared httpx.AsyncClient to enable connection pooling and improve performance.
-
Expand source code
async def fetch_agent_authorizations( agent_url: str, publisher_domains: list[str], timeout: float = 10.0, client: httpx.AsyncClient | None = None, ) -> dict[str, AuthorizationContext]: """Fetch authorization contexts by checking publisher adagents.json files. This function discovers what publishers have authorized your agent by fetching their adagents.json files from the .well-known directory and extracting the properties your agent can access. This is the "pull" approach - you query publishers to see if they've authorized you. Args: agent_url: URL of your sales agent publisher_domains: List of publisher domains to check (e.g., ["nytimes.com", "wsj.com"]) timeout: Request timeout in seconds for each fetch client: Optional httpx.AsyncClient for connection pooling Returns: Dictionary mapping publisher domain to AuthorizationContext. Only includes domains where the agent is authorized. Example: >>> # "Pull" approach - check what publishers have authorized you >>> contexts = await fetch_agent_authorizations( ... "https://our-sales-agent.com", ... ["nytimes.com", "wsj.com", "cnn.com"] ... ) >>> for domain, ctx in contexts.items(): ... print(f"{domain}:") ... print(f" Property IDs: {ctx.property_ids}") ... print(f" Tags: {ctx.property_tags}") Notes: - Silently skips domains where adagents.json is not found or invalid - Only returns domains where the agent is explicitly authorized - For production use with many domains, pass a shared httpx.AsyncClient to enable connection pooling """ import asyncio # Create tasks to fetch all adagents.json files in parallel async def fetch_authorization_for_domain( domain: str, ) -> tuple[str, AuthorizationContext | None]: """Fetch authorization context for a single domain.""" try: adagents_data = await fetch_adagents(domain, timeout=timeout, client=client) # Check if agent is authorized if not verify_agent_authorization(adagents_data, agent_url): return (domain, None) # Get properties for this agent properties = get_properties_by_agent(adagents_data, agent_url) # Create authorization context return (domain, AuthorizationContext(properties)) except (AdagentsNotFoundError, AdagentsValidationError, AdagentsTimeoutError): # Silently skip domains with missing or invalid adagents.json return (domain, None) # Fetch all domains in parallel tasks = [fetch_authorization_for_domain(domain) for domain in publisher_domains] results = await asyncio.gather(*tasks) # Build result dictionary, filtering out None values return {domain: ctx for domain, ctx in results if ctx is not None}Fetch authorization contexts by checking publisher adagents.json files.
This function discovers what publishers have authorized your agent by fetching their adagents.json files from the .well-known directory and extracting the properties your agent can access.
This is the "pull" approach - you query publishers to see if they've authorized you.
Args
agent_url- URL of your sales agent
publisher_domains- List of publisher domains to check (e.g., ["nytimes.com", "wsj.com"])
timeout- Request timeout in seconds for each fetch
client- Optional httpx.AsyncClient for connection pooling
Returns
Dictionary mapping publisher domain to AuthorizationContext. Only includes domains where the agent is authorized.
Example
>>> # "Pull" approach - check what publishers have authorized you >>> contexts = await fetch_agent_authorizations( ... "https://our-sales-agent.com", ... ["nytimes.com", "wsj.com", "cnn.com"] ... ) >>> for domain, ctx in contexts.items(): ... print(f"{domain}:") ... print(f" Property IDs: {ctx.property_ids}") ... print(f" Tags: {ctx.property_tags}")Notes
- Silently skips domains where adagents.json is not found or invalid
- Only returns domains where the agent is explicitly authorized
- For production use with many domains, pass a shared httpx.AsyncClient to enable connection pooling
def get_adcp_signed_headers_for_webhook(headers: dict[str, Any],
secret: str,
timestamp: str | int | None,
payload: dict[str, Any] | AdCPBaseModel) ‑> dict[str, typing.Any]-
Expand source code
def get_adcp_signed_headers_for_webhook( headers: dict[str, Any], secret: str, timestamp: str | int | None, payload: dict[str, Any] | AdCPBaseModel, ) -> dict[str, Any]: """ Generate AdCP-compliant signed headers for webhook delivery. This function creates a cryptographic signature that proves the webhook came from an authorized agent and protects against replay attacks by including a timestamp in the signed message. The function adds two headers to the provided headers dict: - X-AdCP-Signature: HMAC-SHA256 signature in format "sha256=<hex_digest>" - X-AdCP-Timestamp: Unix timestamp in seconds The signing algorithm: 1. Constructs message as "{timestamp}.{json_payload}" 2. JSON-serializes payload with default separators (matches wire format from json= kwarg) 3. UTF-8 encodes the message 4. HMAC-SHA256 signs with the shared secret 5. Hex-encodes and prefixes with "sha256=" Args: headers: Existing headers dictionary to add signature headers to secret: Shared secret key for HMAC signing timestamp: Unix timestamp in seconds (str or int). If None, uses current time. payload: Webhook payload (dict or Pydantic model - will be JSON-serialized) Returns: The modified headers dictionary with signature headers added Examples: Sign and send an MCP webhook: >>> import time >>> from adcp.webhooks import create_mcp_webhook_payload >>> from adcp.webhooks import get_adcp_signed_headers_for_webhook >>> >>> payload = create_mcp_webhook_payload( ... task_id="task_123", ... task_type="get_products", ... status="completed", ... result={"products": [...]} ... ) >>> headers = {"Content-Type": "application/json"} >>> signed_headers = get_adcp_signed_headers_for_webhook( ... headers, secret="my-webhook-secret", timestamp=str(int(time.time())), ... payload=payload, ... ) >>> >>> # Send webhook with signed headers >>> import httpx >>> response = await httpx.post( ... webhook_url, ... json=payload, ... headers=signed_headers ... ) Headers will contain: >>> print(signed_headers) { "Content-Type": "application/json", "X-AdCP-Signature": "sha256=a1b2c3...", "X-AdCP-Timestamp": "1773185740" } """ # Default to current Unix time if not provided if timestamp is None: import time timestamp = str(int(time.time())) else: timestamp = str(timestamp) # Convert Pydantic model to dict if needed # All AdCP types inherit from AdCPBaseModel (Pydantic BaseModel) if hasattr(payload, "model_dump"): payload_dict = payload.model_dump(mode="json") else: payload_dict = payload # Serialize payload to JSON with default formatting (matches what json= kwarg sends on the wire) # This aligns with the JS reference implementation's JSON.stringify() behavior payload_json = json.dumps(payload_dict) # Construct signed message: timestamp.payload # Including timestamp prevents replay attacks signed_message = f"{timestamp}.{payload_json}" # Generate HMAC-SHA256 signature over timestamp + payload signature_hex = hmac.new( secret.encode("utf-8"), signed_message.encode("utf-8"), hashlib.sha256 ).hexdigest() # Add AdCP-compliant signature headers headers["X-AdCP-Signature"] = f"sha256={signature_hex}" headers["X-AdCP-Timestamp"] = timestamp return headersGenerate AdCP-compliant signed headers for webhook delivery.
This function creates a cryptographic signature that proves the webhook came from an authorized agent and protects against replay attacks by including a timestamp in the signed message.
The function adds two headers to the provided headers dict: - X-AdCP-Signature: HMAC-SHA256 signature in format "sha256=
" - X-AdCP-Timestamp: Unix timestamp in seconds The signing algorithm: 1. Constructs message as "{timestamp}.{json_payload}" 2. JSON-serializes payload with default separators (matches wire format from json= kwarg) 3. UTF-8 encodes the message 4. HMAC-SHA256 signs with the shared secret 5. Hex-encodes and prefixes with "sha256="
Args
headers- Existing headers dictionary to add signature headers to
secret- Shared secret key for HMAC signing
timestamp- Unix timestamp in seconds (str or int). If None, uses current time.
payload- Webhook payload (dict or Pydantic model - will be JSON-serialized)
Returns
The modified headers dictionary with signature headers added
Examples
Sign and send an MCP webhook:
>>> import time >>> from adcp.webhooks import create_mcp_webhook_payload >>> from adcp.webhooks import get_adcp_signed_headers_for_webhook >>> >>> payload = create_mcp_webhook_payload( ... task_id="task_123", ... task_type="get_products", ... status="completed", ... result={"products": [...]} ... ) >>> headers = {"Content-Type": "application/json"} >>> signed_headers = get_adcp_signed_headers_for_webhook( ... headers, secret="my-webhook-secret", timestamp=str(int(time.time())), ... payload=payload, ... ) >>> >>> # Send webhook with signed headers >>> import httpx >>> response = await httpx.post( ... webhook_url, ... json=payload, ... headers=signed_headers ... )Headers will contain:
>>> print(signed_headers) { "Content-Type": "application/json", "X-AdCP-Signature": "sha256=a1b2c3...", "X-AdCP-Timestamp": "1773185740" } def get_adcp_version() ‑> str-
Expand source code
def get_adcp_version() -> str: """ Get the target AdCP specification version this SDK is built for. This version determines which AdCP schemas are used for type generation and validation. The SDK is designed to work with this specific version of the AdCP specification. Returns: AdCP specification version (e.g., "2.5.0") Raises: FileNotFoundError: If ADCP_VERSION file is missing from package """ from importlib.resources import files # Read from ADCP_VERSION file in package version_file = files("adcp") / "ADCP_VERSION" return version_file.read_text().strip()Get the target AdCP specification version this SDK is built for.
This version determines which AdCP schemas are used for type generation and validation. The SDK is designed to work with this specific version of the AdCP specification.
Returns
AdCP specification version (e.g., "2.5.0")
Raises
FileNotFoundError- If ADCP_VERSION file is missing from package
def get_all_properties(adagents_data: dict[str, Any]) ‑> list[dict[str, typing.Any]]-
Expand source code
def get_all_properties(adagents_data: dict[str, Any]) -> list[dict[str, Any]]: """Extract all properties from adagents.json data. Args: adagents_data: Parsed adagents.json data Returns: List of all properties across all authorized agents, with agent_url added Raises: AdagentsValidationError: If adagents_data is malformed """ if not isinstance(adagents_data, dict): raise AdagentsValidationError("adagents_data must be a dictionary") authorized_agents = adagents_data.get("authorized_agents") if not isinstance(authorized_agents, list): raise AdagentsValidationError("adagents.json must have 'authorized_agents' array") properties = [] for agent in authorized_agents: if not isinstance(agent, dict): continue agent_url = agent.get("url", "") if not agent_url: continue agent_properties = agent.get("properties", []) if not isinstance(agent_properties, list): continue # Add each property with the agent URL for reference for prop in agent_properties: if isinstance(prop, dict): # Create a copy and add agent_url prop_with_agent = {**prop, "agent_url": agent_url} properties.append(prop_with_agent) return propertiesExtract all properties from adagents.json data.
Args
adagents_data- Parsed adagents.json data
Returns
List of all properties across all authorized agents, with agent_url added
Raises
AdagentsValidationError- If adagents_data is malformed
-
Expand source code
def get_all_tags(adagents_data: dict[str, Any]) -> set[str]: """Extract all unique tags from properties in adagents.json data. Args: adagents_data: Parsed adagents.json data Returns: Set of all unique tags across all properties Raises: AdagentsValidationError: If adagents_data is malformed """ properties = get_all_properties(adagents_data) tags = set() for prop in properties: prop_tags = prop.get("tags", []) if isinstance(prop_tags, list): for tag in prop_tags: if isinstance(tag, str): tags.add(tag) return tagsExtract all unique tags from properties in adagents.json data.
Args
adagents_data- Parsed adagents.json data
Returns
Set of all unique tags across all properties
Raises
AdagentsValidationError- If adagents_data is malformed
def get_asset_count(format: Format) ‑> int-
Expand source code
def get_asset_count(format: Format) -> int: """Get the count of assets in a format (for display purposes). Args: format: The Format object Returns: Number of assets, or 0 if none defined """ return len(get_format_assets(format))Get the count of assets in a format (for display purposes).
Args
format- The Format object
Returns
Number of assets, or 0 if none defined
def get_format_assets(format: Format) ‑> list[FormatAsset]-
Expand source code
def get_format_assets(format: Format) -> list[FormatAsset]: """Get assets from a Format. Returns the list of assets from the format's `assets` field. Returns empty list if no assets are defined (flexible format with no assets). Args: format: The Format object from list_creative_formats response Returns: List of assets Example: ```python formats = await agent.simple.list_creative_formats() for format in formats.formats: assets = get_format_assets(format) print(f"{format.name} has {len(assets)} assets") ``` """ if format.assets and len(format.assets) > 0: return list(format.assets) return []Get assets from a Format.
Returns the list of assets from the format's
assetsfield. Returns empty list if no assets are defined (flexible format with no assets).Args
format- The Format object from list_creative_formats response
Returns
List of assets
Example
formats = await agent.simple.list_creative_formats() for format in formats.formats: assets = get_format_assets(format) print(f"{format.name} has {len(assets)} assets") def get_individual_assets(format: Format) ‑> list[FormatAsset]-
Expand source code
def get_individual_assets(format: Format) -> list[FormatAsset]: """Get individual assets (not repeatable groups) from a Format. Args: format: The Format object Returns: List of individual assets (item_type='individual') """ return [asset for asset in get_format_assets(format) if _get_item_type(asset) == "individual"]Get individual assets (not repeatable groups) from a Format.
Args
format- The Format object
Returns
List of individual assets (item_type='individual')
def get_optional_assets(format: Format) ‑> list[FormatAsset]-
Expand source code
def get_optional_assets(format: Format) -> list[FormatAsset]: """Get only optional assets from a Format. Note: When using deprecated `assets_required`, this will always return empty since assets_required only contained required assets. Args: format: The Format object Returns: List of optional assets only Example: ```python optional_assets = get_optional_assets(format) print(f"Can optionally provide {len(optional_assets)} additional assets") ``` """ return [asset for asset in get_format_assets(format) if not _is_required(asset)]Get only optional assets from a Format.
Note: When using deprecated
assets_required, this will always return empty since assets_required only contained required assets.Args
format- The Format object
Returns
List of optional assets only
Example
optional_assets = get_optional_assets(format) print(f"Can optionally provide {len(optional_assets)} additional assets") def get_properties_by_agent(adagents_data: dict[str, Any], agent_url: str) ‑> list[dict[str, typing.Any]]-
Expand source code
def get_properties_by_agent(adagents_data: dict[str, Any], agent_url: str) -> list[dict[str, Any]]: """Get all properties authorized for a specific agent. Handles all authorization types per the AdCP specification: - inline_properties: Properties defined directly in the agent's properties array - property_ids: Filter top-level properties by property_id - property_tags: Filter top-level properties by tags - publisher_properties: References properties from other publisher domains (returns the selector objects, not resolved properties) Args: adagents_data: Parsed adagents.json data agent_url: URL of the agent to filter by Returns: List of properties for the specified agent (empty if agent not found) Raises: AdagentsValidationError: If adagents_data is malformed """ if not isinstance(adagents_data, dict): raise AdagentsValidationError("adagents_data must be a dictionary") authorized_agents = adagents_data.get("authorized_agents") if not isinstance(authorized_agents, list): raise AdagentsValidationError("adagents.json must have 'authorized_agents' array") # Get top-level properties for reference-based authorization types top_level_properties = adagents_data.get("properties", []) if not isinstance(top_level_properties, list): top_level_properties = [] # Normalize the agent URL for comparison normalized_agent_url = normalize_url(agent_url) for agent in authorized_agents: if not isinstance(agent, dict): continue agent_url_from_json = agent.get("url", "") if not agent_url_from_json: continue # Match agent URL (protocol-agnostic) if normalize_url(agent_url_from_json) != normalized_agent_url: continue # Found the agent - determine authorization type authorization_type = agent.get("authorization_type", "") # Handle inline_properties (properties array directly on agent) if authorization_type == "inline_properties" or "properties" in agent: properties = agent.get("properties", []) if not isinstance(properties, list): return [] return [p for p in properties if isinstance(p, dict)] # Handle property_ids (filter top-level properties by property_id) if authorization_type == "property_ids": authorized_ids = set(agent.get("property_ids", [])) return [ p for p in top_level_properties if isinstance(p, dict) and p.get("property_id") in authorized_ids ] # Handle property_tags (filter top-level properties by tags) if authorization_type == "property_tags": authorized_tags = set(agent.get("property_tags", [])) return [ p for p in top_level_properties if isinstance(p, dict) and set(p.get("tags", [])) & authorized_tags ] # Handle publisher_properties (cross-domain references) # Returns the selector objects; caller must resolve against other domains if authorization_type == "publisher_properties": publisher_props = agent.get("publisher_properties", []) if not isinstance(publisher_props, list): return [] return [p for p in publisher_props if isinstance(p, dict)] # No recognized authorization type - return empty return [] return []Get all properties authorized for a specific agent.
Handles all authorization types per the AdCP specification: - inline_properties: Properties defined directly in the agent's properties array - property_ids: Filter top-level properties by property_id - property_tags: Filter top-level properties by tags - publisher_properties: References properties from other publisher domains (returns the selector objects, not resolved properties)
Args
adagents_data- Parsed adagents.json data
agent_url- URL of the agent to filter by
Returns
List of properties for the specified agent (empty if agent not found)
Raises
AdagentsValidationError- If adagents_data is malformed
def get_repeatable_groups(format: Format) ‑> list[FormatAsset]-
Expand source code
def get_repeatable_groups(format: Format) -> list[FormatAsset]: """Get repeatable asset groups from a Format. Args: format: The Format object Returns: List of repeatable asset groups (item_type='repeatable_group') """ return [ asset for asset in get_format_assets(format) if _get_item_type(asset) == "repeatable_group" ]Get repeatable asset groups from a Format.
Args
format- The Format object
Returns
List of repeatable asset groups (item_type='repeatable_group')
def get_required_assets(format: Format) ‑> list[FormatAsset]-
Expand source code
def get_required_assets(format: Format) -> list[FormatAsset]: """Get only required assets from a Format. Args: format: The Format object Returns: List of required assets only Example: ```python required_assets = get_required_assets(format) print(f"Must provide {len(required_assets)} assets") ``` """ return [asset for asset in get_format_assets(format) if _is_required(asset)]Get only required assets from a Format.
Args
format- The Format object
Returns
List of required assets only
Example
required_assets = get_required_assets(format) print(f"Must provide {len(required_assets)} assets") def has_assets(format: Format) ‑> bool-
Expand source code
def has_assets(format: Format) -> bool: """Check if a format has any assets defined. Args: format: The Format object Returns: True if format has assets, False otherwise """ return get_asset_count(format) > 0Check if a format has any assets defined.
Args
format- The Format object
Returns
True if format has assets, False otherwise
def identifiers_match(property_identifiers: list[dict[str, str]],
agent_identifiers: list[dict[str, str]]) ‑> bool-
Expand source code
def identifiers_match( property_identifiers: list[dict[str, str]], agent_identifiers: list[dict[str, str]], ) -> bool: """Check if any property identifier matches agent's authorized identifiers. Args: property_identifiers: Identifiers from property (e.g., [{"type": "domain", "value": "cnn.com"}]) agent_identifiers: Identifiers from adagents.json Returns: True if any identifier matches Notes: - Domain identifiers use AdCP domain matching rules - Other identifiers (bundle_id, roku_store_id, etc.) require exact match """ for prop_id in property_identifiers: prop_type = prop_id.get("type", "") prop_value = prop_id.get("value", "") for agent_id in agent_identifiers: agent_type = agent_id.get("type", "") agent_value = agent_id.get("value", "") # Type must match if prop_type != agent_type: continue # Domain identifiers use special matching rules if prop_type == "domain": if domain_matches(prop_value, agent_value): return True else: # Other identifier types require exact match if prop_value == agent_value: return True return FalseCheck if any property identifier matches agent's authorized identifiers.
Args
property_identifiers- Identifiers from property (e.g., [{"type": "domain", "value": "cnn.com"}])
agent_identifiers- Identifiers from adagents.json
Returns
True if any identifier matches
Notes
- Domain identifiers use AdCP domain matching rules
- Other identifiers (bundle_id, roku_store_id, etc.) require exact match
def normalize_assets_required(assets_required: list[Any]) ‑> list[typing.Any]-
Expand source code
def normalize_assets_required(assets_required: list[Any]) -> list[FormatAsset]: """Convert deprecated assets_required to new assets format. .. deprecated:: 3.2.0 The ``assets_required`` field was removed in ADCP 3.0.0-beta.2. This function will be removed in a future version. All assets in assets_required are required by definition (that's why they were in that array). The new `assets` field has an explicit `required: boolean` to allow both required AND optional assets. Args: assets_required: The deprecated assets_required array Returns: Normalized assets as Pydantic models with explicit required=True """ warnings.warn( "normalize_assets_required() is deprecated. " "The assets_required field was removed in ADCP 3.0.0-beta.2. " "This function will be removed in a future version.", DeprecationWarning, stacklevel=2, ) normalized: list[FormatAsset] = [] for asset in assets_required: # Get asset data as dict if isinstance(asset, dict): asset_dict = asset else: asset_dict = asset.model_dump() if hasattr(asset, "model_dump") else dict(asset) # Map old fields to new schema format mapped = {**asset_dict, "required": True} # Ensure asset_id is present (map from asset_group_id if needed) if "asset_group_id" in mapped and "asset_id" not in mapped: mapped["asset_id"] = mapped.pop("asset_group_id") # Remove fields that don't exist in the new schema for old_field in ("min_count", "max_count", "assets"): mapped.pop(old_field, None) # Use AssetsModel (individual asset type) normalized.append(AssetsModel(**mapped)) return normalizedConvert deprecated assets_required to new assets format.
Deprecated since version: 3.2.0
The
assets_requiredfield was removed in ADCP 3.0.0-beta.2. This function will be removed in a future version.All assets in assets_required are required by definition (that's why they were in that array). The new
assetsfield has an explicitrequired: booleanto allow both required AND optional assets.Args
assets_required- The deprecated assets_required array
Returns
Normalized assets as Pydantic models with explicit required=True
def uses_deprecated_assets_field(format: Format) ‑> bool-
Expand source code
def uses_deprecated_assets_field(format: Format) -> bool: """Check if format uses deprecated assets_required field. .. deprecated:: 3.2.0 The ``assets_required`` field was removed in ADCP 3.0.0-beta.2. This function always returns False and will be removed in a future version. Args: format: The Format object Returns: Always False (deprecated field no longer exists) """ warnings.warn( "uses_deprecated_assets_field() is deprecated and always returns False. " "The assets_required field was removed in ADCP 3.0.0-beta.2. " "This function will be removed in a future version.", DeprecationWarning, stacklevel=2, ) return FalseCheck if format uses deprecated assets_required field.
Deprecated since version: 3.2.0
The
assets_requiredfield was removed in ADCP 3.0.0-beta.2. This function always returns False and will be removed in a future version.Args
format- The Format object
Returns
Always False (deprecated field no longer exists)
def validate_adagents(adagents: dict[str, Any]) ‑> None-
Expand source code
def validate_adagents(adagents: dict[str, Any]) -> None: """Validate an adagents.json structure. Args: adagents: The adagents.json dict Raises: ValidationError: If validation fails """ if "agents" in adagents: for agent in adagents["agents"]: validate_agent_authorization(agent)Validate an adagents.json structure.
Args
adagents- The adagents.json dict
Raises
ValidationError- If validation fails
-
Expand source code
def validate_agent_authorization(agent: dict[str, Any]) -> None: """Validate agent authorization discriminated union. AdCP v2.4.0+ uses discriminated unions with authorization_type discriminator: - authorization_type: "property_ids" requires property_ids - authorization_type: "property_tags" requires property_tags - authorization_type: "inline_properties" requires properties - authorization_type: "publisher_properties" requires publisher_properties For backward compatibility, also validates the old mutual exclusivity constraint. Args: agent: An agent dict from adagents.json Raises: ValidationError: If discriminator or field constraints are violated """ authorization_type = agent.get("authorization_type") auth_fields = ["properties", "property_ids", "property_tags", "publisher_properties"] present_fields = [field for field in auth_fields if field in agent and agent[field] is not None] # If authorization_type discriminator is present, validate discriminated union if authorization_type: if authorization_type == "property_ids" and "property_ids" not in present_fields: raise ValidationError( "Agent with authorization_type='property_ids' must have property_ids" ) elif authorization_type == "property_tags" and "property_tags" not in present_fields: raise ValidationError( "Agent with authorization_type='property_tags' must have property_tags" ) elif authorization_type == "inline_properties" and "properties" not in present_fields: raise ValidationError( "Agent with authorization_type='inline_properties' must have properties" ) elif ( authorization_type == "publisher_properties" and "publisher_properties" not in present_fields ): raise ValidationError( "Agent with authorization_type='publisher_properties' " "must have publisher_properties" ) elif authorization_type not in ( "property_ids", "property_tags", "inline_properties", "publisher_properties", ): raise ValidationError(f"Agent has invalid authorization_type: {authorization_type}") # Validate mutual exclusivity (for both old and new formats) if len(present_fields) > 1: raise ValidationError( f"Agent authorization cannot have multiple fields: {', '.join(present_fields)}. " f"Only one of {', '.join(auth_fields)} is allowed." ) if len(present_fields) == 0: raise ValidationError( f"Agent authorization must have exactly one of: {', '.join(auth_fields)}." ) # If using publisher_properties, validate each item if "publisher_properties" in present_fields: for pub_prop in agent["publisher_properties"]: validate_publisher_properties_item(pub_prop)Validate agent authorization discriminated union.
AdCP v2.4.0+ uses discriminated unions with authorization_type discriminator: - authorization_type: "property_ids" requires property_ids - authorization_type: "property_tags" requires property_tags - authorization_type: "inline_properties" requires properties - authorization_type: "publisher_properties" requires publisher_properties
For backward compatibility, also validates the old mutual exclusivity constraint.
Args
agent- An agent dict from adagents.json
Raises
ValidationError- If discriminator or field constraints are violated
def validate_capabilities(handler: Any, capabilities: GetAdcpCapabilitiesResponse) ‑> list[str]-
Expand source code
def validate_capabilities( handler: Any, capabilities: GetAdcpCapabilitiesResponse, ) -> list[str]: """Check that a handler implements the methods required by its declared features. Compares the features declared in a capabilities response against the handler's method implementations. Returns warnings for features that are declared but whose corresponding handler methods are not overridden from the base class. This is a development-time check — call it at startup to catch misconfigurations. Args: handler: An ADCPHandler instance (or any object with handler methods). capabilities: The capabilities response the handler will serve. Returns: List of warning strings. Empty if everything is consistent. """ # Late import to avoid circular dependency: server.base imports from adcp.types # which may transitively import from this module. from adcp.server.base import ADCPHandler resolver = FeatureResolver(capabilities) warnings: list[str] = [] for feature, handler_methods in FEATURE_HANDLER_MAP.items(): if not resolver.supports(feature): continue for method_name in handler_methods: if not hasattr(handler, method_name): warnings.append( f"Feature '{feature}' is declared but handler has no " f"'{method_name}' method" ) continue # Walk MRO to check if any class between the leaf and ADCPHandler # overrides the method (handles mixin / intermediate-class patterns). if isinstance(handler, ADCPHandler): overridden = any( method_name in cls.__dict__ for cls in type(handler).__mro__ if cls is not ADCPHandler and not issubclass(ADCPHandler, cls) ) if not overridden: warnings.append( f"Feature '{feature}' is declared but '{method_name}' " f"is not overridden from ADCPHandler" ) return warningsCheck that a handler implements the methods required by its declared features.
Compares the features declared in a capabilities response against the handler's method implementations. Returns warnings for features that are declared but whose corresponding handler methods are not overridden from the base class.
This is a development-time check — call it at startup to catch misconfigurations.
Args
handler- An ADCPHandler instance (or any object with handler methods).
capabilities- The capabilities response the handler will serve.
Returns
List of warning strings. Empty if everything is consistent.
def validate_product(product: dict[str, Any]) ‑> None-
Expand source code
def validate_product(product: dict[str, Any]) -> None: """Validate a Product object. Args: product: Product dict Raises: ValidationError: If validation fails """ if "publisher_properties" in product and product["publisher_properties"]: for item in product["publisher_properties"]: validate_publisher_properties_item(item) def validate_publisher_properties_item(item: dict[str, Any]) ‑> None-
Expand source code
def validate_publisher_properties_item(item: dict[str, Any]) -> None: """Validate publisher_properties item discriminated union. AdCP v2.4.0+ uses discriminated unions with selection_type discriminator: - selection_type: "by_id" requires property_ids - selection_type: "by_tag" requires property_tags For backward compatibility, also validates the old mutual exclusivity constraint. Args: item: A single item from publisher_properties array Raises: ValidationError: If discriminator or field constraints are violated """ selection_type = item.get("selection_type") has_property_ids = "property_ids" in item and item["property_ids"] is not None has_property_tags = "property_tags" in item and item["property_tags"] is not None # If selection_type discriminator is present, validate discriminated union if selection_type: if selection_type == "by_id" and not has_property_ids: raise ValidationError( "publisher_properties item with selection_type='by_id' must have property_ids" ) elif selection_type == "by_tag" and not has_property_tags: raise ValidationError( "publisher_properties item with selection_type='by_tag' must have property_tags" ) elif selection_type not in ("by_id", "by_tag"): raise ValidationError( f"publisher_properties item has invalid selection_type: {selection_type}" ) # Validate mutual exclusivity (for both old and new formats) if has_property_ids and has_property_tags: raise ValidationError( "publisher_properties item cannot have both property_ids and property_tags. " "These fields are mutually exclusive." ) if not has_property_ids and not has_property_tags: raise ValidationError( "publisher_properties item must have either property_ids or property_tags. " "At least one is required." )Validate publisher_properties item discriminated union.
AdCP v2.4.0+ uses discriminated unions with selection_type discriminator: - selection_type: "by_id" requires property_ids - selection_type: "by_tag" requires property_tags
For backward compatibility, also validates the old mutual exclusivity constraint.
Args
item- A single item from publisher_properties array
Raises
ValidationError- If discriminator or field constraints are violated
-
Expand source code
def verify_agent_authorization( adagents_data: dict[str, Any], agent_url: str, property_type: str | None = None, property_identifiers: list[dict[str, str]] | None = None, ) -> bool: """Check if agent is authorized for a property. Args: adagents_data: Parsed adagents.json data agent_url: URL of the sales agent to verify property_type: Type of property (website, app, etc.) - optional property_identifiers: List of identifiers to match - optional Returns: True if agent is authorized, False otherwise Raises: AdagentsValidationError: If adagents_data is malformed Notes: - If property_type/identifiers are None, checks if agent is authorized for ANY property on this domain - Implements AdCP domain matching rules - Agent URLs are matched ignoring protocol and trailing slash """ # Validate structure if not isinstance(adagents_data, dict): raise AdagentsValidationError("adagents_data must be a dictionary") authorized_agents = adagents_data.get("authorized_agents") if not isinstance(authorized_agents, list): raise AdagentsValidationError("adagents.json must have 'authorized_agents' array") # Normalize the agent URL for comparison normalized_agent_url = normalize_url(agent_url) # Check each authorized agent for agent in authorized_agents: if not isinstance(agent, dict): continue agent_url_from_json = agent.get("url", "") if not agent_url_from_json: continue # Match agent URL (protocol-agnostic) if normalize_url(agent_url_from_json) != normalized_agent_url: continue # Found matching agent - now check properties properties = agent.get("properties") # If properties field is missing or empty, agent is authorized for all properties if properties is None or (isinstance(properties, list) and len(properties) == 0): return True # If no property filters specified, we found the agent - authorized if property_type is None and property_identifiers is None: return True # Check specific property authorization if isinstance(properties, list): for prop in properties: if not isinstance(prop, dict): continue # Check property type if specified if property_type is not None: prop_type = prop.get("property_type", "") if prop_type != property_type: continue # Check identifiers if specified if property_identifiers is not None: prop_identifiers = prop.get("identifiers", []) if not isinstance(prop_identifiers, list): continue if identifiers_match(property_identifiers, prop_identifiers): return True else: # Property type matched and no identifier check needed return True return FalseCheck if agent is authorized for a property.
Args
adagents_data- Parsed adagents.json data
agent_url- URL of the sales agent to verify
property_type- Type of property (website, app, etc.) - optional
property_identifiers- List of identifiers to match - optional
Returns
True if agent is authorized, False otherwise
Raises
AdagentsValidationError- If adagents_data is malformed
Notes
- If property_type/identifiers are None, checks if agent is authorized for ANY property on this domain
- Implements AdCP domain matching rules
- Agent URLs are matched ignoring protocol and trailing slash
async def verify_agent_for_property(publisher_domain: str,
agent_url: str,
property_identifiers: list[dict[str, str]],
property_type: str | None = None,
timeout: float = 10.0,
client: httpx.AsyncClient | None = None) ‑> bool-
Expand source code
async def verify_agent_for_property( publisher_domain: str, agent_url: str, property_identifiers: list[dict[str, str]], property_type: str | None = None, timeout: float = 10.0, client: httpx.AsyncClient | None = None, ) -> bool: """Convenience wrapper to fetch adagents.json and verify authorization in one call. Args: publisher_domain: Domain hosting the adagents.json file agent_url: URL of the sales agent to verify property_identifiers: List of identifiers to match property_type: Type of property (website, app, etc.) - optional timeout: Request timeout in seconds client: Optional httpx.AsyncClient for connection pooling Returns: True if agent is authorized, False otherwise Raises: AdagentsNotFoundError: If adagents.json not found (404) AdagentsValidationError: If JSON is invalid or malformed AdagentsTimeoutError: If request times out """ adagents_data = await fetch_adagents(publisher_domain, timeout=timeout, client=client) return verify_agent_authorization( adagents_data=adagents_data, agent_url=agent_url, property_type=property_type, property_identifiers=property_identifiers, )Convenience wrapper to fetch adagents.json and verify authorization in one call.
Args
publisher_domain- Domain hosting the adagents.json file
agent_url- URL of the sales agent to verify
property_identifiers- List of identifiers to match
property_type- Type of property (website, app, etc.) - optional
timeout- Request timeout in seconds
client- Optional httpx.AsyncClient for connection pooling
Returns
True if agent is authorized, False otherwise
Raises
AdagentsNotFoundError- If adagents.json not found (404)
AdagentsValidationError- If JSON is invalid or malformed
AdagentsTimeoutError- If request times out
Classes
class ADCPAuthenticationError (message: str, agent_id: str | None = None, agent_uri: str | None = None)-
Expand source code
class ADCPAuthenticationError(ADCPError): """Authentication failed (401, 403).""" def __init__(self, message: str, agent_id: str | None = None, agent_uri: str | None = None): """Initialize authentication error.""" suggestion = ( "Check that your auth_token is valid and not expired.\n" " Verify auth_type ('bearer' vs 'token') and auth_header are correct.\n" " Some agents (like Optable) require auth_type='bearer' and " "auth_header='Authorization'" ) super().__init__(message, agent_id, agent_uri, suggestion)Authentication failed (401, 403).
Initialize authentication error.
Ancestors
- ADCPError
- builtins.Exception
- builtins.BaseException
class ADCPClient (agent_config: AgentConfig,
webhook_url_template: str | None = None,
webhook_secret: str | None = None,
on_activity: Callable[[Activity], None] | None = None,
webhook_timestamp_tolerance: int = 300,
capabilities_ttl: float = 3600.0,
validate_features: bool = False)-
Expand source code
class ADCPClient: """Client for interacting with a single AdCP agent.""" def __init__( self, agent_config: AgentConfig, webhook_url_template: str | None = None, webhook_secret: str | None = None, on_activity: Callable[[Activity], None] | None = None, webhook_timestamp_tolerance: int = 300, capabilities_ttl: float = 3600.0, validate_features: bool = False, ): """ Initialize ADCP client for a single agent. Args: agent_config: Agent configuration webhook_url_template: Template for webhook URLs with {agent_id}, {task_type}, {operation_id} webhook_secret: Secret for webhook signature verification on_activity: Callback for activity events webhook_timestamp_tolerance: Maximum age (in seconds) for webhook timestamps. Webhooks with timestamps older than this or more than this far in the future are rejected. Defaults to 300 (5 minutes). capabilities_ttl: Time-to-live in seconds for cached capabilities (default: 1 hour) validate_features: When True, automatically check that the seller supports required features before making task calls (e.g., sync_audiences requires audience_targeting). Requires capabilities to have been fetched first. """ self.agent_config = agent_config self.webhook_url_template = webhook_url_template self.webhook_secret = webhook_secret self.on_activity = on_activity self.webhook_timestamp_tolerance = webhook_timestamp_tolerance self.capabilities_ttl = capabilities_ttl self.validate_features = validate_features # Capabilities cache self._capabilities: GetAdcpCapabilitiesResponse | None = None self._feature_resolver: FeatureResolver | None = None self._capabilities_fetched_at: float | None = None # Initialize protocol adapter self.adapter: ProtocolAdapter if agent_config.protocol == Protocol.A2A: self.adapter = A2AAdapter(agent_config) elif agent_config.protocol == Protocol.MCP: self.adapter = MCPAdapter(agent_config) else: raise ValueError(f"Unsupported protocol: {agent_config.protocol}") # Initialize simple API accessor (lazy import to avoid circular dependency) from adcp.simple import SimpleAPI self.simple = SimpleAPI(self) def get_webhook_url(self, task_type: str, operation_id: str) -> str: """Generate webhook URL for a task.""" if not self.webhook_url_template: raise ValueError("webhook_url_template not configured") return self.webhook_url_template.format( agent_id=self.agent_config.id, task_type=task_type, operation_id=operation_id, ) def _emit_activity(self, activity: Activity) -> None: """Emit activity event.""" if self.on_activity: self.on_activity(activity) # ======================================================================== # Capability Validation # ======================================================================== @property def capabilities(self) -> GetAdcpCapabilitiesResponse | None: """Return cached capabilities, or None if not yet fetched.""" return self._capabilities @property def feature_resolver(self) -> FeatureResolver | None: """Return the FeatureResolver for cached capabilities, or None.""" return self._feature_resolver async def fetch_capabilities(self) -> GetAdcpCapabilitiesResponse: """Fetch capabilities, using cache if still valid. Returns: The seller's capabilities response. """ if self._capabilities is not None and self._capabilities_fetched_at is not None: elapsed = time.monotonic() - self._capabilities_fetched_at if elapsed < self.capabilities_ttl: return self._capabilities return await self.refresh_capabilities() async def refresh_capabilities(self) -> GetAdcpCapabilitiesResponse: """Fetch capabilities from the seller, bypassing cache. Returns: The seller's capabilities response. """ result = await self.get_adcp_capabilities(GetAdcpCapabilitiesRequest()) if result.success and result.data is not None: self._capabilities = result.data self._feature_resolver = FeatureResolver(result.data) self._capabilities_fetched_at = time.monotonic() return self._capabilities raise ADCPError( f"Failed to fetch capabilities: {result.error or result.message}", agent_id=self.agent_config.id, agent_uri=self.agent_config.agent_uri, ) def _ensure_resolver(self) -> FeatureResolver: """Return the FeatureResolver, raising if capabilities haven't been fetched.""" if self._feature_resolver is None: raise ADCPError( "Cannot check feature support: capabilities have not been fetched. " "Call fetch_capabilities() first.", agent_id=self.agent_config.id, agent_uri=self.agent_config.agent_uri, ) return self._feature_resolver def supports(self, feature: str) -> bool: """Check if the seller supports a feature. Supports multiple feature namespaces: - Protocol support: ``supports("media_buy")`` checks ``supported_protocols`` - Extension support: ``supports("ext:scope3")`` checks ``extensions_supported`` - Targeting: ``supports("targeting.geo_countries")`` checks ``media_buy.execution.targeting`` - Media buy features: ``supports("audience_targeting")`` checks ``media_buy.features`` - Signals features: ``supports("catalog_signals")`` checks ``signals.features`` Args: feature: Feature identifier to check. Returns: True if the seller declares the feature as supported. Raises: ADCPError: If capabilities have not been fetched yet. """ return self._ensure_resolver().supports(feature) def require(self, *features: str) -> None: """Assert that the seller supports all listed features. Args: *features: Feature identifiers to require. Raises: ADCPFeatureUnsupportedError: If any features are not supported. ADCPError: If capabilities have not been fetched yet. """ self._ensure_resolver().require( *features, agent_id=self.agent_config.id, agent_uri=self.agent_config.agent_uri, ) def _validate_task_features(self, task_name: str) -> None: """Check feature requirements for a task if validate_features is enabled. Returns without checking if validate_features is False or capabilities haven't been fetched yet (logs a warning in the latter case). """ if not self.validate_features: return if self._feature_resolver is None: logger.warning( "validate_features is enabled but capabilities have not been fetched. " "Call fetch_capabilities() to enable feature validation." ) return required_feature = TASK_FEATURE_MAP.get(task_name) if required_feature is None: return self.require(required_feature) async def get_products( self, request: GetProductsRequest, fetch_previews: bool = False, preview_output_format: str = "url", creative_agent_client: ADCPClient | None = None, ) -> TaskResult[GetProductsResponse]: """ Get advertising products. Args: request: Request parameters fetch_previews: If True, generate preview URLs for each product's formats (uses batch API for 5-10x performance improvement) preview_output_format: "url" for iframe URLs (default), "html" for direct embedding (2-3x faster, no iframe overhead) creative_agent_client: Client for creative agent (required if fetch_previews=True) Returns: TaskResult containing GetProductsResponse with optional preview URLs in metadata Raises: ValueError: If fetch_previews=True but creative_agent_client is not provided """ if fetch_previews and not creative_agent_client: raise ValueError("creative_agent_client is required when fetch_previews=True") operation_id = create_operation_id() params = request.model_dump(mode="json", exclude_none=True) self._emit_activity( Activity( type=ActivityType.PROTOCOL_REQUEST, operation_id=operation_id, agent_id=self.agent_config.id, task_type="get_products", timestamp=datetime.now(timezone.utc).isoformat(), ) ) raw_result = await self.adapter.get_products(params) self._emit_activity( Activity( type=ActivityType.PROTOCOL_RESPONSE, operation_id=operation_id, agent_id=self.agent_config.id, task_type="get_products", status=raw_result.status, timestamp=datetime.now(timezone.utc).isoformat(), ) ) result: TaskResult[GetProductsResponse] = self.adapter._parse_response( raw_result, GetProductsResponse ) if fetch_previews and result.success and result.data and creative_agent_client: from adcp.utils.preview_cache import add_preview_urls_to_products products_with_previews = await add_preview_urls_to_products( result.data.products, creative_agent_client, use_batch=True, output_format=preview_output_format, ) result.metadata = result.metadata or {} result.metadata["products_with_previews"] = products_with_previews return result async def list_creative_formats( self, request: ListCreativeFormatsRequest, fetch_previews: bool = False, preview_output_format: str = "url", ) -> TaskResult[ListCreativeFormatsResponse]: """ List supported creative formats. Args: request: Request parameters fetch_previews: If True, generate preview URLs for each format using sample manifests (uses batch API for 5-10x performance improvement) preview_output_format: "url" for iframe URLs (default), "html" for direct embedding (2-3x faster, no iframe overhead) Returns: TaskResult containing ListCreativeFormatsResponse with optional preview URLs in metadata """ operation_id = create_operation_id() params = request.model_dump(mode="json", exclude_none=True) self._emit_activity( Activity( type=ActivityType.PROTOCOL_REQUEST, operation_id=operation_id, agent_id=self.agent_config.id, task_type="list_creative_formats", timestamp=datetime.now(timezone.utc).isoformat(), ) ) raw_result = await self.adapter.list_creative_formats(params) self._emit_activity( Activity( type=ActivityType.PROTOCOL_RESPONSE, operation_id=operation_id, agent_id=self.agent_config.id, task_type="list_creative_formats", status=raw_result.status, timestamp=datetime.now(timezone.utc).isoformat(), ) ) result: TaskResult[ListCreativeFormatsResponse] = self.adapter._parse_response( raw_result, ListCreativeFormatsResponse ) if fetch_previews and result.success and result.data: from adcp.utils.preview_cache import add_preview_urls_to_formats formats_with_previews = await add_preview_urls_to_formats( result.data.formats, self, use_batch=True, output_format=preview_output_format, ) result.metadata = result.metadata or {} result.metadata["formats_with_previews"] = formats_with_previews return result async def preview_creative( self, request: PreviewCreativeRequest, ) -> TaskResult[PreviewCreativeResponse]: """ Generate preview of a creative manifest. Args: request: Request parameters Returns: TaskResult containing PreviewCreativeResponse with preview URLs """ operation_id = create_operation_id() params = request.model_dump(mode="json", exclude_none=True) self._emit_activity( Activity( type=ActivityType.PROTOCOL_REQUEST, operation_id=operation_id, agent_id=self.agent_config.id, task_type="preview_creative", timestamp=datetime.now(timezone.utc).isoformat(), ) ) raw_result = await self.adapter.preview_creative(params) self._emit_activity( Activity( type=ActivityType.PROTOCOL_RESPONSE, operation_id=operation_id, agent_id=self.agent_config.id, task_type="preview_creative", status=raw_result.status, timestamp=datetime.now(timezone.utc).isoformat(), ) ) return self.adapter._parse_response(raw_result, PreviewCreativeResponse) async def sync_creatives( self, request: SyncCreativesRequest, ) -> TaskResult[SyncCreativesResponse]: """ Sync Creatives. Args: request: Request parameters Returns: TaskResult containing SyncCreativesResponse """ operation_id = create_operation_id() params = request.model_dump(mode="json", exclude_none=True) self._emit_activity( Activity( type=ActivityType.PROTOCOL_REQUEST, operation_id=operation_id, agent_id=self.agent_config.id, task_type="sync_creatives", timestamp=datetime.now(timezone.utc).isoformat(), ) ) raw_result = await self.adapter.sync_creatives(params) self._emit_activity( Activity( type=ActivityType.PROTOCOL_RESPONSE, operation_id=operation_id, agent_id=self.agent_config.id, task_type="sync_creatives", status=raw_result.status, timestamp=datetime.now(timezone.utc).isoformat(), ) ) return self.adapter._parse_response(raw_result, SyncCreativesResponse) async def list_creatives( self, request: ListCreativesRequest, ) -> TaskResult[ListCreativesResponse]: """ List Creatives. Args: request: Request parameters Returns: TaskResult containing ListCreativesResponse """ operation_id = create_operation_id() params = request.model_dump(mode="json", exclude_none=True) self._emit_activity( Activity( type=ActivityType.PROTOCOL_REQUEST, operation_id=operation_id, agent_id=self.agent_config.id, task_type="list_creatives", timestamp=datetime.now(timezone.utc).isoformat(), ) ) raw_result = await self.adapter.list_creatives(params) self._emit_activity( Activity( type=ActivityType.PROTOCOL_RESPONSE, operation_id=operation_id, agent_id=self.agent_config.id, task_type="list_creatives", status=raw_result.status, timestamp=datetime.now(timezone.utc).isoformat(), ) ) return self.adapter._parse_response(raw_result, ListCreativesResponse) async def get_media_buy_delivery( self, request: GetMediaBuyDeliveryRequest, ) -> TaskResult[GetMediaBuyDeliveryResponse]: """ Get Media Buy Delivery. Args: request: Request parameters Returns: TaskResult containing GetMediaBuyDeliveryResponse """ operation_id = create_operation_id() params = request.model_dump(mode="json", exclude_none=True) self._emit_activity( Activity( type=ActivityType.PROTOCOL_REQUEST, operation_id=operation_id, agent_id=self.agent_config.id, task_type="get_media_buy_delivery", timestamp=datetime.now(timezone.utc).isoformat(), ) ) raw_result = await self.adapter.get_media_buy_delivery(params) self._emit_activity( Activity( type=ActivityType.PROTOCOL_RESPONSE, operation_id=operation_id, agent_id=self.agent_config.id, task_type="get_media_buy_delivery", status=raw_result.status, timestamp=datetime.now(timezone.utc).isoformat(), ) ) return self.adapter._parse_response(raw_result, GetMediaBuyDeliveryResponse) async def get_media_buys( self, request: GetMediaBuysRequest, ) -> TaskResult[GetMediaBuysResponse]: """ Get Media Buys. Args: request: Request parameters Returns: TaskResult containing GetMediaBuysResponse """ operation_id = create_operation_id() params = request.model_dump(mode="json", exclude_none=True) self._emit_activity( Activity( type=ActivityType.PROTOCOL_REQUEST, operation_id=operation_id, agent_id=self.agent_config.id, task_type="get_media_buys", timestamp=datetime.now(timezone.utc).isoformat(), ) ) raw_result = await self.adapter.get_media_buys(params) self._emit_activity( Activity( type=ActivityType.PROTOCOL_RESPONSE, operation_id=operation_id, agent_id=self.agent_config.id, task_type="get_media_buys", status=raw_result.status, timestamp=datetime.now(timezone.utc).isoformat(), ) ) return self.adapter._parse_response(raw_result, GetMediaBuysResponse) async def get_signals( self, request: GetSignalsRequest, ) -> TaskResult[GetSignalsResponse]: """ Get Signals. Args: request: Request parameters Returns: TaskResult containing GetSignalsResponse """ operation_id = create_operation_id() params = request.model_dump(mode="json", exclude_none=True) self._emit_activity( Activity( type=ActivityType.PROTOCOL_REQUEST, operation_id=operation_id, agent_id=self.agent_config.id, task_type="get_signals", timestamp=datetime.now(timezone.utc).isoformat(), ) ) raw_result = await self.adapter.get_signals(params) self._emit_activity( Activity( type=ActivityType.PROTOCOL_RESPONSE, operation_id=operation_id, agent_id=self.agent_config.id, task_type="get_signals", status=raw_result.status, timestamp=datetime.now(timezone.utc).isoformat(), ) ) return self.adapter._parse_response(raw_result, GetSignalsResponse) async def activate_signal( self, request: ActivateSignalRequest, ) -> TaskResult[ActivateSignalResponse]: """ Activate Signal. Args: request: Request parameters Returns: TaskResult containing ActivateSignalResponse """ operation_id = create_operation_id() params = request.model_dump(mode="json", exclude_none=True) self._emit_activity( Activity( type=ActivityType.PROTOCOL_REQUEST, operation_id=operation_id, agent_id=self.agent_config.id, task_type="activate_signal", timestamp=datetime.now(timezone.utc).isoformat(), ) ) raw_result = await self.adapter.activate_signal(params) self._emit_activity( Activity( type=ActivityType.PROTOCOL_RESPONSE, operation_id=operation_id, agent_id=self.agent_config.id, task_type="activate_signal", status=raw_result.status, timestamp=datetime.now(timezone.utc).isoformat(), ) ) return self.adapter._parse_response(raw_result, ActivateSignalResponse) async def provide_performance_feedback( self, request: ProvidePerformanceFeedbackRequest, ) -> TaskResult[ProvidePerformanceFeedbackResponse]: """ Provide Performance Feedback. Args: request: Request parameters Returns: TaskResult containing ProvidePerformanceFeedbackResponse """ operation_id = create_operation_id() params = request.model_dump(mode="json", exclude_none=True) self._emit_activity( Activity( type=ActivityType.PROTOCOL_REQUEST, operation_id=operation_id, agent_id=self.agent_config.id, task_type="provide_performance_feedback", timestamp=datetime.now(timezone.utc).isoformat(), ) ) raw_result = await self.adapter.provide_performance_feedback(params) self._emit_activity( Activity( type=ActivityType.PROTOCOL_RESPONSE, operation_id=operation_id, agent_id=self.agent_config.id, task_type="provide_performance_feedback", status=raw_result.status, timestamp=datetime.now(timezone.utc).isoformat(), ) ) return self.adapter._parse_response(raw_result, ProvidePerformanceFeedbackResponse) async def create_media_buy( self, request: CreateMediaBuyRequest, ) -> TaskResult[CreateMediaBuyResponse]: """ Create a new media buy reservation. Requests the agent to reserve inventory for a campaign. The agent returns a media_buy_id that tracks this reservation and can be used for updates. Args: request: Media buy creation parameters including: - brand_manifest: Advertiser brand information and creative assets - packages: List of package requests specifying desired inventory - publisher_properties: Target properties for ad placement - budget: Optional budget constraints - start_date/end_date: Campaign flight dates Returns: TaskResult containing CreateMediaBuyResponse with: - media_buy_id: Unique identifier for this reservation - status: Current state of the media buy - packages: Confirmed package details - Additional platform-specific metadata Example: >>> from adcp import ADCPClient, CreateMediaBuyRequest >>> client = ADCPClient(agent_config) >>> request = CreateMediaBuyRequest( ... brand_manifest=brand, ... packages=[package_request], ... publisher_properties=properties ... ) >>> result = await client.create_media_buy(request) >>> if result.success: ... media_buy_id = result.data.media_buy_id """ operation_id = create_operation_id() params = request.model_dump(mode="json", exclude_none=True) self._emit_activity( Activity( type=ActivityType.PROTOCOL_REQUEST, operation_id=operation_id, agent_id=self.agent_config.id, task_type="create_media_buy", timestamp=datetime.now(timezone.utc).isoformat(), ) ) raw_result = await self.adapter.create_media_buy(params) self._emit_activity( Activity( type=ActivityType.PROTOCOL_RESPONSE, operation_id=operation_id, agent_id=self.agent_config.id, task_type="create_media_buy", status=raw_result.status, timestamp=datetime.now(timezone.utc).isoformat(), ) ) return self.adapter._parse_response(raw_result, CreateMediaBuyResponse) async def update_media_buy( self, request: UpdateMediaBuyRequest, ) -> TaskResult[UpdateMediaBuyResponse]: """ Update an existing media buy reservation. Modifies a previously created media buy by updating packages or publisher properties. The update operation uses discriminated unions to specify what to change - either package details or targeting properties. Args: request: Media buy update parameters including: - media_buy_id: Identifier from create_media_buy response - updates: Discriminated union specifying update type: * UpdateMediaBuyPackagesRequest: Modify package selections * UpdateMediaBuyPropertiesRequest: Change targeting properties Returns: TaskResult containing UpdateMediaBuyResponse with: - media_buy_id: The updated media buy identifier - status: Updated state of the media buy - packages: Updated package configurations - Additional platform-specific metadata Example: >>> from adcp import ADCPClient, UpdateMediaBuyPackagesRequest >>> client = ADCPClient(agent_config) >>> request = UpdateMediaBuyPackagesRequest( ... media_buy_id="mb_123", ... packages=[updated_package] ... ) >>> result = await client.update_media_buy(request) >>> if result.success: ... updated_packages = result.data.packages """ operation_id = create_operation_id() params = request.model_dump(mode="json", exclude_none=True) self._emit_activity( Activity( type=ActivityType.PROTOCOL_REQUEST, operation_id=operation_id, agent_id=self.agent_config.id, task_type="update_media_buy", timestamp=datetime.now(timezone.utc).isoformat(), ) ) raw_result = await self.adapter.update_media_buy(params) self._emit_activity( Activity( type=ActivityType.PROTOCOL_RESPONSE, operation_id=operation_id, agent_id=self.agent_config.id, task_type="update_media_buy", status=raw_result.status, timestamp=datetime.now(timezone.utc).isoformat(), ) ) return self.adapter._parse_response(raw_result, UpdateMediaBuyResponse) async def build_creative( self, request: BuildCreativeRequest, ) -> TaskResult[BuildCreativeResponse]: """ Generate production-ready creative assets. Requests the creative agent to build final deliverable assets in the target format (e.g., VAST, DAAST, HTML5). This is typically called after previewing and approving a creative manifest. Args: request: Creative build parameters including: - manifest: Creative manifest with brand info and content - target_format_id: Desired output format identifier - inputs: Optional user-provided inputs for template variables - deployment: Platform or agent deployment configuration Returns: TaskResult containing BuildCreativeResponse with: - assets: Production-ready creative files (URLs or inline content) - format_id: The generated format identifier - manifest: The creative manifest used for generation - metadata: Additional platform-specific details Example: >>> from adcp import ADCPClient, BuildCreativeRequest >>> client = ADCPClient(agent_config) >>> request = BuildCreativeRequest( ... manifest=creative_manifest, ... target_format_id="vast_2.0", ... inputs={"duration": 30} ... ) >>> result = await client.build_creative(request) >>> if result.success: ... vast_url = result.data.assets[0].url """ operation_id = create_operation_id() params = request.model_dump(mode="json", exclude_none=True) self._emit_activity( Activity( type=ActivityType.PROTOCOL_REQUEST, operation_id=operation_id, agent_id=self.agent_config.id, task_type="build_creative", timestamp=datetime.now(timezone.utc).isoformat(), ) ) raw_result = await self.adapter.build_creative(params) self._emit_activity( Activity( type=ActivityType.PROTOCOL_RESPONSE, operation_id=operation_id, agent_id=self.agent_config.id, task_type="build_creative", status=raw_result.status, timestamp=datetime.now(timezone.utc).isoformat(), ) ) return self.adapter._parse_response(raw_result, BuildCreativeResponse) async def list_accounts( self, request: ListAccountsRequest, ) -> TaskResult[ListAccountsResponse]: """ List Accounts. Args: request: Request parameters Returns: TaskResult containing ListAccountsResponse """ operation_id = create_operation_id() params = request.model_dump(mode="json", exclude_none=True) self._emit_activity( Activity( type=ActivityType.PROTOCOL_REQUEST, operation_id=operation_id, agent_id=self.agent_config.id, task_type="list_accounts", timestamp=datetime.now(timezone.utc).isoformat(), ) ) raw_result = await self.adapter.list_accounts(params) self._emit_activity( Activity( type=ActivityType.PROTOCOL_RESPONSE, operation_id=operation_id, agent_id=self.agent_config.id, task_type="list_accounts", status=raw_result.status, timestamp=datetime.now(timezone.utc).isoformat(), ) ) return self.adapter._parse_response(raw_result, ListAccountsResponse) async def sync_accounts( self, request: SyncAccountsRequest, ) -> TaskResult[SyncAccountsResponse]: """ Sync Accounts. Args: request: Request parameters Returns: TaskResult containing SyncAccountsResponse """ operation_id = create_operation_id() params = request.model_dump(mode="json", exclude_none=True) self._emit_activity( Activity( type=ActivityType.PROTOCOL_REQUEST, operation_id=operation_id, agent_id=self.agent_config.id, task_type="sync_accounts", timestamp=datetime.now(timezone.utc).isoformat(), ) ) raw_result = await self.adapter.sync_accounts(params) self._emit_activity( Activity( type=ActivityType.PROTOCOL_RESPONSE, operation_id=operation_id, agent_id=self.agent_config.id, task_type="sync_accounts", status=raw_result.status, timestamp=datetime.now(timezone.utc).isoformat(), ) ) return self.adapter._parse_response(raw_result, SyncAccountsResponse) async def get_account_financials( self, request: GetAccountFinancialsRequest, ) -> TaskResult[GetAccountFinancialsResponse]: """ Get Account Financials. Args: request: Request parameters Returns: TaskResult containing GetAccountFinancialsResponse """ operation_id = create_operation_id() params = request.model_dump(mode="json", exclude_none=True) self._emit_activity( Activity( type=ActivityType.PROTOCOL_REQUEST, operation_id=operation_id, agent_id=self.agent_config.id, task_type="get_account_financials", timestamp=datetime.now(timezone.utc).isoformat(), ) ) raw_result = await self.adapter.get_account_financials(params) self._emit_activity( Activity( type=ActivityType.PROTOCOL_RESPONSE, operation_id=operation_id, agent_id=self.agent_config.id, task_type="get_account_financials", status=raw_result.status, timestamp=datetime.now(timezone.utc).isoformat(), ) ) return self.adapter._parse_response(raw_result, GetAccountFinancialsResponse) async def report_usage( self, request: ReportUsageRequest, ) -> TaskResult[ReportUsageResponse]: """ Report Usage. Args: request: Request parameters Returns: TaskResult containing ReportUsageResponse """ operation_id = create_operation_id() params = request.model_dump(mode="json", exclude_none=True) self._emit_activity( Activity( type=ActivityType.PROTOCOL_REQUEST, operation_id=operation_id, agent_id=self.agent_config.id, task_type="report_usage", timestamp=datetime.now(timezone.utc).isoformat(), ) ) raw_result = await self.adapter.report_usage(params) self._emit_activity( Activity( type=ActivityType.PROTOCOL_RESPONSE, operation_id=operation_id, agent_id=self.agent_config.id, task_type="report_usage", status=raw_result.status, timestamp=datetime.now(timezone.utc).isoformat(), ) ) return self.adapter._parse_response(raw_result, ReportUsageResponse) async def log_event( self, request: LogEventRequest, ) -> TaskResult[LogEventResponse]: """ Log Event. Args: request: Request parameters Returns: TaskResult containing LogEventResponse """ self._validate_task_features("log_event") operation_id = create_operation_id() params = request.model_dump(mode="json", exclude_none=True) self._emit_activity( Activity( type=ActivityType.PROTOCOL_REQUEST, operation_id=operation_id, agent_id=self.agent_config.id, task_type="log_event", timestamp=datetime.now(timezone.utc).isoformat(), ) ) raw_result = await self.adapter.log_event(params) self._emit_activity( Activity( type=ActivityType.PROTOCOL_RESPONSE, operation_id=operation_id, agent_id=self.agent_config.id, task_type="log_event", status=raw_result.status, timestamp=datetime.now(timezone.utc).isoformat(), ) ) return self.adapter._parse_response(raw_result, LogEventResponse) async def sync_event_sources( self, request: SyncEventSourcesRequest, ) -> TaskResult[SyncEventSourcesResponse]: """ Sync Event Sources. Args: request: Request parameters Returns: TaskResult containing SyncEventSourcesResponse """ self._validate_task_features("sync_event_sources") operation_id = create_operation_id() params = request.model_dump(mode="json", exclude_none=True) self._emit_activity( Activity( type=ActivityType.PROTOCOL_REQUEST, operation_id=operation_id, agent_id=self.agent_config.id, task_type="sync_event_sources", timestamp=datetime.now(timezone.utc).isoformat(), ) ) raw_result = await self.adapter.sync_event_sources(params) self._emit_activity( Activity( type=ActivityType.PROTOCOL_RESPONSE, operation_id=operation_id, agent_id=self.agent_config.id, task_type="sync_event_sources", status=raw_result.status, timestamp=datetime.now(timezone.utc).isoformat(), ) ) return self.adapter._parse_response(raw_result, SyncEventSourcesResponse) async def sync_audiences( self, request: SyncAudiencesRequest, ) -> TaskResult[SyncAudiencesResponse]: """ Sync Audiences. Args: request: Request parameters Returns: TaskResult containing SyncAudiencesResponse """ operation_id = create_operation_id() params = request.model_dump(mode="json", exclude_none=True) self._emit_activity( Activity( type=ActivityType.PROTOCOL_REQUEST, operation_id=operation_id, agent_id=self.agent_config.id, task_type="sync_audiences", timestamp=datetime.now(timezone.utc).isoformat(), ) ) raw_result = await self.adapter.sync_audiences(params) self._emit_activity( Activity( type=ActivityType.PROTOCOL_RESPONSE, operation_id=operation_id, agent_id=self.agent_config.id, task_type="sync_audiences", status=raw_result.status, timestamp=datetime.now(timezone.utc).isoformat(), ) ) return self.adapter._parse_response(raw_result, SyncAudiencesResponse) async def sync_catalogs( self, request: SyncCatalogsRequest, ) -> TaskResult[SyncCatalogsResponse]: """ Sync Catalogs. Args: request: Request parameters Returns: TaskResult containing SyncCatalogsResponse """ operation_id = create_operation_id() params = request.model_dump(mode="json", exclude_none=True) self._emit_activity( Activity( type=ActivityType.PROTOCOL_REQUEST, operation_id=operation_id, agent_id=self.agent_config.id, task_type="sync_catalogs", timestamp=datetime.now(timezone.utc).isoformat(), ) ) raw_result = await self.adapter.sync_catalogs(params) self._emit_activity( Activity( type=ActivityType.PROTOCOL_RESPONSE, operation_id=operation_id, agent_id=self.agent_config.id, task_type="sync_catalogs", status=raw_result.status, timestamp=datetime.now(timezone.utc).isoformat(), ) ) return self.adapter._parse_response(raw_result, SyncCatalogsResponse) async def get_creative_delivery( self, request: GetCreativeDeliveryRequest, ) -> TaskResult[GetCreativeDeliveryResponse]: """ Get Creative Delivery. Args: request: Request parameters Returns: TaskResult containing GetCreativeDeliveryResponse """ operation_id = create_operation_id() params = request.model_dump(mode="json", exclude_none=True) self._emit_activity( Activity( type=ActivityType.PROTOCOL_REQUEST, operation_id=operation_id, agent_id=self.agent_config.id, task_type="get_creative_delivery", timestamp=datetime.now(timezone.utc).isoformat(), ) ) raw_result = await self.adapter.get_creative_delivery(params) self._emit_activity( Activity( type=ActivityType.PROTOCOL_RESPONSE, operation_id=operation_id, agent_id=self.agent_config.id, task_type="get_creative_delivery", status=raw_result.status, timestamp=datetime.now(timezone.utc).isoformat(), ) ) return self.adapter._parse_response(raw_result, GetCreativeDeliveryResponse) # ======================================================================== # V3 Protocol Methods - Protocol Discovery # ======================================================================== async def get_adcp_capabilities( self, request: GetAdcpCapabilitiesRequest, ) -> TaskResult[GetAdcpCapabilitiesResponse]: """ Get AdCP capabilities from the agent. Queries the agent's supported AdCP features, protocol versions, and domain-specific capabilities (media_buy, signals, sponsored_intelligence). Args: request: Request parameters including optional protocol filters Returns: TaskResult containing GetAdcpCapabilitiesResponse with: - adcp: Core protocol version information - supported_protocols: List of supported domain protocols - media_buy: Media buy capabilities (if supported) - sponsored_intelligence: SI capabilities (if supported) - signals: Signals capabilities (if supported) """ operation_id = create_operation_id() params = request.model_dump(mode="json", exclude_none=True) self._emit_activity( Activity( type=ActivityType.PROTOCOL_REQUEST, operation_id=operation_id, agent_id=self.agent_config.id, task_type="get_adcp_capabilities", timestamp=datetime.now(timezone.utc).isoformat(), ) ) raw_result = await self.adapter.get_adcp_capabilities(params) self._emit_activity( Activity( type=ActivityType.PROTOCOL_RESPONSE, operation_id=operation_id, agent_id=self.agent_config.id, task_type="get_adcp_capabilities", status=raw_result.status, timestamp=datetime.now(timezone.utc).isoformat(), ) ) return self.adapter._parse_response(raw_result, GetAdcpCapabilitiesResponse) # ======================================================================== # V3 Protocol Methods - Content Standards # ======================================================================== async def create_content_standards( self, request: CreateContentStandardsRequest, ) -> TaskResult[CreateContentStandardsResponse]: """ Create a new content standards configuration. Defines acceptable content contexts for ad placement using natural language policy and optional calibration exemplars. Args: request: Request parameters including policy and scope Returns: TaskResult containing CreateContentStandardsResponse with standards_id """ operation_id = create_operation_id() params = request.model_dump(mode="json", exclude_none=True) self._emit_activity( Activity( type=ActivityType.PROTOCOL_REQUEST, operation_id=operation_id, agent_id=self.agent_config.id, task_type="create_content_standards", timestamp=datetime.now(timezone.utc).isoformat(), ) ) raw_result = await self.adapter.create_content_standards(params) self._emit_activity( Activity( type=ActivityType.PROTOCOL_RESPONSE, operation_id=operation_id, agent_id=self.agent_config.id, task_type="create_content_standards", status=raw_result.status, timestamp=datetime.now(timezone.utc).isoformat(), ) ) return self.adapter._parse_response(raw_result, CreateContentStandardsResponse) async def get_content_standards( self, request: GetContentStandardsRequest, ) -> TaskResult[GetContentStandardsResponse]: """ Get a content standards configuration by ID. Args: request: Request parameters including standards_id Returns: TaskResult containing GetContentStandardsResponse """ operation_id = create_operation_id() params = request.model_dump(mode="json", exclude_none=True) self._emit_activity( Activity( type=ActivityType.PROTOCOL_REQUEST, operation_id=operation_id, agent_id=self.agent_config.id, task_type="get_content_standards", timestamp=datetime.now(timezone.utc).isoformat(), ) ) raw_result = await self.adapter.get_content_standards(params) self._emit_activity( Activity( type=ActivityType.PROTOCOL_RESPONSE, operation_id=operation_id, agent_id=self.agent_config.id, task_type="get_content_standards", status=raw_result.status, timestamp=datetime.now(timezone.utc).isoformat(), ) ) return self.adapter._parse_response(raw_result, GetContentStandardsResponse) async def list_content_standards( self, request: ListContentStandardsRequest, ) -> TaskResult[ListContentStandardsResponse]: """ List content standards configurations. Args: request: Request parameters including optional filters Returns: TaskResult containing ListContentStandardsResponse """ operation_id = create_operation_id() params = request.model_dump(mode="json", exclude_none=True) self._emit_activity( Activity( type=ActivityType.PROTOCOL_REQUEST, operation_id=operation_id, agent_id=self.agent_config.id, task_type="list_content_standards", timestamp=datetime.now(timezone.utc).isoformat(), ) ) raw_result = await self.adapter.list_content_standards(params) self._emit_activity( Activity( type=ActivityType.PROTOCOL_RESPONSE, operation_id=operation_id, agent_id=self.agent_config.id, task_type="list_content_standards", status=raw_result.status, timestamp=datetime.now(timezone.utc).isoformat(), ) ) return self.adapter._parse_response(raw_result, ListContentStandardsResponse) async def update_content_standards( self, request: UpdateContentStandardsRequest, ) -> TaskResult[UpdateContentStandardsResponse]: """ Update a content standards configuration. Args: request: Request parameters including standards_id and updates Returns: TaskResult containing UpdateContentStandardsResponse """ operation_id = create_operation_id() params = request.model_dump(mode="json", exclude_none=True) self._emit_activity( Activity( type=ActivityType.PROTOCOL_REQUEST, operation_id=operation_id, agent_id=self.agent_config.id, task_type="update_content_standards", timestamp=datetime.now(timezone.utc).isoformat(), ) ) raw_result = await self.adapter.update_content_standards(params) self._emit_activity( Activity( type=ActivityType.PROTOCOL_RESPONSE, operation_id=operation_id, agent_id=self.agent_config.id, task_type="update_content_standards", status=raw_result.status, timestamp=datetime.now(timezone.utc).isoformat(), ) ) return self.adapter._parse_response(raw_result, UpdateContentStandardsResponse) async def calibrate_content( self, request: CalibrateContentRequest, ) -> TaskResult[CalibrateContentResponse]: """ Calibrate content against standards. Evaluates content (artifact or URL) against configured standards to determine suitability for ad placement. Args: request: Request parameters including content to evaluate Returns: TaskResult containing CalibrateContentResponse with verdict """ operation_id = create_operation_id() params = request.model_dump(mode="json", exclude_none=True) self._emit_activity( Activity( type=ActivityType.PROTOCOL_REQUEST, operation_id=operation_id, agent_id=self.agent_config.id, task_type="calibrate_content", timestamp=datetime.now(timezone.utc).isoformat(), ) ) raw_result = await self.adapter.calibrate_content(params) self._emit_activity( Activity( type=ActivityType.PROTOCOL_RESPONSE, operation_id=operation_id, agent_id=self.agent_config.id, task_type="calibrate_content", status=raw_result.status, timestamp=datetime.now(timezone.utc).isoformat(), ) ) return self.adapter._parse_response(raw_result, CalibrateContentResponse) async def validate_content_delivery( self, request: ValidateContentDeliveryRequest, ) -> TaskResult[ValidateContentDeliveryResponse]: """ Validate content delivery against standards. Validates that ad delivery records comply with content standards. Args: request: Request parameters including delivery records Returns: TaskResult containing ValidateContentDeliveryResponse """ operation_id = create_operation_id() params = request.model_dump(mode="json", exclude_none=True) self._emit_activity( Activity( type=ActivityType.PROTOCOL_REQUEST, operation_id=operation_id, agent_id=self.agent_config.id, task_type="validate_content_delivery", timestamp=datetime.now(timezone.utc).isoformat(), ) ) raw_result = await self.adapter.validate_content_delivery(params) self._emit_activity( Activity( type=ActivityType.PROTOCOL_RESPONSE, operation_id=operation_id, agent_id=self.agent_config.id, task_type="validate_content_delivery", status=raw_result.status, timestamp=datetime.now(timezone.utc).isoformat(), ) ) return self.adapter._parse_response(raw_result, ValidateContentDeliveryResponse) async def get_media_buy_artifacts( self, request: GetMediaBuyArtifactsRequest, ) -> TaskResult[GetMediaBuyArtifactsResponse]: """ Get artifacts associated with a media buy. Retrieves content artifacts where ads were delivered for a media buy. Args: request: Request parameters including media_buy_id Returns: TaskResult containing GetMediaBuyArtifactsResponse """ operation_id = create_operation_id() params = request.model_dump(mode="json", exclude_none=True) self._emit_activity( Activity( type=ActivityType.PROTOCOL_REQUEST, operation_id=operation_id, agent_id=self.agent_config.id, task_type="get_media_buy_artifacts", timestamp=datetime.now(timezone.utc).isoformat(), ) ) raw_result = await self.adapter.get_media_buy_artifacts(params) self._emit_activity( Activity( type=ActivityType.PROTOCOL_RESPONSE, operation_id=operation_id, agent_id=self.agent_config.id, task_type="get_media_buy_artifacts", status=raw_result.status, timestamp=datetime.now(timezone.utc).isoformat(), ) ) return self.adapter._parse_response(raw_result, GetMediaBuyArtifactsResponse) # ======================================================================== # V3 Protocol Methods - Sponsored Intelligence # ======================================================================== async def si_get_offering( self, request: SiGetOfferingRequest, ) -> TaskResult[SiGetOfferingResponse]: """ Get sponsored intelligence offering. Retrieves product/service offerings that can be presented in a sponsored intelligence session. Args: request: Request parameters including brand context Returns: TaskResult containing SiGetOfferingResponse """ operation_id = create_operation_id() params = request.model_dump(mode="json", exclude_none=True) self._emit_activity( Activity( type=ActivityType.PROTOCOL_REQUEST, operation_id=operation_id, agent_id=self.agent_config.id, task_type="si_get_offering", timestamp=datetime.now(timezone.utc).isoformat(), ) ) raw_result = await self.adapter.si_get_offering(params) self._emit_activity( Activity( type=ActivityType.PROTOCOL_RESPONSE, operation_id=operation_id, agent_id=self.agent_config.id, task_type="si_get_offering", status=raw_result.status, timestamp=datetime.now(timezone.utc).isoformat(), ) ) return self.adapter._parse_response(raw_result, SiGetOfferingResponse) async def si_initiate_session( self, request: SiInitiateSessionRequest, ) -> TaskResult[SiInitiateSessionResponse]: """ Initiate a sponsored intelligence session. Starts a conversational brand experience session with a user. Args: request: Request parameters including identity and context Returns: TaskResult containing SiInitiateSessionResponse with session_id """ operation_id = create_operation_id() params = request.model_dump(mode="json", exclude_none=True) self._emit_activity( Activity( type=ActivityType.PROTOCOL_REQUEST, operation_id=operation_id, agent_id=self.agent_config.id, task_type="si_initiate_session", timestamp=datetime.now(timezone.utc).isoformat(), ) ) raw_result = await self.adapter.si_initiate_session(params) self._emit_activity( Activity( type=ActivityType.PROTOCOL_RESPONSE, operation_id=operation_id, agent_id=self.agent_config.id, task_type="si_initiate_session", status=raw_result.status, timestamp=datetime.now(timezone.utc).isoformat(), ) ) return self.adapter._parse_response(raw_result, SiInitiateSessionResponse) async def si_send_message( self, request: SiSendMessageRequest, ) -> TaskResult[SiSendMessageResponse]: """ Send a message in a sponsored intelligence session. Continues the conversation in an active SI session. Args: request: Request parameters including session_id and message Returns: TaskResult containing SiSendMessageResponse with brand response """ operation_id = create_operation_id() params = request.model_dump(mode="json", exclude_none=True) self._emit_activity( Activity( type=ActivityType.PROTOCOL_REQUEST, operation_id=operation_id, agent_id=self.agent_config.id, task_type="si_send_message", timestamp=datetime.now(timezone.utc).isoformat(), ) ) raw_result = await self.adapter.si_send_message(params) self._emit_activity( Activity( type=ActivityType.PROTOCOL_RESPONSE, operation_id=operation_id, agent_id=self.agent_config.id, task_type="si_send_message", status=raw_result.status, timestamp=datetime.now(timezone.utc).isoformat(), ) ) return self.adapter._parse_response(raw_result, SiSendMessageResponse) async def si_terminate_session( self, request: SiTerminateSessionRequest, ) -> TaskResult[SiTerminateSessionResponse]: """ Terminate a sponsored intelligence session. Ends an active SI session, optionally with follow-up actions. Args: request: Request parameters including session_id and termination context Returns: TaskResult containing SiTerminateSessionResponse """ operation_id = create_operation_id() params = request.model_dump(mode="json", exclude_none=True) self._emit_activity( Activity( type=ActivityType.PROTOCOL_REQUEST, operation_id=operation_id, agent_id=self.agent_config.id, task_type="si_terminate_session", timestamp=datetime.now(timezone.utc).isoformat(), ) ) raw_result = await self.adapter.si_terminate_session(params) self._emit_activity( Activity( type=ActivityType.PROTOCOL_RESPONSE, operation_id=operation_id, agent_id=self.agent_config.id, task_type="si_terminate_session", status=raw_result.status, timestamp=datetime.now(timezone.utc).isoformat(), ) ) return self.adapter._parse_response(raw_result, SiTerminateSessionResponse) # ======================================================================== # V3 Governance Methods # ======================================================================== async def get_creative_features( self, request: GetCreativeFeaturesRequest, ) -> TaskResult[GetCreativeFeaturesResponse]: """Evaluate governance features for a creative manifest.""" operation_id = create_operation_id() params = request.model_dump(mode="json", exclude_none=True) self._emit_activity( Activity( type=ActivityType.PROTOCOL_REQUEST, operation_id=operation_id, agent_id=self.agent_config.id, task_type="get_creative_features", timestamp=datetime.now(timezone.utc).isoformat(), ) ) raw_result = await self.adapter.get_creative_features(params) self._emit_activity( Activity( type=ActivityType.PROTOCOL_RESPONSE, operation_id=operation_id, agent_id=self.agent_config.id, task_type="get_creative_features", status=raw_result.status, timestamp=datetime.now(timezone.utc).isoformat(), ) ) return self.adapter._parse_response(raw_result, GetCreativeFeaturesResponse) async def sync_plans( self, request: SyncPlansRequest, ) -> TaskResult[SyncPlansResponse]: """Sync campaign governance plans to the governance agent.""" operation_id = create_operation_id() params = request.model_dump(mode="json", exclude_none=True) self._emit_activity( Activity( type=ActivityType.PROTOCOL_REQUEST, operation_id=operation_id, agent_id=self.agent_config.id, task_type="sync_plans", timestamp=datetime.now(timezone.utc).isoformat(), ) ) raw_result = await self.adapter.sync_plans(params) self._emit_activity( Activity( type=ActivityType.PROTOCOL_RESPONSE, operation_id=operation_id, agent_id=self.agent_config.id, task_type="sync_plans", status=raw_result.status, timestamp=datetime.now(timezone.utc).isoformat(), ) ) return self.adapter._parse_response(raw_result, SyncPlansResponse) async def check_governance( self, request: CheckGovernanceRequest, ) -> TaskResult[CheckGovernanceResponse]: """Check a proposed or committed action against campaign governance.""" operation_id = create_operation_id() params = request.model_dump(mode="json", exclude_none=True) self._emit_activity( Activity( type=ActivityType.PROTOCOL_REQUEST, operation_id=operation_id, agent_id=self.agent_config.id, task_type="check_governance", timestamp=datetime.now(timezone.utc).isoformat(), ) ) raw_result = await self.adapter.check_governance(params) self._emit_activity( Activity( type=ActivityType.PROTOCOL_RESPONSE, operation_id=operation_id, agent_id=self.agent_config.id, task_type="check_governance", status=raw_result.status, timestamp=datetime.now(timezone.utc).isoformat(), ) ) return self.adapter._parse_response(raw_result, CheckGovernanceResponse) async def report_plan_outcome( self, request: ReportPlanOutcomeRequest, ) -> TaskResult[ReportPlanOutcomeResponse]: """Report the outcome of a governed action to the governance agent.""" operation_id = create_operation_id() params = request.model_dump(mode="json", exclude_none=True) self._emit_activity( Activity( type=ActivityType.PROTOCOL_REQUEST, operation_id=operation_id, agent_id=self.agent_config.id, task_type="report_plan_outcome", timestamp=datetime.now(timezone.utc).isoformat(), ) ) raw_result = await self.adapter.report_plan_outcome(params) self._emit_activity( Activity( type=ActivityType.PROTOCOL_RESPONSE, operation_id=operation_id, agent_id=self.agent_config.id, task_type="report_plan_outcome", status=raw_result.status, timestamp=datetime.now(timezone.utc).isoformat(), ) ) return self.adapter._parse_response(raw_result, ReportPlanOutcomeResponse) async def get_plan_audit_logs( self, request: GetPlanAuditLogsRequest, ) -> TaskResult[GetPlanAuditLogsResponse]: """Retrieve governance state and audit logs for one or more plans.""" operation_id = create_operation_id() params = request.model_dump(mode="json", exclude_none=True) self._emit_activity( Activity( type=ActivityType.PROTOCOL_REQUEST, operation_id=operation_id, agent_id=self.agent_config.id, task_type="get_plan_audit_logs", timestamp=datetime.now(timezone.utc).isoformat(), ) ) raw_result = await self.adapter.get_plan_audit_logs(params) self._emit_activity( Activity( type=ActivityType.PROTOCOL_RESPONSE, operation_id=operation_id, agent_id=self.agent_config.id, task_type="get_plan_audit_logs", status=raw_result.status, timestamp=datetime.now(timezone.utc).isoformat(), ) ) return self.adapter._parse_response(raw_result, GetPlanAuditLogsResponse) async def create_property_list( self, request: CreatePropertyListRequest, ) -> TaskResult[CreatePropertyListResponse]: """ Create a property list for governance filtering. Property lists define dynamic sets of properties based on filters, brand manifests, and feature requirements. Args: request: Request parameters for creating the property list Returns: TaskResult containing CreatePropertyListResponse with list_id """ operation_id = create_operation_id() params = request.model_dump(mode="json", exclude_none=True) self._emit_activity( Activity( type=ActivityType.PROTOCOL_REQUEST, operation_id=operation_id, agent_id=self.agent_config.id, task_type="create_property_list", timestamp=datetime.now(timezone.utc).isoformat(), ) ) raw_result = await self.adapter.create_property_list(params) self._emit_activity( Activity( type=ActivityType.PROTOCOL_RESPONSE, operation_id=operation_id, agent_id=self.agent_config.id, task_type="create_property_list", status=raw_result.status, timestamp=datetime.now(timezone.utc).isoformat(), ) ) return self.adapter._parse_response(raw_result, CreatePropertyListResponse) async def get_property_list( self, request: GetPropertyListRequest, ) -> TaskResult[GetPropertyListResponse]: """ Get a property list with optional resolution. When resolve=true, returns the list of resolved property identifiers. Use this to get the actual properties that match the list's filters. Args: request: Request parameters including list_id and resolve flag Returns: TaskResult containing GetPropertyListResponse with identifiers """ operation_id = create_operation_id() params = request.model_dump(mode="json", exclude_none=True) self._emit_activity( Activity( type=ActivityType.PROTOCOL_REQUEST, operation_id=operation_id, agent_id=self.agent_config.id, task_type="get_property_list", timestamp=datetime.now(timezone.utc).isoformat(), ) ) raw_result = await self.adapter.get_property_list(params) self._emit_activity( Activity( type=ActivityType.PROTOCOL_RESPONSE, operation_id=operation_id, agent_id=self.agent_config.id, task_type="get_property_list", status=raw_result.status, timestamp=datetime.now(timezone.utc).isoformat(), ) ) return self.adapter._parse_response(raw_result, GetPropertyListResponse) async def list_property_lists( self, request: ListPropertyListsRequest, ) -> TaskResult[ListPropertyListsResponse]: """ List property lists owned by a principal. Retrieves metadata for all property lists, optionally filtered by principal or pagination parameters. Args: request: Request parameters with optional filtering Returns: TaskResult containing ListPropertyListsResponse """ operation_id = create_operation_id() params = request.model_dump(mode="json", exclude_none=True) self._emit_activity( Activity( type=ActivityType.PROTOCOL_REQUEST, operation_id=operation_id, agent_id=self.agent_config.id, task_type="list_property_lists", timestamp=datetime.now(timezone.utc).isoformat(), ) ) raw_result = await self.adapter.list_property_lists(params) self._emit_activity( Activity( type=ActivityType.PROTOCOL_RESPONSE, operation_id=operation_id, agent_id=self.agent_config.id, task_type="list_property_lists", status=raw_result.status, timestamp=datetime.now(timezone.utc).isoformat(), ) ) return self.adapter._parse_response(raw_result, ListPropertyListsResponse) async def update_property_list( self, request: UpdatePropertyListRequest, ) -> TaskResult[UpdatePropertyListResponse]: """ Update a property list. Modifies the filters, brand manifest, or other parameters of an existing property list. Args: request: Request parameters with list_id and updates Returns: TaskResult containing UpdatePropertyListResponse """ operation_id = create_operation_id() params = request.model_dump(mode="json", exclude_none=True) self._emit_activity( Activity( type=ActivityType.PROTOCOL_REQUEST, operation_id=operation_id, agent_id=self.agent_config.id, task_type="update_property_list", timestamp=datetime.now(timezone.utc).isoformat(), ) ) raw_result = await self.adapter.update_property_list(params) self._emit_activity( Activity( type=ActivityType.PROTOCOL_RESPONSE, operation_id=operation_id, agent_id=self.agent_config.id, task_type="update_property_list", status=raw_result.status, timestamp=datetime.now(timezone.utc).isoformat(), ) ) return self.adapter._parse_response(raw_result, UpdatePropertyListResponse) async def delete_property_list( self, request: DeletePropertyListRequest, ) -> TaskResult[DeletePropertyListResponse]: """ Delete a property list. Removes a property list. Any active subscriptions to this list will be terminated. Args: request: Request parameters with list_id Returns: TaskResult containing DeletePropertyListResponse """ operation_id = create_operation_id() params = request.model_dump(mode="json", exclude_none=True) self._emit_activity( Activity( type=ActivityType.PROTOCOL_REQUEST, operation_id=operation_id, agent_id=self.agent_config.id, task_type="delete_property_list", timestamp=datetime.now(timezone.utc).isoformat(), ) ) raw_result = await self.adapter.delete_property_list(params) self._emit_activity( Activity( type=ActivityType.PROTOCOL_RESPONSE, operation_id=operation_id, agent_id=self.agent_config.id, task_type="delete_property_list", status=raw_result.status, timestamp=datetime.now(timezone.utc).isoformat(), ) ) return self.adapter._parse_response(raw_result, DeletePropertyListResponse) # ======================================================================== # V3 Protocol Methods - Temporal Matching Protocol (TMP) # ======================================================================== async def context_match( self, request: ContextMatchRequest, ) -> TaskResult[ContextMatchResponse]: """Match ad context to buyer packages. Evaluates contextual signals for a publisher placement against the buyer's active packages and returns matching offers. Args: request: Context match request with placement, property, and optional artifact refs, context signals, and geo data. Returns: TaskResult containing ContextMatchResponse with offers. """ operation_id = create_operation_id() params = request.model_dump(mode="json", exclude_none=True, by_alias=True) self._emit_activity( Activity( type=ActivityType.PROTOCOL_REQUEST, operation_id=operation_id, agent_id=self.agent_config.id, task_type="context_match", timestamp=datetime.now(timezone.utc).isoformat(), ) ) raw_result = await self.adapter.context_match(params) self._emit_activity( Activity( type=ActivityType.PROTOCOL_RESPONSE, operation_id=operation_id, agent_id=self.agent_config.id, task_type="context_match", status=raw_result.status, timestamp=datetime.now(timezone.utc).isoformat(), ) ) return self.adapter._parse_response(raw_result, ContextMatchResponse) async def identity_match( self, request: IdentityMatchRequest, ) -> TaskResult[IdentityMatchResponse]: """Match user identity for package eligibility. Evaluates a user identity token against all active packages for frequency capping and personalization. Args: request: Identity match request with user_token, uid_type, and package_ids. Returns: TaskResult containing IdentityMatchResponse with eligible_package_ids. """ operation_id = create_operation_id() params = request.model_dump(mode="json", exclude_none=True, by_alias=True) self._emit_activity( Activity( type=ActivityType.PROTOCOL_REQUEST, operation_id=operation_id, agent_id=self.agent_config.id, task_type="identity_match", timestamp=datetime.now(timezone.utc).isoformat(), ) ) raw_result = await self.adapter.identity_match(params) self._emit_activity( Activity( type=ActivityType.PROTOCOL_RESPONSE, operation_id=operation_id, agent_id=self.agent_config.id, task_type="identity_match", status=raw_result.status, timestamp=datetime.now(timezone.utc).isoformat(), ) ) return self.adapter._parse_response(raw_result, IdentityMatchResponse) # ======================================================================== # V3 Protocol Methods - Brand Rights # ======================================================================== async def get_brand_identity( self, request: GetBrandIdentityRequest, ) -> TaskResult[GetBrandIdentityResponse]: """Get brand identity information. Retrieves brand identity data including logos, colors, fonts, voice synthesis config, and rights availability. Args: request: Request with brand_id and optional fields filter. Returns: TaskResult containing GetBrandIdentityResponse. """ operation_id = create_operation_id() params = request.model_dump(mode="json", exclude_none=True) self._emit_activity( Activity( type=ActivityType.PROTOCOL_REQUEST, operation_id=operation_id, agent_id=self.agent_config.id, task_type="get_brand_identity", timestamp=datetime.now(timezone.utc).isoformat(), ) ) raw_result = await self.adapter.get_brand_identity(params) self._emit_activity( Activity( type=ActivityType.PROTOCOL_RESPONSE, operation_id=operation_id, agent_id=self.agent_config.id, task_type="get_brand_identity", status=raw_result.status, timestamp=datetime.now(timezone.utc).isoformat(), ) ) return self.adapter._parse_response(raw_result, GetBrandIdentityResponse) async def get_rights( self, request: GetRightsRequest, ) -> TaskResult[GetRightsResponse]: """Get available rights for licensing. Searches for rights offerings using natural language query and filters by type, uses, countries, and buyer compatibility. Args: request: Request with query, uses, and optional filters. Returns: TaskResult containing GetRightsResponse with matched rights. """ operation_id = create_operation_id() params = request.model_dump(mode="json", exclude_none=True) self._emit_activity( Activity( type=ActivityType.PROTOCOL_REQUEST, operation_id=operation_id, agent_id=self.agent_config.id, task_type="get_rights", timestamp=datetime.now(timezone.utc).isoformat(), ) ) raw_result = await self.adapter.get_rights(params) self._emit_activity( Activity( type=ActivityType.PROTOCOL_RESPONSE, operation_id=operation_id, agent_id=self.agent_config.id, task_type="get_rights", status=raw_result.status, timestamp=datetime.now(timezone.utc).isoformat(), ) ) return self.adapter._parse_response(raw_result, GetRightsResponse) async def acquire_rights( self, request: AcquireRightsRequest, ) -> TaskResult[AcquireRightsResponse]: """Acquire rights for brand content usage. Binding contractual request to license rights for a campaign. Returns credentials for generating rights-cleared content. Args: request: Request with rights_id, pricing_option_id, buyer, campaign, and revocation_webhook. Returns: TaskResult containing AcquireRightsResponse (acquired, pending_approval, rejected, or error). """ operation_id = create_operation_id() params = request.model_dump(mode="json", exclude_none=True) self._emit_activity( Activity( type=ActivityType.PROTOCOL_REQUEST, operation_id=operation_id, agent_id=self.agent_config.id, task_type="acquire_rights", timestamp=datetime.now(timezone.utc).isoformat(), ) ) raw_result = await self.adapter.acquire_rights(params) self._emit_activity( Activity( type=ActivityType.PROTOCOL_RESPONSE, operation_id=operation_id, agent_id=self.agent_config.id, task_type="acquire_rights", status=raw_result.status, timestamp=datetime.now(timezone.utc).isoformat(), ) ) return self.adapter._parse_response(raw_result, AcquireRightsResponse) # ======================================================================== # V3 Protocol Methods - Compliance # ======================================================================== async def comply_test_controller( self, request: ComplyTestControllerRequest, ) -> TaskResult[ComplyTestControllerResponse]: """Compliance test controller for sandbox testing. Enables sellers to simulate state transitions and delivery data in a sandbox environment for compliance testing. Args: request: Request specifying scenario and parameters. Returns: TaskResult containing ComplyTestControllerResponse. """ operation_id = create_operation_id() params = request.model_dump(mode="json", exclude_none=True) self._emit_activity( Activity( type=ActivityType.PROTOCOL_REQUEST, operation_id=operation_id, agent_id=self.agent_config.id, task_type="comply_test_controller", timestamp=datetime.now(timezone.utc).isoformat(), ) ) raw_result = await self.adapter.comply_test_controller(params) self._emit_activity( Activity( type=ActivityType.PROTOCOL_RESPONSE, operation_id=operation_id, agent_id=self.agent_config.id, task_type="comply_test_controller", status=raw_result.status, timestamp=datetime.now(timezone.utc).isoformat(), ) ) return self.adapter._parse_response(raw_result, ComplyTestControllerResponse) async def list_tools(self) -> list[str]: """ List available tools from the agent. Returns: List of tool names """ return await self.adapter.list_tools() async def get_info(self) -> dict[str, Any]: """ Get agent information including AdCP extension metadata. Returns agent card information including: - Agent name, description, version - Protocol type (mcp or a2a) - AdCP version (from extensions.adcp.adcp_version) - Supported protocols (from extensions.adcp.protocols_supported) - Available tools/skills Returns: Dictionary with agent metadata """ return await self.adapter.get_agent_info() async def close(self) -> None: """Close the adapter and clean up resources.""" if hasattr(self.adapter, "close"): logger.debug(f"Closing adapter for agent {self.agent_config.id}") await self.adapter.close() async def __aenter__(self) -> ADCPClient: """Async context manager entry.""" return self async def __aexit__(self, exc_type: Any, exc_val: Any, exc_tb: Any) -> None: """Async context manager exit.""" await self.close() def _verify_webhook_signature( self, payload: dict[str, Any], signature: str, timestamp: str, raw_body: bytes | str | None = None, ) -> bool: """ Verify HMAC-SHA256 signature of webhook payload. The verification algorithm matches get_adcp_signed_headers_for_webhook: 1. Constructs message as "{timestamp}.{json_payload}" 2. Uses raw HTTP body bytes when available (preserves sender's serialization) 3. Falls back to json.dumps() if raw_body not provided 4. HMAC-SHA256 signs with the shared secret 5. Compares against the provided signature (with "sha256=" prefix stripped) Args: payload: Webhook payload dict (used as fallback if raw_body not provided) signature: Signature to verify (with or without "sha256=" prefix) timestamp: Unix timestamp in seconds from X-AdCP-Timestamp header raw_body: Raw HTTP request body bytes. When provided, used directly for signature verification to avoid cross-language serialization mismatches. Strongly recommended for production use. Returns: True if signature is valid, False otherwise """ if not self.webhook_secret: logger.warning( "Webhook signature verification skipped: no webhook_secret configured" ) return True # Reject stale or future timestamps to prevent replay attacks try: ts = int(timestamp) except (ValueError, TypeError): return False now = int(time.time()) if abs(now - ts) > self.webhook_timestamp_tolerance: return False # Strip "sha256=" prefix if present if signature.startswith("sha256="): signature = signature[7:] # Use raw body if available (avoids cross-language serialization mismatches), # otherwise fall back to json.dumps() for backward compatibility if raw_body is not None: payload_str = raw_body.decode("utf-8") if isinstance(raw_body, bytes) else raw_body else: payload_str = json.dumps(payload) # Construct signed message: timestamp.payload signed_message = f"{timestamp}.{payload_str}" # Generate expected signature expected_signature = hmac.new( self.webhook_secret.encode("utf-8"), signed_message.encode("utf-8"), hashlib.sha256 ).hexdigest() return hmac.compare_digest(signature, expected_signature) def _parse_webhook_result( self, task_id: str, task_type: str, operation_id: str, status: GeneratedTaskStatus, result: Any, timestamp: datetime | str, message: str | None, context_id: str | None, ) -> TaskResult[AdcpAsyncResponseData]: """ Parse webhook data into typed TaskResult based on task_type. Args: task_id: Unique identifier for this task task_type: Task type from application routing (e.g., "get_products") operation_id: Operation identifier from application routing status: Current task status result: Task-specific payload (AdCP response data) timestamp: ISO 8601 timestamp when webhook was generated message: Human-readable summary of task state context_id: Session/conversation identifier Returns: TaskResult with task-specific typed response data Note: This method works with both MCP and A2A protocols by accepting protocol-agnostic parameters rather than protocol-specific objects. """ from adcp.utils.response_parser import parse_json_or_text # Map task types to their response types (using string literals, not enum) # Note: Some response types are Union types (e.g., ActivateSignalResponse = Success | Error) response_type_map: dict[str, type[BaseModel] | Any] = { # Core operations "get_products": GetProductsResponse, "list_creative_formats": ListCreativeFormatsResponse, "sync_creatives": SyncCreativesResponse, "list_creatives": ListCreativesResponse, "build_creative": BuildCreativeResponse, "preview_creative": PreviewCreativeResponse, "create_media_buy": CreateMediaBuyResponse, "update_media_buy": UpdateMediaBuyResponse, "get_media_buy_delivery": GetMediaBuyDeliveryResponse, "get_media_buys": GetMediaBuysResponse, "get_signals": GetSignalsResponse, "activate_signal": ActivateSignalResponse, "provide_performance_feedback": ProvidePerformanceFeedbackResponse, "report_usage": ReportUsageResponse, "get_account_financials": GetAccountFinancialsResponse, "list_accounts": ListAccountsResponse, "sync_accounts": SyncAccountsResponse, "log_event": LogEventResponse, "sync_event_sources": SyncEventSourcesResponse, "sync_audiences": SyncAudiencesResponse, "sync_catalogs": SyncCatalogsResponse, "get_creative_delivery": GetCreativeDeliveryResponse, # V3 Protocol Discovery "get_adcp_capabilities": GetAdcpCapabilitiesResponse, # V3 Content Standards "create_content_standards": CreateContentStandardsResponse, "get_content_standards": GetContentStandardsResponse, "list_content_standards": ListContentStandardsResponse, "update_content_standards": UpdateContentStandardsResponse, "calibrate_content": CalibrateContentResponse, "validate_content_delivery": ValidateContentDeliveryResponse, "get_media_buy_artifacts": GetMediaBuyArtifactsResponse, # V3 Sponsored Intelligence "si_get_offering": SiGetOfferingResponse, "si_initiate_session": SiInitiateSessionResponse, "si_send_message": SiSendMessageResponse, "si_terminate_session": SiTerminateSessionResponse, # V3 Governance "get_creative_features": GetCreativeFeaturesResponse, "sync_plans": SyncPlansResponse, "check_governance": CheckGovernanceResponse, "report_plan_outcome": ReportPlanOutcomeResponse, "get_plan_audit_logs": GetPlanAuditLogsResponse, "create_property_list": CreatePropertyListResponse, "get_property_list": GetPropertyListResponse, "list_property_lists": ListPropertyListsResponse, "update_property_list": UpdatePropertyListResponse, "delete_property_list": DeletePropertyListResponse, # TMP "context_match": ContextMatchResponse, "identity_match": IdentityMatchResponse, # Brand Rights "get_brand_identity": GetBrandIdentityResponse, "get_rights": GetRightsResponse, "acquire_rights": AcquireRightsResponse, # Compliance "comply_test_controller": ComplyTestControllerResponse, } # Handle completed tasks with result parsing if status == GeneratedTaskStatus.completed and result is not None: response_type = response_type_map.get(task_type) if response_type: try: parsed_result: Any = parse_json_or_text(result, response_type) return TaskResult[AdcpAsyncResponseData]( status=TaskStatus.COMPLETED, data=parsed_result, success=True, metadata={ "task_id": task_id, "operation_id": operation_id, "timestamp": timestamp, "message": message, }, ) except ValueError as e: logger.warning(f"Failed to parse webhook result: {e}") # Fall through to untyped result # Handle failed, input-required, or unparseable results # Convert status to core TaskStatus enum status_map = { GeneratedTaskStatus.completed: TaskStatus.COMPLETED, GeneratedTaskStatus.submitted: TaskStatus.SUBMITTED, GeneratedTaskStatus.working: TaskStatus.WORKING, GeneratedTaskStatus.failed: TaskStatus.FAILED, GeneratedTaskStatus.input_required: TaskStatus.NEEDS_INPUT, } task_status = status_map.get(status, TaskStatus.FAILED) # Extract error message from result.errors if present error_message: str | None = None if result is not None and hasattr(result, "errors"): errors = getattr(result, "errors", None) if errors and len(errors) > 0: first_error = errors[0] if hasattr(first_error, "message"): error_message = first_error.message return TaskResult[AdcpAsyncResponseData]( status=task_status, data=result, success=status == GeneratedTaskStatus.completed, error=error_message, metadata={ "task_id": task_id, "operation_id": operation_id, "timestamp": timestamp, "message": message, "context_id": context_id, }, ) async def _handle_mcp_webhook( self, payload: dict[str, Any], task_type: str, operation_id: str, signature: str | None, timestamp: str | None = None, raw_body: bytes | str | None = None, ) -> TaskResult[AdcpAsyncResponseData]: """ Handle MCP webhook delivered via HTTP POST. Args: payload: Webhook payload dict task_type: Task type from application routing operation_id: Operation identifier from application routing signature: Optional HMAC-SHA256 signature for verification (X-AdCP-Signature header) timestamp: Optional Unix timestamp for signature verification (X-AdCP-Timestamp header) raw_body: Optional raw HTTP request body for signature verification Returns: TaskResult with parsed task-specific response data Raises: ADCPWebhookSignatureError: If signature verification fails ValidationError: If payload doesn't match McpWebhookPayload schema """ from adcp.types.generated_poc.core.mcp_webhook_payload import McpWebhookPayload # When a webhook_secret is configured, require signed webhooks if self.webhook_secret: if not signature or not timestamp: raise ADCPWebhookSignatureError( "Webhook signature and timestamp headers are required" ) if not self._verify_webhook_signature(payload, signature, timestamp, raw_body): logger.warning( f"Webhook signature verification failed for agent {self.agent_config.id}" ) raise ADCPWebhookSignatureError("Invalid webhook signature") # Validate and parse MCP webhook payload webhook = McpWebhookPayload.model_validate(payload) # Emit activity for monitoring self._emit_activity( Activity( type=ActivityType.WEBHOOK_RECEIVED, operation_id=operation_id, agent_id=self.agent_config.id, task_type=task_type, timestamp=datetime.now(timezone.utc).isoformat(), metadata={"payload": payload, "protocol": "mcp"}, ) ) # Extract fields and parse result return self._parse_webhook_result( task_id=webhook.task_id, task_type=task_type, operation_id=operation_id, status=webhook.status, result=webhook.result, timestamp=webhook.timestamp, message=webhook.message, context_id=webhook.context_id, ) async def _handle_a2a_webhook( self, payload: Task | TaskStatusUpdateEvent, task_type: str, operation_id: str ) -> TaskResult[AdcpAsyncResponseData]: """ Handle A2A webhook delivered through Task or TaskStatusUpdateEvent. Per A2A specification: - Terminated statuses (completed, failed): Payload is Task with artifacts[].parts[] - Intermediate statuses (working, input-required, submitted): Payload is TaskStatusUpdateEvent with status.message.parts[] Args: payload: A2A Task or TaskStatusUpdateEvent object task_type: Task type from application routing operation_id: Operation identifier from application routing Returns: TaskResult with parsed task-specific response data Note: Signature verification is NOT applicable for A2A webhooks as they arrive through authenticated A2A connections, not HTTP. """ from a2a.types import DataPart, TextPart adcp_data: Any = None text_message: str | None = None task_id: str context_id: str | None status_state: str timestamp: datetime | str # Type detection and extraction based on payload type if isinstance(payload, TaskStatusUpdateEvent): # Intermediate status: Extract from status.message.parts[] task_id = payload.task_id context_id = payload.context_id status_state = payload.status.state if payload.status else "failed" timestamp = ( payload.status.timestamp if payload.status and payload.status.timestamp else datetime.now(timezone.utc) ) # Extract from status.message.parts[] if payload.status and payload.status.message and payload.status.message.parts: # Extract DataPart for structured AdCP payload data_parts = [ p.root for p in payload.status.message.parts if isinstance(p.root, DataPart) ] if data_parts: # Use last DataPart as authoritative last_data_part = data_parts[-1] adcp_data = last_data_part.data # Unwrap {"response": {...}} wrapper if present (ADK pattern) if isinstance(adcp_data, dict) and "response" in adcp_data: adcp_data = adcp_data["response"] # Extract TextPart for human-readable message for part in payload.status.message.parts: if isinstance(part.root, TextPart): text_message = part.root.text break else: # Terminated status (Task): Extract from artifacts[].parts[] task_id = payload.id context_id = payload.context_id status_state = payload.status.state if payload.status else "failed" timestamp = ( payload.status.timestamp if payload.status and payload.status.timestamp else datetime.now(timezone.utc) ) # Extract from task.artifacts[].parts[] # Following A2A spec: use last artifact, last DataPart is authoritative if payload.artifacts: # Use last artifact (most recent in streaming scenarios) target_artifact = payload.artifacts[-1] if target_artifact.parts: # Extract DataPart for structured AdCP payload data_parts = [ p.root for p in target_artifact.parts if isinstance(p.root, DataPart) ] if data_parts: # Use last DataPart as authoritative last_data_part = data_parts[-1] adcp_data = last_data_part.data # Unwrap {"response": {...}} wrapper if present (ADK pattern) if isinstance(adcp_data, dict) and "response" in adcp_data: adcp_data = adcp_data["response"] # Extract TextPart for human-readable message for part in target_artifact.parts: if isinstance(part.root, TextPart): text_message = part.root.text break # Map A2A status.state to GeneratedTaskStatus enum status_map = { "completed": GeneratedTaskStatus.completed, "submitted": GeneratedTaskStatus.submitted, "working": GeneratedTaskStatus.working, "failed": GeneratedTaskStatus.failed, "input-required": GeneratedTaskStatus.input_required, "input_required": GeneratedTaskStatus.input_required, # Handle both formats } mapped_status = status_map.get(status_state, GeneratedTaskStatus.failed) # Emit activity for monitoring self._emit_activity( Activity( type=ActivityType.WEBHOOK_RECEIVED, operation_id=operation_id, agent_id=self.agent_config.id, task_type=task_type, timestamp=datetime.now(timezone.utc).isoformat(), metadata={ "task_id": task_id, "protocol": "a2a", "payload_type": ( "TaskStatusUpdateEvent" if isinstance(payload, TaskStatusUpdateEvent) else "Task" ), }, ) ) # Parse and return typed result by passing extracted fields directly return self._parse_webhook_result( task_id=task_id, task_type=task_type, operation_id=operation_id, status=mapped_status, result=adcp_data, timestamp=timestamp, message=text_message, context_id=context_id, ) async def handle_webhook( self, payload: dict[str, Any] | Task | TaskStatusUpdateEvent, task_type: str, operation_id: str, signature: str | None = None, timestamp: str | None = None, raw_body: bytes | str | None = None, ) -> TaskResult[AdcpAsyncResponseData]: """ Handle incoming webhook and return typed result. This method provides a unified interface for handling webhooks from both MCP and A2A protocols: - MCP Webhooks: HTTP POST with dict payload, optional HMAC signature - A2A Webhooks: Task or TaskStatusUpdateEvent objects based on status The method automatically detects the protocol type and routes to the appropriate handler. Both protocols return a consistent TaskResult structure with typed AdCP response data. Args: payload: Webhook payload - one of: - dict[str, Any]: MCP webhook payload from HTTP POST - Task: A2A webhook for terminated statuses (completed, failed) - TaskStatusUpdateEvent: A2A webhook for intermediate statuses (working, input-required, submitted) task_type: Task type from application routing (e.g., "get_products"). Applications should extract this from URL routing pattern: /webhook/{task_type}/{agent_id}/{operation_id} operation_id: Operation identifier from application routing. Used to correlate webhook notifications with original task submission. signature: Optional HMAC-SHA256 signature for MCP webhook verification (X-AdCP-Signature header). Ignored for A2A webhooks. timestamp: Optional Unix timestamp (seconds) for MCP webhook signature verification (X-AdCP-Timestamp header). Required when signature is provided. raw_body: Optional raw HTTP request body bytes for signature verification. When provided, used directly instead of re-serializing the payload, avoiding cross-language JSON serialization mismatches. Strongly recommended for production use. Returns: TaskResult with parsed task-specific response data. The structure is identical regardless of protocol. Raises: ADCPWebhookSignatureError: If MCP signature verification fails ValidationError: If MCP payload doesn't match WebhookPayload schema Note: task_type and operation_id were deprecated from the webhook payload per AdCP specification. Applications must extract these from URL routing and pass them explicitly. Examples: MCP webhook (HTTP endpoint): >>> @app.post("/webhook/{task_type}/{agent_id}/{operation_id}") >>> async def webhook_handler(task_type: str, operation_id: str, request: Request): >>> raw_body = await request.body() >>> payload = json.loads(raw_body) >>> signature = request.headers.get("X-AdCP-Signature") >>> timestamp = request.headers.get("X-AdCP-Timestamp") >>> result = await client.handle_webhook( >>> payload, task_type, operation_id, signature, timestamp, >>> raw_body=raw_body, >>> ) >>> if result.success: >>> print(f"Task completed: {result.data}") A2A webhook with Task (terminated status): >>> async def on_task_completed(task: Task): >>> # Extract task_type and operation_id from your app's task tracking >>> task_type = your_task_registry.get_type(task.id) >>> operation_id = your_task_registry.get_operation_id(task.id) >>> result = await client.handle_webhook( >>> task, task_type, operation_id >>> ) >>> if result.success: >>> print(f"Task completed: {result.data}") A2A webhook with TaskStatusUpdateEvent (intermediate status): >>> async def on_task_update(event: TaskStatusUpdateEvent): >>> # Extract task_type and operation_id from your app's task tracking >>> task_type = your_task_registry.get_type(event.task_id) >>> operation_id = your_task_registry.get_operation_id(event.task_id) >>> result = await client.handle_webhook( >>> event, task_type, operation_id >>> ) >>> if result.status == GeneratedTaskStatus.working: >>> print(f"Task still working: {result.metadata.get('message')}") """ # Detect protocol type and route to appropriate handler if isinstance(payload, (Task, TaskStatusUpdateEvent)): # A2A webhook (Task or TaskStatusUpdateEvent) return await self._handle_a2a_webhook(payload, task_type, operation_id) else: # MCP webhook (dict payload) return await self._handle_mcp_webhook( payload, task_type, operation_id, signature, timestamp, raw_body )Client for interacting with a single AdCP agent.
Initialize ADCP client for a single agent.
Args
agent_config- Agent configuration
webhook_url_template- Template for webhook URLs with {agent_id}, {task_type}, {operation_id}
webhook_secret- Secret for webhook signature verification
on_activity- Callback for activity events
webhook_timestamp_tolerance- Maximum age (in seconds) for webhook timestamps. Webhooks with timestamps older than this or more than this far in the future are rejected. Defaults to 300 (5 minutes).
capabilities_ttl- Time-to-live in seconds for cached capabilities (default: 1 hour)
validate_features- When True, automatically check that the seller supports required features before making task calls (e.g., sync_audiences requires audience_targeting). Requires capabilities to have been fetched first.
Instance variables
prop capabilities : GetAdcpCapabilitiesResponse | None-
Expand source code
@property def capabilities(self) -> GetAdcpCapabilitiesResponse | None: """Return cached capabilities, or None if not yet fetched.""" return self._capabilitiesReturn cached capabilities, or None if not yet fetched.
prop feature_resolver : FeatureResolver | None-
Expand source code
@property def feature_resolver(self) -> FeatureResolver | None: """Return the FeatureResolver for cached capabilities, or None.""" return self._feature_resolverReturn the FeatureResolver for cached capabilities, or None.
Methods
async def acquire_rights(self,
request: AcquireRightsRequest) ‑> TaskResult[Union[AcquireRightsResponse1, AcquireRightsResponse2, AcquireRightsResponse3, AcquireRightsResponse4]]-
Expand source code
async def acquire_rights( self, request: AcquireRightsRequest, ) -> TaskResult[AcquireRightsResponse]: """Acquire rights for brand content usage. Binding contractual request to license rights for a campaign. Returns credentials for generating rights-cleared content. Args: request: Request with rights_id, pricing_option_id, buyer, campaign, and revocation_webhook. Returns: TaskResult containing AcquireRightsResponse (acquired, pending_approval, rejected, or error). """ operation_id = create_operation_id() params = request.model_dump(mode="json", exclude_none=True) self._emit_activity( Activity( type=ActivityType.PROTOCOL_REQUEST, operation_id=operation_id, agent_id=self.agent_config.id, task_type="acquire_rights", timestamp=datetime.now(timezone.utc).isoformat(), ) ) raw_result = await self.adapter.acquire_rights(params) self._emit_activity( Activity( type=ActivityType.PROTOCOL_RESPONSE, operation_id=operation_id, agent_id=self.agent_config.id, task_type="acquire_rights", status=raw_result.status, timestamp=datetime.now(timezone.utc).isoformat(), ) ) return self.adapter._parse_response(raw_result, AcquireRightsResponse)Acquire rights for brand content usage.
Binding contractual request to license rights for a campaign. Returns credentials for generating rights-cleared content.
Args
request- Request with rights_id, pricing_option_id, buyer, campaign, and revocation_webhook.
Returns
TaskResult containing AcquireRightsResponse (acquired, pending_approval, rejected, or error).
async def activate_signal(self,
request: ActivateSignalRequest) ‑> TaskResult[Union[ActivateSignalResponse1, ActivateSignalResponse2]]-
Expand source code
async def activate_signal( self, request: ActivateSignalRequest, ) -> TaskResult[ActivateSignalResponse]: """ Activate Signal. Args: request: Request parameters Returns: TaskResult containing ActivateSignalResponse """ operation_id = create_operation_id() params = request.model_dump(mode="json", exclude_none=True) self._emit_activity( Activity( type=ActivityType.PROTOCOL_REQUEST, operation_id=operation_id, agent_id=self.agent_config.id, task_type="activate_signal", timestamp=datetime.now(timezone.utc).isoformat(), ) ) raw_result = await self.adapter.activate_signal(params) self._emit_activity( Activity( type=ActivityType.PROTOCOL_RESPONSE, operation_id=operation_id, agent_id=self.agent_config.id, task_type="activate_signal", status=raw_result.status, timestamp=datetime.now(timezone.utc).isoformat(), ) ) return self.adapter._parse_response(raw_result, ActivateSignalResponse)Activate Signal.
Args
request- Request parameters
Returns
TaskResult containing ActivateSignalResponse
async def build_creative(self,
request: BuildCreativeRequest) ‑> TaskResult[Union[BuildCreativeResponse1, BuildCreativeResponse2, BuildCreativeResponse3]]-
Expand source code
async def build_creative( self, request: BuildCreativeRequest, ) -> TaskResult[BuildCreativeResponse]: """ Generate production-ready creative assets. Requests the creative agent to build final deliverable assets in the target format (e.g., VAST, DAAST, HTML5). This is typically called after previewing and approving a creative manifest. Args: request: Creative build parameters including: - manifest: Creative manifest with brand info and content - target_format_id: Desired output format identifier - inputs: Optional user-provided inputs for template variables - deployment: Platform or agent deployment configuration Returns: TaskResult containing BuildCreativeResponse with: - assets: Production-ready creative files (URLs or inline content) - format_id: The generated format identifier - manifest: The creative manifest used for generation - metadata: Additional platform-specific details Example: >>> from adcp import ADCPClient, BuildCreativeRequest >>> client = ADCPClient(agent_config) >>> request = BuildCreativeRequest( ... manifest=creative_manifest, ... target_format_id="vast_2.0", ... inputs={"duration": 30} ... ) >>> result = await client.build_creative(request) >>> if result.success: ... vast_url = result.data.assets[0].url """ operation_id = create_operation_id() params = request.model_dump(mode="json", exclude_none=True) self._emit_activity( Activity( type=ActivityType.PROTOCOL_REQUEST, operation_id=operation_id, agent_id=self.agent_config.id, task_type="build_creative", timestamp=datetime.now(timezone.utc).isoformat(), ) ) raw_result = await self.adapter.build_creative(params) self._emit_activity( Activity( type=ActivityType.PROTOCOL_RESPONSE, operation_id=operation_id, agent_id=self.agent_config.id, task_type="build_creative", status=raw_result.status, timestamp=datetime.now(timezone.utc).isoformat(), ) ) return self.adapter._parse_response(raw_result, BuildCreativeResponse)Generate production-ready creative assets.
Requests the creative agent to build final deliverable assets in the target format (e.g., VAST, DAAST, HTML5). This is typically called after previewing and approving a creative manifest.
Args
request- Creative build parameters including: - manifest: Creative manifest with brand info and content - target_format_id: Desired output format identifier - inputs: Optional user-provided inputs for template variables - deployment: Platform or agent deployment configuration
Returns
TaskResult containing BuildCreativeResponse with: - assets: Production-ready creative files (URLs or inline content) - format_id: The generated format identifier - manifest: The creative manifest used for generation - metadata: Additional platform-specific details
Example
>>> from adcp import ADCPClient, BuildCreativeRequest >>> client = ADCPClient(agent_config) >>> request = BuildCreativeRequest( ... manifest=creative_manifest, ... target_format_id="vast_2.0", ... inputs={"duration": 30} ... ) >>> result = await client.build_creative(request) >>> if result.success: ... vast_url = result.data.assets[0].url async def calibrate_content(self, request: CalibrateContentRequest) ‑> TaskResult[Union[CalibrateContentResponse1, CalibrateContentResponse2]]-
Expand source code
async def calibrate_content( self, request: CalibrateContentRequest, ) -> TaskResult[CalibrateContentResponse]: """ Calibrate content against standards. Evaluates content (artifact or URL) against configured standards to determine suitability for ad placement. Args: request: Request parameters including content to evaluate Returns: TaskResult containing CalibrateContentResponse with verdict """ operation_id = create_operation_id() params = request.model_dump(mode="json", exclude_none=True) self._emit_activity( Activity( type=ActivityType.PROTOCOL_REQUEST, operation_id=operation_id, agent_id=self.agent_config.id, task_type="calibrate_content", timestamp=datetime.now(timezone.utc).isoformat(), ) ) raw_result = await self.adapter.calibrate_content(params) self._emit_activity( Activity( type=ActivityType.PROTOCOL_RESPONSE, operation_id=operation_id, agent_id=self.agent_config.id, task_type="calibrate_content", status=raw_result.status, timestamp=datetime.now(timezone.utc).isoformat(), ) ) return self.adapter._parse_response(raw_result, CalibrateContentResponse)Calibrate content against standards.
Evaluates content (artifact or URL) against configured standards to determine suitability for ad placement.
Args
request- Request parameters including content to evaluate
Returns
TaskResult containing CalibrateContentResponse with verdict
async def check_governance(self,
request: CheckGovernanceRequest) ‑> TaskResult[CheckGovernanceResponse]-
Expand source code
async def check_governance( self, request: CheckGovernanceRequest, ) -> TaskResult[CheckGovernanceResponse]: """Check a proposed or committed action against campaign governance.""" operation_id = create_operation_id() params = request.model_dump(mode="json", exclude_none=True) self._emit_activity( Activity( type=ActivityType.PROTOCOL_REQUEST, operation_id=operation_id, agent_id=self.agent_config.id, task_type="check_governance", timestamp=datetime.now(timezone.utc).isoformat(), ) ) raw_result = await self.adapter.check_governance(params) self._emit_activity( Activity( type=ActivityType.PROTOCOL_RESPONSE, operation_id=operation_id, agent_id=self.agent_config.id, task_type="check_governance", status=raw_result.status, timestamp=datetime.now(timezone.utc).isoformat(), ) ) return self.adapter._parse_response(raw_result, CheckGovernanceResponse)Check a proposed or committed action against campaign governance.
async def close(self) ‑> None-
Expand source code
async def close(self) -> None: """Close the adapter and clean up resources.""" if hasattr(self.adapter, "close"): logger.debug(f"Closing adapter for agent {self.agent_config.id}") await self.adapter.close()Close the adapter and clean up resources.
async def comply_test_controller(self, request: ComplyTestControllerRequest) ‑> TaskResult[Union[ComplyTestControllerResponse1, ComplyTestControllerResponse2, ComplyTestControllerResponse3, ComplyTestControllerResponse4]]-
Expand source code
async def comply_test_controller( self, request: ComplyTestControllerRequest, ) -> TaskResult[ComplyTestControllerResponse]: """Compliance test controller for sandbox testing. Enables sellers to simulate state transitions and delivery data in a sandbox environment for compliance testing. Args: request: Request specifying scenario and parameters. Returns: TaskResult containing ComplyTestControllerResponse. """ operation_id = create_operation_id() params = request.model_dump(mode="json", exclude_none=True) self._emit_activity( Activity( type=ActivityType.PROTOCOL_REQUEST, operation_id=operation_id, agent_id=self.agent_config.id, task_type="comply_test_controller", timestamp=datetime.now(timezone.utc).isoformat(), ) ) raw_result = await self.adapter.comply_test_controller(params) self._emit_activity( Activity( type=ActivityType.PROTOCOL_RESPONSE, operation_id=operation_id, agent_id=self.agent_config.id, task_type="comply_test_controller", status=raw_result.status, timestamp=datetime.now(timezone.utc).isoformat(), ) ) return self.adapter._parse_response(raw_result, ComplyTestControllerResponse)Compliance test controller for sandbox testing.
Enables sellers to simulate state transitions and delivery data in a sandbox environment for compliance testing.
Args
request- Request specifying scenario and parameters.
Returns
TaskResult containing ComplyTestControllerResponse.
async def context_match(self,
request: ContextMatchRequest) ‑> TaskResult[ContextMatchResponse]-
Expand source code
async def context_match( self, request: ContextMatchRequest, ) -> TaskResult[ContextMatchResponse]: """Match ad context to buyer packages. Evaluates contextual signals for a publisher placement against the buyer's active packages and returns matching offers. Args: request: Context match request with placement, property, and optional artifact refs, context signals, and geo data. Returns: TaskResult containing ContextMatchResponse with offers. """ operation_id = create_operation_id() params = request.model_dump(mode="json", exclude_none=True, by_alias=True) self._emit_activity( Activity( type=ActivityType.PROTOCOL_REQUEST, operation_id=operation_id, agent_id=self.agent_config.id, task_type="context_match", timestamp=datetime.now(timezone.utc).isoformat(), ) ) raw_result = await self.adapter.context_match(params) self._emit_activity( Activity( type=ActivityType.PROTOCOL_RESPONSE, operation_id=operation_id, agent_id=self.agent_config.id, task_type="context_match", status=raw_result.status, timestamp=datetime.now(timezone.utc).isoformat(), ) ) return self.adapter._parse_response(raw_result, ContextMatchResponse)Match ad context to buyer packages.
Evaluates contextual signals for a publisher placement against the buyer's active packages and returns matching offers.
Args
request- Context match request with placement, property, and optional artifact refs, context signals, and geo data.
Returns
TaskResult containing ContextMatchResponse with offers.
async def create_content_standards(self, request: CreateContentStandardsRequest) ‑> TaskResult[Union[CreateContentStandardsResponse1, CreateContentStandardsResponse2]]-
Expand source code
async def create_content_standards( self, request: CreateContentStandardsRequest, ) -> TaskResult[CreateContentStandardsResponse]: """ Create a new content standards configuration. Defines acceptable content contexts for ad placement using natural language policy and optional calibration exemplars. Args: request: Request parameters including policy and scope Returns: TaskResult containing CreateContentStandardsResponse with standards_id """ operation_id = create_operation_id() params = request.model_dump(mode="json", exclude_none=True) self._emit_activity( Activity( type=ActivityType.PROTOCOL_REQUEST, operation_id=operation_id, agent_id=self.agent_config.id, task_type="create_content_standards", timestamp=datetime.now(timezone.utc).isoformat(), ) ) raw_result = await self.adapter.create_content_standards(params) self._emit_activity( Activity( type=ActivityType.PROTOCOL_RESPONSE, operation_id=operation_id, agent_id=self.agent_config.id, task_type="create_content_standards", status=raw_result.status, timestamp=datetime.now(timezone.utc).isoformat(), ) ) return self.adapter._parse_response(raw_result, CreateContentStandardsResponse)Create a new content standards configuration.
Defines acceptable content contexts for ad placement using natural language policy and optional calibration exemplars.
Args
request- Request parameters including policy and scope
Returns
TaskResult containing CreateContentStandardsResponse with standards_id
async def create_media_buy(self,
request: CreateMediaBuyRequest) ‑> TaskResult[Union[CreateMediaBuyResponse1, CreateMediaBuyResponse2]]-
Expand source code
async def create_media_buy( self, request: CreateMediaBuyRequest, ) -> TaskResult[CreateMediaBuyResponse]: """ Create a new media buy reservation. Requests the agent to reserve inventory for a campaign. The agent returns a media_buy_id that tracks this reservation and can be used for updates. Args: request: Media buy creation parameters including: - brand_manifest: Advertiser brand information and creative assets - packages: List of package requests specifying desired inventory - publisher_properties: Target properties for ad placement - budget: Optional budget constraints - start_date/end_date: Campaign flight dates Returns: TaskResult containing CreateMediaBuyResponse with: - media_buy_id: Unique identifier for this reservation - status: Current state of the media buy - packages: Confirmed package details - Additional platform-specific metadata Example: >>> from adcp import ADCPClient, CreateMediaBuyRequest >>> client = ADCPClient(agent_config) >>> request = CreateMediaBuyRequest( ... brand_manifest=brand, ... packages=[package_request], ... publisher_properties=properties ... ) >>> result = await client.create_media_buy(request) >>> if result.success: ... media_buy_id = result.data.media_buy_id """ operation_id = create_operation_id() params = request.model_dump(mode="json", exclude_none=True) self._emit_activity( Activity( type=ActivityType.PROTOCOL_REQUEST, operation_id=operation_id, agent_id=self.agent_config.id, task_type="create_media_buy", timestamp=datetime.now(timezone.utc).isoformat(), ) ) raw_result = await self.adapter.create_media_buy(params) self._emit_activity( Activity( type=ActivityType.PROTOCOL_RESPONSE, operation_id=operation_id, agent_id=self.agent_config.id, task_type="create_media_buy", status=raw_result.status, timestamp=datetime.now(timezone.utc).isoformat(), ) ) return self.adapter._parse_response(raw_result, CreateMediaBuyResponse)Create a new media buy reservation.
Requests the agent to reserve inventory for a campaign. The agent returns a media_buy_id that tracks this reservation and can be used for updates.
Args
request- Media buy creation parameters including: - brand_manifest: Advertiser brand information and creative assets - packages: List of package requests specifying desired inventory - publisher_properties: Target properties for ad placement - budget: Optional budget constraints - start_date/end_date: Campaign flight dates
Returns
TaskResult containing CreateMediaBuyResponse with: - media_buy_id: Unique identifier for this reservation - status: Current state of the media buy - packages: Confirmed package details - Additional platform-specific metadata
Example
>>> from adcp import ADCPClient, CreateMediaBuyRequest >>> client = ADCPClient(agent_config) >>> request = CreateMediaBuyRequest( ... brand_manifest=brand, ... packages=[package_request], ... publisher_properties=properties ... ) >>> result = await client.create_media_buy(request) >>> if result.success: ... media_buy_id = result.data.media_buy_id async def create_property_list(self, request: CreatePropertyListRequest) ‑> TaskResult[CreatePropertyListResponse]-
Expand source code
async def create_property_list( self, request: CreatePropertyListRequest, ) -> TaskResult[CreatePropertyListResponse]: """ Create a property list for governance filtering. Property lists define dynamic sets of properties based on filters, brand manifests, and feature requirements. Args: request: Request parameters for creating the property list Returns: TaskResult containing CreatePropertyListResponse with list_id """ operation_id = create_operation_id() params = request.model_dump(mode="json", exclude_none=True) self._emit_activity( Activity( type=ActivityType.PROTOCOL_REQUEST, operation_id=operation_id, agent_id=self.agent_config.id, task_type="create_property_list", timestamp=datetime.now(timezone.utc).isoformat(), ) ) raw_result = await self.adapter.create_property_list(params) self._emit_activity( Activity( type=ActivityType.PROTOCOL_RESPONSE, operation_id=operation_id, agent_id=self.agent_config.id, task_type="create_property_list", status=raw_result.status, timestamp=datetime.now(timezone.utc).isoformat(), ) ) return self.adapter._parse_response(raw_result, CreatePropertyListResponse)Create a property list for governance filtering.
Property lists define dynamic sets of properties based on filters, brand manifests, and feature requirements.
Args
request- Request parameters for creating the property list
Returns
TaskResult containing CreatePropertyListResponse with list_id
async def delete_property_list(self, request: DeletePropertyListRequest) ‑> TaskResult[DeletePropertyListResponse]-
Expand source code
async def delete_property_list( self, request: DeletePropertyListRequest, ) -> TaskResult[DeletePropertyListResponse]: """ Delete a property list. Removes a property list. Any active subscriptions to this list will be terminated. Args: request: Request parameters with list_id Returns: TaskResult containing DeletePropertyListResponse """ operation_id = create_operation_id() params = request.model_dump(mode="json", exclude_none=True) self._emit_activity( Activity( type=ActivityType.PROTOCOL_REQUEST, operation_id=operation_id, agent_id=self.agent_config.id, task_type="delete_property_list", timestamp=datetime.now(timezone.utc).isoformat(), ) ) raw_result = await self.adapter.delete_property_list(params) self._emit_activity( Activity( type=ActivityType.PROTOCOL_RESPONSE, operation_id=operation_id, agent_id=self.agent_config.id, task_type="delete_property_list", status=raw_result.status, timestamp=datetime.now(timezone.utc).isoformat(), ) ) return self.adapter._parse_response(raw_result, DeletePropertyListResponse)Delete a property list.
Removes a property list. Any active subscriptions to this list will be terminated.
Args
request- Request parameters with list_id
Returns
TaskResult containing DeletePropertyListResponse
async def fetch_capabilities(self) ‑> GetAdcpCapabilitiesResponse-
Expand source code
async def fetch_capabilities(self) -> GetAdcpCapabilitiesResponse: """Fetch capabilities, using cache if still valid. Returns: The seller's capabilities response. """ if self._capabilities is not None and self._capabilities_fetched_at is not None: elapsed = time.monotonic() - self._capabilities_fetched_at if elapsed < self.capabilities_ttl: return self._capabilities return await self.refresh_capabilities()Fetch capabilities, using cache if still valid.
Returns
The seller's capabilities response.
async def get_account_financials(self,
request: GetAccountFinancialsRequest) ‑> TaskResult[Union[GetAccountFinancialsResponse1, GetAccountFinancialsResponse2]]-
Expand source code
async def get_account_financials( self, request: GetAccountFinancialsRequest, ) -> TaskResult[GetAccountFinancialsResponse]: """ Get Account Financials. Args: request: Request parameters Returns: TaskResult containing GetAccountFinancialsResponse """ operation_id = create_operation_id() params = request.model_dump(mode="json", exclude_none=True) self._emit_activity( Activity( type=ActivityType.PROTOCOL_REQUEST, operation_id=operation_id, agent_id=self.agent_config.id, task_type="get_account_financials", timestamp=datetime.now(timezone.utc).isoformat(), ) ) raw_result = await self.adapter.get_account_financials(params) self._emit_activity( Activity( type=ActivityType.PROTOCOL_RESPONSE, operation_id=operation_id, agent_id=self.agent_config.id, task_type="get_account_financials", status=raw_result.status, timestamp=datetime.now(timezone.utc).isoformat(), ) ) return self.adapter._parse_response(raw_result, GetAccountFinancialsResponse)Get Account Financials.
Args
request- Request parameters
Returns
TaskResult containing GetAccountFinancialsResponse
async def get_adcp_capabilities(self, request: GetAdcpCapabilitiesRequest) ‑> TaskResult[GetAdcpCapabilitiesResponse]-
Expand source code
async def get_adcp_capabilities( self, request: GetAdcpCapabilitiesRequest, ) -> TaskResult[GetAdcpCapabilitiesResponse]: """ Get AdCP capabilities from the agent. Queries the agent's supported AdCP features, protocol versions, and domain-specific capabilities (media_buy, signals, sponsored_intelligence). Args: request: Request parameters including optional protocol filters Returns: TaskResult containing GetAdcpCapabilitiesResponse with: - adcp: Core protocol version information - supported_protocols: List of supported domain protocols - media_buy: Media buy capabilities (if supported) - sponsored_intelligence: SI capabilities (if supported) - signals: Signals capabilities (if supported) """ operation_id = create_operation_id() params = request.model_dump(mode="json", exclude_none=True) self._emit_activity( Activity( type=ActivityType.PROTOCOL_REQUEST, operation_id=operation_id, agent_id=self.agent_config.id, task_type="get_adcp_capabilities", timestamp=datetime.now(timezone.utc).isoformat(), ) ) raw_result = await self.adapter.get_adcp_capabilities(params) self._emit_activity( Activity( type=ActivityType.PROTOCOL_RESPONSE, operation_id=operation_id, agent_id=self.agent_config.id, task_type="get_adcp_capabilities", status=raw_result.status, timestamp=datetime.now(timezone.utc).isoformat(), ) ) return self.adapter._parse_response(raw_result, GetAdcpCapabilitiesResponse)Get AdCP capabilities from the agent.
Queries the agent's supported AdCP features, protocol versions, and domain-specific capabilities (media_buy, signals, sponsored_intelligence).
Args
request- Request parameters including optional protocol filters
Returns
TaskResult containing GetAdcpCapabilitiesResponse with: - adcp: Core protocol version information - supported_protocols: List of supported domain protocols - media_buy: Media buy capabilities (if supported) - sponsored_intelligence: SI capabilities (if supported) - signals: Signals capabilities (if supported)
async def get_brand_identity(self,
request: GetBrandIdentityRequest) ‑> TaskResult[Union[GetBrandIdentityResponse1, GetBrandIdentityResponse2]]-
Expand source code
async def get_brand_identity( self, request: GetBrandIdentityRequest, ) -> TaskResult[GetBrandIdentityResponse]: """Get brand identity information. Retrieves brand identity data including logos, colors, fonts, voice synthesis config, and rights availability. Args: request: Request with brand_id and optional fields filter. Returns: TaskResult containing GetBrandIdentityResponse. """ operation_id = create_operation_id() params = request.model_dump(mode="json", exclude_none=True) self._emit_activity( Activity( type=ActivityType.PROTOCOL_REQUEST, operation_id=operation_id, agent_id=self.agent_config.id, task_type="get_brand_identity", timestamp=datetime.now(timezone.utc).isoformat(), ) ) raw_result = await self.adapter.get_brand_identity(params) self._emit_activity( Activity( type=ActivityType.PROTOCOL_RESPONSE, operation_id=operation_id, agent_id=self.agent_config.id, task_type="get_brand_identity", status=raw_result.status, timestamp=datetime.now(timezone.utc).isoformat(), ) ) return self.adapter._parse_response(raw_result, GetBrandIdentityResponse)Get brand identity information.
Retrieves brand identity data including logos, colors, fonts, voice synthesis config, and rights availability.
Args
request- Request with brand_id and optional fields filter.
Returns
TaskResult containing GetBrandIdentityResponse.
async def get_content_standards(self, request: GetContentStandardsRequest) ‑> TaskResult[Union[GetContentStandardsResponse1, GetContentStandardsResponse2]]-
Expand source code
async def get_content_standards( self, request: GetContentStandardsRequest, ) -> TaskResult[GetContentStandardsResponse]: """ Get a content standards configuration by ID. Args: request: Request parameters including standards_id Returns: TaskResult containing GetContentStandardsResponse """ operation_id = create_operation_id() params = request.model_dump(mode="json", exclude_none=True) self._emit_activity( Activity( type=ActivityType.PROTOCOL_REQUEST, operation_id=operation_id, agent_id=self.agent_config.id, task_type="get_content_standards", timestamp=datetime.now(timezone.utc).isoformat(), ) ) raw_result = await self.adapter.get_content_standards(params) self._emit_activity( Activity( type=ActivityType.PROTOCOL_RESPONSE, operation_id=operation_id, agent_id=self.agent_config.id, task_type="get_content_standards", status=raw_result.status, timestamp=datetime.now(timezone.utc).isoformat(), ) ) return self.adapter._parse_response(raw_result, GetContentStandardsResponse)Get a content standards configuration by ID.
Args
request- Request parameters including standards_id
Returns
TaskResult containing GetContentStandardsResponse
async def get_creative_delivery(self,
request: GetCreativeDeliveryRequest) ‑> TaskResult[GetCreativeDeliveryResponse]-
Expand source code
async def get_creative_delivery( self, request: GetCreativeDeliveryRequest, ) -> TaskResult[GetCreativeDeliveryResponse]: """ Get Creative Delivery. Args: request: Request parameters Returns: TaskResult containing GetCreativeDeliveryResponse """ operation_id = create_operation_id() params = request.model_dump(mode="json", exclude_none=True) self._emit_activity( Activity( type=ActivityType.PROTOCOL_REQUEST, operation_id=operation_id, agent_id=self.agent_config.id, task_type="get_creative_delivery", timestamp=datetime.now(timezone.utc).isoformat(), ) ) raw_result = await self.adapter.get_creative_delivery(params) self._emit_activity( Activity( type=ActivityType.PROTOCOL_RESPONSE, operation_id=operation_id, agent_id=self.agent_config.id, task_type="get_creative_delivery", status=raw_result.status, timestamp=datetime.now(timezone.utc).isoformat(), ) ) return self.adapter._parse_response(raw_result, GetCreativeDeliveryResponse)Get Creative Delivery.
Args
request- Request parameters
Returns
TaskResult containing GetCreativeDeliveryResponse
async def get_creative_features(self,
request: GetCreativeFeaturesRequest) ‑> TaskResult[Union[GetCreativeFeaturesResponse1, GetCreativeFeaturesResponse2]]-
Expand source code
async def get_creative_features( self, request: GetCreativeFeaturesRequest, ) -> TaskResult[GetCreativeFeaturesResponse]: """Evaluate governance features for a creative manifest.""" operation_id = create_operation_id() params = request.model_dump(mode="json", exclude_none=True) self._emit_activity( Activity( type=ActivityType.PROTOCOL_REQUEST, operation_id=operation_id, agent_id=self.agent_config.id, task_type="get_creative_features", timestamp=datetime.now(timezone.utc).isoformat(), ) ) raw_result = await self.adapter.get_creative_features(params) self._emit_activity( Activity( type=ActivityType.PROTOCOL_RESPONSE, operation_id=operation_id, agent_id=self.agent_config.id, task_type="get_creative_features", status=raw_result.status, timestamp=datetime.now(timezone.utc).isoformat(), ) ) return self.adapter._parse_response(raw_result, GetCreativeFeaturesResponse)Evaluate governance features for a creative manifest.
async def get_info(self) ‑> dict[str, typing.Any]-
Expand source code
async def get_info(self) -> dict[str, Any]: """ Get agent information including AdCP extension metadata. Returns agent card information including: - Agent name, description, version - Protocol type (mcp or a2a) - AdCP version (from extensions.adcp.adcp_version) - Supported protocols (from extensions.adcp.protocols_supported) - Available tools/skills Returns: Dictionary with agent metadata """ return await self.adapter.get_agent_info()Get agent information including AdCP extension metadata.
Returns agent card information including: - Agent name, description, version - Protocol type (mcp or a2a) - AdCP version (from extensions.adcp.adcp_version) - Supported protocols (from extensions.adcp.protocols_supported) - Available tools/skills
Returns
Dictionary with agent metadata
async def get_media_buy_artifacts(self, request: GetMediaBuyArtifactsRequest) ‑> TaskResult[Union[GetMediaBuyArtifactsResponse1, GetMediaBuyArtifactsResponse2]]-
Expand source code
async def get_media_buy_artifacts( self, request: GetMediaBuyArtifactsRequest, ) -> TaskResult[GetMediaBuyArtifactsResponse]: """ Get artifacts associated with a media buy. Retrieves content artifacts where ads were delivered for a media buy. Args: request: Request parameters including media_buy_id Returns: TaskResult containing GetMediaBuyArtifactsResponse """ operation_id = create_operation_id() params = request.model_dump(mode="json", exclude_none=True) self._emit_activity( Activity( type=ActivityType.PROTOCOL_REQUEST, operation_id=operation_id, agent_id=self.agent_config.id, task_type="get_media_buy_artifacts", timestamp=datetime.now(timezone.utc).isoformat(), ) ) raw_result = await self.adapter.get_media_buy_artifacts(params) self._emit_activity( Activity( type=ActivityType.PROTOCOL_RESPONSE, operation_id=operation_id, agent_id=self.agent_config.id, task_type="get_media_buy_artifacts", status=raw_result.status, timestamp=datetime.now(timezone.utc).isoformat(), ) ) return self.adapter._parse_response(raw_result, GetMediaBuyArtifactsResponse)Get artifacts associated with a media buy.
Retrieves content artifacts where ads were delivered for a media buy.
Args
request- Request parameters including media_buy_id
Returns
TaskResult containing GetMediaBuyArtifactsResponse
async def get_media_buy_delivery(self,
request: GetMediaBuyDeliveryRequest) ‑> TaskResult[GetMediaBuyDeliveryResponse]-
Expand source code
async def get_media_buy_delivery( self, request: GetMediaBuyDeliveryRequest, ) -> TaskResult[GetMediaBuyDeliveryResponse]: """ Get Media Buy Delivery. Args: request: Request parameters Returns: TaskResult containing GetMediaBuyDeliveryResponse """ operation_id = create_operation_id() params = request.model_dump(mode="json", exclude_none=True) self._emit_activity( Activity( type=ActivityType.PROTOCOL_REQUEST, operation_id=operation_id, agent_id=self.agent_config.id, task_type="get_media_buy_delivery", timestamp=datetime.now(timezone.utc).isoformat(), ) ) raw_result = await self.adapter.get_media_buy_delivery(params) self._emit_activity( Activity( type=ActivityType.PROTOCOL_RESPONSE, operation_id=operation_id, agent_id=self.agent_config.id, task_type="get_media_buy_delivery", status=raw_result.status, timestamp=datetime.now(timezone.utc).isoformat(), ) ) return self.adapter._parse_response(raw_result, GetMediaBuyDeliveryResponse)Get Media Buy Delivery.
Args
request- Request parameters
Returns
TaskResult containing GetMediaBuyDeliveryResponse
async def get_media_buys(self,
request: GetMediaBuysRequest) ‑> TaskResult[GetMediaBuysResponse]-
Expand source code
async def get_media_buys( self, request: GetMediaBuysRequest, ) -> TaskResult[GetMediaBuysResponse]: """ Get Media Buys. Args: request: Request parameters Returns: TaskResult containing GetMediaBuysResponse """ operation_id = create_operation_id() params = request.model_dump(mode="json", exclude_none=True) self._emit_activity( Activity( type=ActivityType.PROTOCOL_REQUEST, operation_id=operation_id, agent_id=self.agent_config.id, task_type="get_media_buys", timestamp=datetime.now(timezone.utc).isoformat(), ) ) raw_result = await self.adapter.get_media_buys(params) self._emit_activity( Activity( type=ActivityType.PROTOCOL_RESPONSE, operation_id=operation_id, agent_id=self.agent_config.id, task_type="get_media_buys", status=raw_result.status, timestamp=datetime.now(timezone.utc).isoformat(), ) ) return self.adapter._parse_response(raw_result, GetMediaBuysResponse)Get Media Buys.
Args
request- Request parameters
Returns
TaskResult containing GetMediaBuysResponse
async def get_plan_audit_logs(self,
request: GetPlanAuditLogsRequest) ‑> TaskResult[GetPlanAuditLogsResponse]-
Expand source code
async def get_plan_audit_logs( self, request: GetPlanAuditLogsRequest, ) -> TaskResult[GetPlanAuditLogsResponse]: """Retrieve governance state and audit logs for one or more plans.""" operation_id = create_operation_id() params = request.model_dump(mode="json", exclude_none=True) self._emit_activity( Activity( type=ActivityType.PROTOCOL_REQUEST, operation_id=operation_id, agent_id=self.agent_config.id, task_type="get_plan_audit_logs", timestamp=datetime.now(timezone.utc).isoformat(), ) ) raw_result = await self.adapter.get_plan_audit_logs(params) self._emit_activity( Activity( type=ActivityType.PROTOCOL_RESPONSE, operation_id=operation_id, agent_id=self.agent_config.id, task_type="get_plan_audit_logs", status=raw_result.status, timestamp=datetime.now(timezone.utc).isoformat(), ) ) return self.adapter._parse_response(raw_result, GetPlanAuditLogsResponse)Retrieve governance state and audit logs for one or more plans.
async def get_products(self,
request: GetProductsRequest,
fetch_previews: bool = False,
preview_output_format: str = 'url',
creative_agent_client: ADCPClient | None = None) ‑> TaskResult[GetProductsResponse]-
Expand source code
async def get_products( self, request: GetProductsRequest, fetch_previews: bool = False, preview_output_format: str = "url", creative_agent_client: ADCPClient | None = None, ) -> TaskResult[GetProductsResponse]: """ Get advertising products. Args: request: Request parameters fetch_previews: If True, generate preview URLs for each product's formats (uses batch API for 5-10x performance improvement) preview_output_format: "url" for iframe URLs (default), "html" for direct embedding (2-3x faster, no iframe overhead) creative_agent_client: Client for creative agent (required if fetch_previews=True) Returns: TaskResult containing GetProductsResponse with optional preview URLs in metadata Raises: ValueError: If fetch_previews=True but creative_agent_client is not provided """ if fetch_previews and not creative_agent_client: raise ValueError("creative_agent_client is required when fetch_previews=True") operation_id = create_operation_id() params = request.model_dump(mode="json", exclude_none=True) self._emit_activity( Activity( type=ActivityType.PROTOCOL_REQUEST, operation_id=operation_id, agent_id=self.agent_config.id, task_type="get_products", timestamp=datetime.now(timezone.utc).isoformat(), ) ) raw_result = await self.adapter.get_products(params) self._emit_activity( Activity( type=ActivityType.PROTOCOL_RESPONSE, operation_id=operation_id, agent_id=self.agent_config.id, task_type="get_products", status=raw_result.status, timestamp=datetime.now(timezone.utc).isoformat(), ) ) result: TaskResult[GetProductsResponse] = self.adapter._parse_response( raw_result, GetProductsResponse ) if fetch_previews and result.success and result.data and creative_agent_client: from adcp.utils.preview_cache import add_preview_urls_to_products products_with_previews = await add_preview_urls_to_products( result.data.products, creative_agent_client, use_batch=True, output_format=preview_output_format, ) result.metadata = result.metadata or {} result.metadata["products_with_previews"] = products_with_previews return resultGet advertising products.
Args
request- Request parameters
fetch_previews- If True, generate preview URLs for each product's formats (uses batch API for 5-10x performance improvement)
preview_output_format- "url" for iframe URLs (default), "html" for direct embedding (2-3x faster, no iframe overhead)
creative_agent_client- Client for creative agent (required if fetch_previews=True)
Returns
TaskResult containing GetProductsResponse with optional preview URLs in metadata
Raises
ValueError- If fetch_previews=True but creative_agent_client is not provided
async def get_property_list(self, request: GetPropertyListRequest) ‑> TaskResult[GetPropertyListResponse]-
Expand source code
async def get_property_list( self, request: GetPropertyListRequest, ) -> TaskResult[GetPropertyListResponse]: """ Get a property list with optional resolution. When resolve=true, returns the list of resolved property identifiers. Use this to get the actual properties that match the list's filters. Args: request: Request parameters including list_id and resolve flag Returns: TaskResult containing GetPropertyListResponse with identifiers """ operation_id = create_operation_id() params = request.model_dump(mode="json", exclude_none=True) self._emit_activity( Activity( type=ActivityType.PROTOCOL_REQUEST, operation_id=operation_id, agent_id=self.agent_config.id, task_type="get_property_list", timestamp=datetime.now(timezone.utc).isoformat(), ) ) raw_result = await self.adapter.get_property_list(params) self._emit_activity( Activity( type=ActivityType.PROTOCOL_RESPONSE, operation_id=operation_id, agent_id=self.agent_config.id, task_type="get_property_list", status=raw_result.status, timestamp=datetime.now(timezone.utc).isoformat(), ) ) return self.adapter._parse_response(raw_result, GetPropertyListResponse)Get a property list with optional resolution.
When resolve=true, returns the list of resolved property identifiers. Use this to get the actual properties that match the list's filters.
Args
request- Request parameters including list_id and resolve flag
Returns
TaskResult containing GetPropertyListResponse with identifiers
async def get_rights(self,
request: GetRightsRequest) ‑> TaskResult[Union[GetRightsResponse1, GetRightsResponse2]]-
Expand source code
async def get_rights( self, request: GetRightsRequest, ) -> TaskResult[GetRightsResponse]: """Get available rights for licensing. Searches for rights offerings using natural language query and filters by type, uses, countries, and buyer compatibility. Args: request: Request with query, uses, and optional filters. Returns: TaskResult containing GetRightsResponse with matched rights. """ operation_id = create_operation_id() params = request.model_dump(mode="json", exclude_none=True) self._emit_activity( Activity( type=ActivityType.PROTOCOL_REQUEST, operation_id=operation_id, agent_id=self.agent_config.id, task_type="get_rights", timestamp=datetime.now(timezone.utc).isoformat(), ) ) raw_result = await self.adapter.get_rights(params) self._emit_activity( Activity( type=ActivityType.PROTOCOL_RESPONSE, operation_id=operation_id, agent_id=self.agent_config.id, task_type="get_rights", status=raw_result.status, timestamp=datetime.now(timezone.utc).isoformat(), ) ) return self.adapter._parse_response(raw_result, GetRightsResponse)Get available rights for licensing.
Searches for rights offerings using natural language query and filters by type, uses, countries, and buyer compatibility.
Args
request- Request with query, uses, and optional filters.
Returns
TaskResult containing GetRightsResponse with matched rights.
async def get_signals(self,
request: GetSignalsRequest) ‑> TaskResult[GetSignalsResponse]-
Expand source code
async def get_signals( self, request: GetSignalsRequest, ) -> TaskResult[GetSignalsResponse]: """ Get Signals. Args: request: Request parameters Returns: TaskResult containing GetSignalsResponse """ operation_id = create_operation_id() params = request.model_dump(mode="json", exclude_none=True) self._emit_activity( Activity( type=ActivityType.PROTOCOL_REQUEST, operation_id=operation_id, agent_id=self.agent_config.id, task_type="get_signals", timestamp=datetime.now(timezone.utc).isoformat(), ) ) raw_result = await self.adapter.get_signals(params) self._emit_activity( Activity( type=ActivityType.PROTOCOL_RESPONSE, operation_id=operation_id, agent_id=self.agent_config.id, task_type="get_signals", status=raw_result.status, timestamp=datetime.now(timezone.utc).isoformat(), ) ) return self.adapter._parse_response(raw_result, GetSignalsResponse)Get Signals.
Args
request- Request parameters
Returns
TaskResult containing GetSignalsResponse
def get_webhook_url(self, task_type: str, operation_id: str) ‑> str-
Expand source code
def get_webhook_url(self, task_type: str, operation_id: str) -> str: """Generate webhook URL for a task.""" if not self.webhook_url_template: raise ValueError("webhook_url_template not configured") return self.webhook_url_template.format( agent_id=self.agent_config.id, task_type=task_type, operation_id=operation_id, )Generate webhook URL for a task.
async def handle_webhook(self,
payload: dict[str, Any] | Task | TaskStatusUpdateEvent,
task_type: str,
operation_id: str,
signature: str | None = None,
timestamp: str | None = None,
raw_body: bytes | str | None = None) ‑> TaskResult[AdcpAsyncResponseData]-
Expand source code
async def handle_webhook( self, payload: dict[str, Any] | Task | TaskStatusUpdateEvent, task_type: str, operation_id: str, signature: str | None = None, timestamp: str | None = None, raw_body: bytes | str | None = None, ) -> TaskResult[AdcpAsyncResponseData]: """ Handle incoming webhook and return typed result. This method provides a unified interface for handling webhooks from both MCP and A2A protocols: - MCP Webhooks: HTTP POST with dict payload, optional HMAC signature - A2A Webhooks: Task or TaskStatusUpdateEvent objects based on status The method automatically detects the protocol type and routes to the appropriate handler. Both protocols return a consistent TaskResult structure with typed AdCP response data. Args: payload: Webhook payload - one of: - dict[str, Any]: MCP webhook payload from HTTP POST - Task: A2A webhook for terminated statuses (completed, failed) - TaskStatusUpdateEvent: A2A webhook for intermediate statuses (working, input-required, submitted) task_type: Task type from application routing (e.g., "get_products"). Applications should extract this from URL routing pattern: /webhook/{task_type}/{agent_id}/{operation_id} operation_id: Operation identifier from application routing. Used to correlate webhook notifications with original task submission. signature: Optional HMAC-SHA256 signature for MCP webhook verification (X-AdCP-Signature header). Ignored for A2A webhooks. timestamp: Optional Unix timestamp (seconds) for MCP webhook signature verification (X-AdCP-Timestamp header). Required when signature is provided. raw_body: Optional raw HTTP request body bytes for signature verification. When provided, used directly instead of re-serializing the payload, avoiding cross-language JSON serialization mismatches. Strongly recommended for production use. Returns: TaskResult with parsed task-specific response data. The structure is identical regardless of protocol. Raises: ADCPWebhookSignatureError: If MCP signature verification fails ValidationError: If MCP payload doesn't match WebhookPayload schema Note: task_type and operation_id were deprecated from the webhook payload per AdCP specification. Applications must extract these from URL routing and pass them explicitly. Examples: MCP webhook (HTTP endpoint): >>> @app.post("/webhook/{task_type}/{agent_id}/{operation_id}") >>> async def webhook_handler(task_type: str, operation_id: str, request: Request): >>> raw_body = await request.body() >>> payload = json.loads(raw_body) >>> signature = request.headers.get("X-AdCP-Signature") >>> timestamp = request.headers.get("X-AdCP-Timestamp") >>> result = await client.handle_webhook( >>> payload, task_type, operation_id, signature, timestamp, >>> raw_body=raw_body, >>> ) >>> if result.success: >>> print(f"Task completed: {result.data}") A2A webhook with Task (terminated status): >>> async def on_task_completed(task: Task): >>> # Extract task_type and operation_id from your app's task tracking >>> task_type = your_task_registry.get_type(task.id) >>> operation_id = your_task_registry.get_operation_id(task.id) >>> result = await client.handle_webhook( >>> task, task_type, operation_id >>> ) >>> if result.success: >>> print(f"Task completed: {result.data}") A2A webhook with TaskStatusUpdateEvent (intermediate status): >>> async def on_task_update(event: TaskStatusUpdateEvent): >>> # Extract task_type and operation_id from your app's task tracking >>> task_type = your_task_registry.get_type(event.task_id) >>> operation_id = your_task_registry.get_operation_id(event.task_id) >>> result = await client.handle_webhook( >>> event, task_type, operation_id >>> ) >>> if result.status == GeneratedTaskStatus.working: >>> print(f"Task still working: {result.metadata.get('message')}") """ # Detect protocol type and route to appropriate handler if isinstance(payload, (Task, TaskStatusUpdateEvent)): # A2A webhook (Task or TaskStatusUpdateEvent) return await self._handle_a2a_webhook(payload, task_type, operation_id) else: # MCP webhook (dict payload) return await self._handle_mcp_webhook( payload, task_type, operation_id, signature, timestamp, raw_body )Handle incoming webhook and return typed result.
This method provides a unified interface for handling webhooks from both MCP and A2A protocols:
- MCP Webhooks: HTTP POST with dict payload, optional HMAC signature
- A2A Webhooks: Task or TaskStatusUpdateEvent objects based on status
The method automatically detects the protocol type and routes to the appropriate handler. Both protocols return a consistent TaskResult structure with typed AdCP response data.
Args
payload- Webhook payload - one of: - dict[str, Any]: MCP webhook payload from HTTP POST - Task: A2A webhook for terminated statuses (completed, failed) - TaskStatusUpdateEvent: A2A webhook for intermediate statuses (working, input-required, submitted)
task_type- Task type from application routing (e.g., "get_products"). Applications should extract this from URL routing pattern: /webhook/{task_type}/{agent_id}/{operation_id}
operation_id- Operation identifier from application routing. Used to correlate webhook notifications with original task submission.
signature- Optional HMAC-SHA256 signature for MCP webhook verification (X-AdCP-Signature header). Ignored for A2A webhooks.
timestamp- Optional Unix timestamp (seconds) for MCP webhook signature verification (X-AdCP-Timestamp header). Required when signature is provided.
raw_body- Optional raw HTTP request body bytes for signature verification. When provided, used directly instead of re-serializing the payload, avoiding cross-language JSON serialization mismatches. Strongly recommended for production use.
Returns
TaskResult with parsed task-specific response data. The structure is identical regardless of protocol.
Raises
ADCPWebhookSignatureError- If MCP signature verification fails
ValidationError- If MCP payload doesn't match WebhookPayload schema
Note
task_type and operation_id were deprecated from the webhook payload per AdCP specification. Applications must extract these from URL routing and pass them explicitly.
Examples
MCP webhook (HTTP endpoint):
>>> @app.post("/webhook/{task_type}/{agent_id}/{operation_id}") >>> async def webhook_handler(task_type: str, operation_id: str, request: Request): >>> raw_body = await request.body() >>> payload = json.loads(raw_body) >>> signature = request.headers.get("X-AdCP-Signature") >>> timestamp = request.headers.get("X-AdCP-Timestamp") >>> result = await client.handle_webhook( >>> payload, task_type, operation_id, signature, timestamp, >>> raw_body=raw_body, >>> ) >>> if result.success: >>> print(f"Task completed: {result.data}")A2A webhook with Task (terminated status):
>>> async def on_task_completed(task: Task): >>> # Extract task_type and operation_id from your app's task tracking >>> task_type = your_task_registry.get_type(task.id) >>> operation_id = your_task_registry.get_operation_id(task.id) >>> result = await client.handle_webhook( >>> task, task_type, operation_id >>> ) >>> if result.success: >>> print(f"Task completed: {result.data}")A2A webhook with TaskStatusUpdateEvent (intermediate status):
>>> async def on_task_update(event: TaskStatusUpdateEvent): >>> # Extract task_type and operation_id from your app's task tracking >>> task_type = your_task_registry.get_type(event.task_id) >>> operation_id = your_task_registry.get_operation_id(event.task_id) >>> result = await client.handle_webhook( >>> event, task_type, operation_id >>> ) >>> if result.status == GeneratedTaskStatus.working: >>> print(f"Task still working: {result.metadata.get('message')}") async def identity_match(self,
request: IdentityMatchRequest) ‑> TaskResult[IdentityMatchResponse]-
Expand source code
async def identity_match( self, request: IdentityMatchRequest, ) -> TaskResult[IdentityMatchResponse]: """Match user identity for package eligibility. Evaluates a user identity token against all active packages for frequency capping and personalization. Args: request: Identity match request with user_token, uid_type, and package_ids. Returns: TaskResult containing IdentityMatchResponse with eligible_package_ids. """ operation_id = create_operation_id() params = request.model_dump(mode="json", exclude_none=True, by_alias=True) self._emit_activity( Activity( type=ActivityType.PROTOCOL_REQUEST, operation_id=operation_id, agent_id=self.agent_config.id, task_type="identity_match", timestamp=datetime.now(timezone.utc).isoformat(), ) ) raw_result = await self.adapter.identity_match(params) self._emit_activity( Activity( type=ActivityType.PROTOCOL_RESPONSE, operation_id=operation_id, agent_id=self.agent_config.id, task_type="identity_match", status=raw_result.status, timestamp=datetime.now(timezone.utc).isoformat(), ) ) return self.adapter._parse_response(raw_result, IdentityMatchResponse)Match user identity for package eligibility.
Evaluates a user identity token against all active packages for frequency capping and personalization.
Args
request- Identity match request with user_token, uid_type, and package_ids.
Returns
TaskResult containing IdentityMatchResponse with eligible_package_ids.
async def list_accounts(self,
request: ListAccountsRequest) ‑> TaskResult[ListAccountsResponse]-
Expand source code
async def list_accounts( self, request: ListAccountsRequest, ) -> TaskResult[ListAccountsResponse]: """ List Accounts. Args: request: Request parameters Returns: TaskResult containing ListAccountsResponse """ operation_id = create_operation_id() params = request.model_dump(mode="json", exclude_none=True) self._emit_activity( Activity( type=ActivityType.PROTOCOL_REQUEST, operation_id=operation_id, agent_id=self.agent_config.id, task_type="list_accounts", timestamp=datetime.now(timezone.utc).isoformat(), ) ) raw_result = await self.adapter.list_accounts(params) self._emit_activity( Activity( type=ActivityType.PROTOCOL_RESPONSE, operation_id=operation_id, agent_id=self.agent_config.id, task_type="list_accounts", status=raw_result.status, timestamp=datetime.now(timezone.utc).isoformat(), ) ) return self.adapter._parse_response(raw_result, ListAccountsResponse)List Accounts.
Args
request- Request parameters
Returns
TaskResult containing ListAccountsResponse
async def list_content_standards(self, request: ListContentStandardsRequest) ‑> TaskResult[Union[ListContentStandardsResponse1, ListContentStandardsResponse2]]-
Expand source code
async def list_content_standards( self, request: ListContentStandardsRequest, ) -> TaskResult[ListContentStandardsResponse]: """ List content standards configurations. Args: request: Request parameters including optional filters Returns: TaskResult containing ListContentStandardsResponse """ operation_id = create_operation_id() params = request.model_dump(mode="json", exclude_none=True) self._emit_activity( Activity( type=ActivityType.PROTOCOL_REQUEST, operation_id=operation_id, agent_id=self.agent_config.id, task_type="list_content_standards", timestamp=datetime.now(timezone.utc).isoformat(), ) ) raw_result = await self.adapter.list_content_standards(params) self._emit_activity( Activity( type=ActivityType.PROTOCOL_RESPONSE, operation_id=operation_id, agent_id=self.agent_config.id, task_type="list_content_standards", status=raw_result.status, timestamp=datetime.now(timezone.utc).isoformat(), ) ) return self.adapter._parse_response(raw_result, ListContentStandardsResponse)List content standards configurations.
Args
request- Request parameters including optional filters
Returns
TaskResult containing ListContentStandardsResponse
async def list_creative_formats(self,
request: ListCreativeFormatsRequest,
fetch_previews: bool = False,
preview_output_format: str = 'url') ‑> TaskResult[ListCreativeFormatsResponse]-
Expand source code
async def list_creative_formats( self, request: ListCreativeFormatsRequest, fetch_previews: bool = False, preview_output_format: str = "url", ) -> TaskResult[ListCreativeFormatsResponse]: """ List supported creative formats. Args: request: Request parameters fetch_previews: If True, generate preview URLs for each format using sample manifests (uses batch API for 5-10x performance improvement) preview_output_format: "url" for iframe URLs (default), "html" for direct embedding (2-3x faster, no iframe overhead) Returns: TaskResult containing ListCreativeFormatsResponse with optional preview URLs in metadata """ operation_id = create_operation_id() params = request.model_dump(mode="json", exclude_none=True) self._emit_activity( Activity( type=ActivityType.PROTOCOL_REQUEST, operation_id=operation_id, agent_id=self.agent_config.id, task_type="list_creative_formats", timestamp=datetime.now(timezone.utc).isoformat(), ) ) raw_result = await self.adapter.list_creative_formats(params) self._emit_activity( Activity( type=ActivityType.PROTOCOL_RESPONSE, operation_id=operation_id, agent_id=self.agent_config.id, task_type="list_creative_formats", status=raw_result.status, timestamp=datetime.now(timezone.utc).isoformat(), ) ) result: TaskResult[ListCreativeFormatsResponse] = self.adapter._parse_response( raw_result, ListCreativeFormatsResponse ) if fetch_previews and result.success and result.data: from adcp.utils.preview_cache import add_preview_urls_to_formats formats_with_previews = await add_preview_urls_to_formats( result.data.formats, self, use_batch=True, output_format=preview_output_format, ) result.metadata = result.metadata or {} result.metadata["formats_with_previews"] = formats_with_previews return resultList supported creative formats.
Args
request- Request parameters
fetch_previews- If True, generate preview URLs for each format using sample manifests (uses batch API for 5-10x performance improvement)
preview_output_format- "url" for iframe URLs (default), "html" for direct embedding (2-3x faster, no iframe overhead)
Returns
TaskResult containing ListCreativeFormatsResponse with optional preview URLs in metadata
async def list_creatives(self,
request: ListCreativesRequest) ‑> TaskResult[ListCreativesResponse]-
Expand source code
async def list_creatives( self, request: ListCreativesRequest, ) -> TaskResult[ListCreativesResponse]: """ List Creatives. Args: request: Request parameters Returns: TaskResult containing ListCreativesResponse """ operation_id = create_operation_id() params = request.model_dump(mode="json", exclude_none=True) self._emit_activity( Activity( type=ActivityType.PROTOCOL_REQUEST, operation_id=operation_id, agent_id=self.agent_config.id, task_type="list_creatives", timestamp=datetime.now(timezone.utc).isoformat(), ) ) raw_result = await self.adapter.list_creatives(params) self._emit_activity( Activity( type=ActivityType.PROTOCOL_RESPONSE, operation_id=operation_id, agent_id=self.agent_config.id, task_type="list_creatives", status=raw_result.status, timestamp=datetime.now(timezone.utc).isoformat(), ) ) return self.adapter._parse_response(raw_result, ListCreativesResponse)List Creatives.
Args
request- Request parameters
Returns
TaskResult containing ListCreativesResponse
async def list_property_lists(self, request: ListPropertyListsRequest) ‑> TaskResult[ListPropertyListsResponse]-
Expand source code
async def list_property_lists( self, request: ListPropertyListsRequest, ) -> TaskResult[ListPropertyListsResponse]: """ List property lists owned by a principal. Retrieves metadata for all property lists, optionally filtered by principal or pagination parameters. Args: request: Request parameters with optional filtering Returns: TaskResult containing ListPropertyListsResponse """ operation_id = create_operation_id() params = request.model_dump(mode="json", exclude_none=True) self._emit_activity( Activity( type=ActivityType.PROTOCOL_REQUEST, operation_id=operation_id, agent_id=self.agent_config.id, task_type="list_property_lists", timestamp=datetime.now(timezone.utc).isoformat(), ) ) raw_result = await self.adapter.list_property_lists(params) self._emit_activity( Activity( type=ActivityType.PROTOCOL_RESPONSE, operation_id=operation_id, agent_id=self.agent_config.id, task_type="list_property_lists", status=raw_result.status, timestamp=datetime.now(timezone.utc).isoformat(), ) ) return self.adapter._parse_response(raw_result, ListPropertyListsResponse)List property lists owned by a principal.
Retrieves metadata for all property lists, optionally filtered by principal or pagination parameters.
Args
request- Request parameters with optional filtering
Returns
TaskResult containing ListPropertyListsResponse
async def list_tools(self) ‑> list[str]-
Expand source code
async def list_tools(self) -> list[str]: """ List available tools from the agent. Returns: List of tool names """ return await self.adapter.list_tools()List available tools from the agent.
Returns
List of tool names
async def log_event(self,
request: LogEventRequest) ‑> TaskResult[Union[LogEventResponse1, LogEventResponse2]]-
Expand source code
async def log_event( self, request: LogEventRequest, ) -> TaskResult[LogEventResponse]: """ Log Event. Args: request: Request parameters Returns: TaskResult containing LogEventResponse """ self._validate_task_features("log_event") operation_id = create_operation_id() params = request.model_dump(mode="json", exclude_none=True) self._emit_activity( Activity( type=ActivityType.PROTOCOL_REQUEST, operation_id=operation_id, agent_id=self.agent_config.id, task_type="log_event", timestamp=datetime.now(timezone.utc).isoformat(), ) ) raw_result = await self.adapter.log_event(params) self._emit_activity( Activity( type=ActivityType.PROTOCOL_RESPONSE, operation_id=operation_id, agent_id=self.agent_config.id, task_type="log_event", status=raw_result.status, timestamp=datetime.now(timezone.utc).isoformat(), ) ) return self.adapter._parse_response(raw_result, LogEventResponse)Log Event.
Args
request- Request parameters
Returns
TaskResult containing LogEventResponse
async def preview_creative(self, request: PreviewCreativeRequest) ‑> TaskResult[Union[PreviewCreativeResponse1, PreviewCreativeResponse2, PreviewCreativeResponse3]]-
Expand source code
async def preview_creative( self, request: PreviewCreativeRequest, ) -> TaskResult[PreviewCreativeResponse]: """ Generate preview of a creative manifest. Args: request: Request parameters Returns: TaskResult containing PreviewCreativeResponse with preview URLs """ operation_id = create_operation_id() params = request.model_dump(mode="json", exclude_none=True) self._emit_activity( Activity( type=ActivityType.PROTOCOL_REQUEST, operation_id=operation_id, agent_id=self.agent_config.id, task_type="preview_creative", timestamp=datetime.now(timezone.utc).isoformat(), ) ) raw_result = await self.adapter.preview_creative(params) self._emit_activity( Activity( type=ActivityType.PROTOCOL_RESPONSE, operation_id=operation_id, agent_id=self.agent_config.id, task_type="preview_creative", status=raw_result.status, timestamp=datetime.now(timezone.utc).isoformat(), ) ) return self.adapter._parse_response(raw_result, PreviewCreativeResponse)Generate preview of a creative manifest.
Args
request- Request parameters
Returns
TaskResult containing PreviewCreativeResponse with preview URLs
async def provide_performance_feedback(self,
request: ProvidePerformanceFeedbackRequest) ‑> TaskResult[Union[ProvidePerformanceFeedbackResponse1, ProvidePerformanceFeedbackResponse2]]-
Expand source code
async def provide_performance_feedback( self, request: ProvidePerformanceFeedbackRequest, ) -> TaskResult[ProvidePerformanceFeedbackResponse]: """ Provide Performance Feedback. Args: request: Request parameters Returns: TaskResult containing ProvidePerformanceFeedbackResponse """ operation_id = create_operation_id() params = request.model_dump(mode="json", exclude_none=True) self._emit_activity( Activity( type=ActivityType.PROTOCOL_REQUEST, operation_id=operation_id, agent_id=self.agent_config.id, task_type="provide_performance_feedback", timestamp=datetime.now(timezone.utc).isoformat(), ) ) raw_result = await self.adapter.provide_performance_feedback(params) self._emit_activity( Activity( type=ActivityType.PROTOCOL_RESPONSE, operation_id=operation_id, agent_id=self.agent_config.id, task_type="provide_performance_feedback", status=raw_result.status, timestamp=datetime.now(timezone.utc).isoformat(), ) ) return self.adapter._parse_response(raw_result, ProvidePerformanceFeedbackResponse)Provide Performance Feedback.
Args
request- Request parameters
Returns
TaskResult containing ProvidePerformanceFeedbackResponse
async def refresh_capabilities(self) ‑> GetAdcpCapabilitiesResponse-
Expand source code
async def refresh_capabilities(self) -> GetAdcpCapabilitiesResponse: """Fetch capabilities from the seller, bypassing cache. Returns: The seller's capabilities response. """ result = await self.get_adcp_capabilities(GetAdcpCapabilitiesRequest()) if result.success and result.data is not None: self._capabilities = result.data self._feature_resolver = FeatureResolver(result.data) self._capabilities_fetched_at = time.monotonic() return self._capabilities raise ADCPError( f"Failed to fetch capabilities: {result.error or result.message}", agent_id=self.agent_config.id, agent_uri=self.agent_config.agent_uri, )Fetch capabilities from the seller, bypassing cache.
Returns
The seller's capabilities response.
async def report_plan_outcome(self,
request: ReportPlanOutcomeRequest) ‑> TaskResult[ReportPlanOutcomeResponse]-
Expand source code
async def report_plan_outcome( self, request: ReportPlanOutcomeRequest, ) -> TaskResult[ReportPlanOutcomeResponse]: """Report the outcome of a governed action to the governance agent.""" operation_id = create_operation_id() params = request.model_dump(mode="json", exclude_none=True) self._emit_activity( Activity( type=ActivityType.PROTOCOL_REQUEST, operation_id=operation_id, agent_id=self.agent_config.id, task_type="report_plan_outcome", timestamp=datetime.now(timezone.utc).isoformat(), ) ) raw_result = await self.adapter.report_plan_outcome(params) self._emit_activity( Activity( type=ActivityType.PROTOCOL_RESPONSE, operation_id=operation_id, agent_id=self.agent_config.id, task_type="report_plan_outcome", status=raw_result.status, timestamp=datetime.now(timezone.utc).isoformat(), ) ) return self.adapter._parse_response(raw_result, ReportPlanOutcomeResponse)Report the outcome of a governed action to the governance agent.
async def report_usage(self,
request: ReportUsageRequest) ‑> TaskResult[ReportUsageResponse]-
Expand source code
async def report_usage( self, request: ReportUsageRequest, ) -> TaskResult[ReportUsageResponse]: """ Report Usage. Args: request: Request parameters Returns: TaskResult containing ReportUsageResponse """ operation_id = create_operation_id() params = request.model_dump(mode="json", exclude_none=True) self._emit_activity( Activity( type=ActivityType.PROTOCOL_REQUEST, operation_id=operation_id, agent_id=self.agent_config.id, task_type="report_usage", timestamp=datetime.now(timezone.utc).isoformat(), ) ) raw_result = await self.adapter.report_usage(params) self._emit_activity( Activity( type=ActivityType.PROTOCOL_RESPONSE, operation_id=operation_id, agent_id=self.agent_config.id, task_type="report_usage", status=raw_result.status, timestamp=datetime.now(timezone.utc).isoformat(), ) ) return self.adapter._parse_response(raw_result, ReportUsageResponse)Report Usage.
Args
request- Request parameters
Returns
TaskResult containing ReportUsageResponse
def require(self, *features: str) ‑> None-
Expand source code
def require(self, *features: str) -> None: """Assert that the seller supports all listed features. Args: *features: Feature identifiers to require. Raises: ADCPFeatureUnsupportedError: If any features are not supported. ADCPError: If capabilities have not been fetched yet. """ self._ensure_resolver().require( *features, agent_id=self.agent_config.id, agent_uri=self.agent_config.agent_uri, )Assert that the seller supports all listed features.
Args
*features- Feature identifiers to require.
Raises
ADCPFeatureUnsupportedError- If any features are not supported.
ADCPError- If capabilities have not been fetched yet.
async def si_get_offering(self, request: SiGetOfferingRequest) ‑> TaskResult[SiGetOfferingResponse]-
Expand source code
async def si_get_offering( self, request: SiGetOfferingRequest, ) -> TaskResult[SiGetOfferingResponse]: """ Get sponsored intelligence offering. Retrieves product/service offerings that can be presented in a sponsored intelligence session. Args: request: Request parameters including brand context Returns: TaskResult containing SiGetOfferingResponse """ operation_id = create_operation_id() params = request.model_dump(mode="json", exclude_none=True) self._emit_activity( Activity( type=ActivityType.PROTOCOL_REQUEST, operation_id=operation_id, agent_id=self.agent_config.id, task_type="si_get_offering", timestamp=datetime.now(timezone.utc).isoformat(), ) ) raw_result = await self.adapter.si_get_offering(params) self._emit_activity( Activity( type=ActivityType.PROTOCOL_RESPONSE, operation_id=operation_id, agent_id=self.agent_config.id, task_type="si_get_offering", status=raw_result.status, timestamp=datetime.now(timezone.utc).isoformat(), ) ) return self.adapter._parse_response(raw_result, SiGetOfferingResponse)Get sponsored intelligence offering.
Retrieves product/service offerings that can be presented in a sponsored intelligence session.
Args
request- Request parameters including brand context
Returns
TaskResult containing SiGetOfferingResponse
async def si_initiate_session(self, request: SiInitiateSessionRequest) ‑> TaskResult[SiInitiateSessionResponse]-
Expand source code
async def si_initiate_session( self, request: SiInitiateSessionRequest, ) -> TaskResult[SiInitiateSessionResponse]: """ Initiate a sponsored intelligence session. Starts a conversational brand experience session with a user. Args: request: Request parameters including identity and context Returns: TaskResult containing SiInitiateSessionResponse with session_id """ operation_id = create_operation_id() params = request.model_dump(mode="json", exclude_none=True) self._emit_activity( Activity( type=ActivityType.PROTOCOL_REQUEST, operation_id=operation_id, agent_id=self.agent_config.id, task_type="si_initiate_session", timestamp=datetime.now(timezone.utc).isoformat(), ) ) raw_result = await self.adapter.si_initiate_session(params) self._emit_activity( Activity( type=ActivityType.PROTOCOL_RESPONSE, operation_id=operation_id, agent_id=self.agent_config.id, task_type="si_initiate_session", status=raw_result.status, timestamp=datetime.now(timezone.utc).isoformat(), ) ) return self.adapter._parse_response(raw_result, SiInitiateSessionResponse)Initiate a sponsored intelligence session.
Starts a conversational brand experience session with a user.
Args
request- Request parameters including identity and context
Returns
TaskResult containing SiInitiateSessionResponse with session_id
async def si_send_message(self,
request: SiSendMessageRequest) ‑> TaskResult[SiSendMessageResponse]-
Expand source code
async def si_send_message( self, request: SiSendMessageRequest, ) -> TaskResult[SiSendMessageResponse]: """ Send a message in a sponsored intelligence session. Continues the conversation in an active SI session. Args: request: Request parameters including session_id and message Returns: TaskResult containing SiSendMessageResponse with brand response """ operation_id = create_operation_id() params = request.model_dump(mode="json", exclude_none=True) self._emit_activity( Activity( type=ActivityType.PROTOCOL_REQUEST, operation_id=operation_id, agent_id=self.agent_config.id, task_type="si_send_message", timestamp=datetime.now(timezone.utc).isoformat(), ) ) raw_result = await self.adapter.si_send_message(params) self._emit_activity( Activity( type=ActivityType.PROTOCOL_RESPONSE, operation_id=operation_id, agent_id=self.agent_config.id, task_type="si_send_message", status=raw_result.status, timestamp=datetime.now(timezone.utc).isoformat(), ) ) return self.adapter._parse_response(raw_result, SiSendMessageResponse)Send a message in a sponsored intelligence session.
Continues the conversation in an active SI session.
Args
request- Request parameters including session_id and message
Returns
TaskResult containing SiSendMessageResponse with brand response
async def si_terminate_session(self, request: SiTerminateSessionRequest) ‑> TaskResult[SiTerminateSessionResponse]-
Expand source code
async def si_terminate_session( self, request: SiTerminateSessionRequest, ) -> TaskResult[SiTerminateSessionResponse]: """ Terminate a sponsored intelligence session. Ends an active SI session, optionally with follow-up actions. Args: request: Request parameters including session_id and termination context Returns: TaskResult containing SiTerminateSessionResponse """ operation_id = create_operation_id() params = request.model_dump(mode="json", exclude_none=True) self._emit_activity( Activity( type=ActivityType.PROTOCOL_REQUEST, operation_id=operation_id, agent_id=self.agent_config.id, task_type="si_terminate_session", timestamp=datetime.now(timezone.utc).isoformat(), ) ) raw_result = await self.adapter.si_terminate_session(params) self._emit_activity( Activity( type=ActivityType.PROTOCOL_RESPONSE, operation_id=operation_id, agent_id=self.agent_config.id, task_type="si_terminate_session", status=raw_result.status, timestamp=datetime.now(timezone.utc).isoformat(), ) ) return self.adapter._parse_response(raw_result, SiTerminateSessionResponse)Terminate a sponsored intelligence session.
Ends an active SI session, optionally with follow-up actions.
Args
request- Request parameters including session_id and termination context
Returns
TaskResult containing SiTerminateSessionResponse
def supports(self, feature: str) ‑> bool-
Expand source code
def supports(self, feature: str) -> bool: """Check if the seller supports a feature. Supports multiple feature namespaces: - Protocol support: ``supports("media_buy")`` checks ``supported_protocols`` - Extension support: ``supports("ext:scope3")`` checks ``extensions_supported`` - Targeting: ``supports("targeting.geo_countries")`` checks ``media_buy.execution.targeting`` - Media buy features: ``supports("audience_targeting")`` checks ``media_buy.features`` - Signals features: ``supports("catalog_signals")`` checks ``signals.features`` Args: feature: Feature identifier to check. Returns: True if the seller declares the feature as supported. Raises: ADCPError: If capabilities have not been fetched yet. """ return self._ensure_resolver().supports(feature)Check if the seller supports a feature.
Supports multiple feature namespaces: - Protocol support:
supports("media_buy")checkssupported_protocols- Extension support:supports("ext:scope3")checksextensions_supported- Targeting:supports("targeting.geo_countries")checksmedia_buy.execution.targeting- Media buy features:supports("audience_targeting")checksmedia_buy.features- Signals features:supports("catalog_signals")checkssignals.featuresArgs
feature- Feature identifier to check.
Returns
True if the seller declares the feature as supported.
Raises
ADCPError- If capabilities have not been fetched yet.
async def sync_accounts(self,
request: SyncAccountsRequest) ‑> TaskResult[Union[SyncAccountsResponse1, SyncAccountsResponse2]]-
Expand source code
async def sync_accounts( self, request: SyncAccountsRequest, ) -> TaskResult[SyncAccountsResponse]: """ Sync Accounts. Args: request: Request parameters Returns: TaskResult containing SyncAccountsResponse """ operation_id = create_operation_id() params = request.model_dump(mode="json", exclude_none=True) self._emit_activity( Activity( type=ActivityType.PROTOCOL_REQUEST, operation_id=operation_id, agent_id=self.agent_config.id, task_type="sync_accounts", timestamp=datetime.now(timezone.utc).isoformat(), ) ) raw_result = await self.adapter.sync_accounts(params) self._emit_activity( Activity( type=ActivityType.PROTOCOL_RESPONSE, operation_id=operation_id, agent_id=self.agent_config.id, task_type="sync_accounts", status=raw_result.status, timestamp=datetime.now(timezone.utc).isoformat(), ) ) return self.adapter._parse_response(raw_result, SyncAccountsResponse)Sync Accounts.
Args
request- Request parameters
Returns
TaskResult containing SyncAccountsResponse
async def sync_audiences(self,
request: SyncAudiencesRequest) ‑> TaskResult[Union[SyncAudiencesResponse1, SyncAudiencesResponse2]]-
Expand source code
async def sync_audiences( self, request: SyncAudiencesRequest, ) -> TaskResult[SyncAudiencesResponse]: """ Sync Audiences. Args: request: Request parameters Returns: TaskResult containing SyncAudiencesResponse """ operation_id = create_operation_id() params = request.model_dump(mode="json", exclude_none=True) self._emit_activity( Activity( type=ActivityType.PROTOCOL_REQUEST, operation_id=operation_id, agent_id=self.agent_config.id, task_type="sync_audiences", timestamp=datetime.now(timezone.utc).isoformat(), ) ) raw_result = await self.adapter.sync_audiences(params) self._emit_activity( Activity( type=ActivityType.PROTOCOL_RESPONSE, operation_id=operation_id, agent_id=self.agent_config.id, task_type="sync_audiences", status=raw_result.status, timestamp=datetime.now(timezone.utc).isoformat(), ) ) return self.adapter._parse_response(raw_result, SyncAudiencesResponse)Sync Audiences.
Args
request- Request parameters
Returns
TaskResult containing SyncAudiencesResponse
async def sync_catalogs(self,
request: SyncCatalogsRequest) ‑> TaskResult[Union[SyncCatalogsResponse1, SyncCatalogsResponse2]]-
Expand source code
async def sync_catalogs( self, request: SyncCatalogsRequest, ) -> TaskResult[SyncCatalogsResponse]: """ Sync Catalogs. Args: request: Request parameters Returns: TaskResult containing SyncCatalogsResponse """ operation_id = create_operation_id() params = request.model_dump(mode="json", exclude_none=True) self._emit_activity( Activity( type=ActivityType.PROTOCOL_REQUEST, operation_id=operation_id, agent_id=self.agent_config.id, task_type="sync_catalogs", timestamp=datetime.now(timezone.utc).isoformat(), ) ) raw_result = await self.adapter.sync_catalogs(params) self._emit_activity( Activity( type=ActivityType.PROTOCOL_RESPONSE, operation_id=operation_id, agent_id=self.agent_config.id, task_type="sync_catalogs", status=raw_result.status, timestamp=datetime.now(timezone.utc).isoformat(), ) ) return self.adapter._parse_response(raw_result, SyncCatalogsResponse)Sync Catalogs.
Args
request- Request parameters
Returns
TaskResult containing SyncCatalogsResponse
async def sync_creatives(self,
request: SyncCreativesRequest) ‑> TaskResult[Union[SyncCreativesResponse1, SyncCreativesResponse2]]-
Expand source code
async def sync_creatives( self, request: SyncCreativesRequest, ) -> TaskResult[SyncCreativesResponse]: """ Sync Creatives. Args: request: Request parameters Returns: TaskResult containing SyncCreativesResponse """ operation_id = create_operation_id() params = request.model_dump(mode="json", exclude_none=True) self._emit_activity( Activity( type=ActivityType.PROTOCOL_REQUEST, operation_id=operation_id, agent_id=self.agent_config.id, task_type="sync_creatives", timestamp=datetime.now(timezone.utc).isoformat(), ) ) raw_result = await self.adapter.sync_creatives(params) self._emit_activity( Activity( type=ActivityType.PROTOCOL_RESPONSE, operation_id=operation_id, agent_id=self.agent_config.id, task_type="sync_creatives", status=raw_result.status, timestamp=datetime.now(timezone.utc).isoformat(), ) ) return self.adapter._parse_response(raw_result, SyncCreativesResponse)Sync Creatives.
Args
request- Request parameters
Returns
TaskResult containing SyncCreativesResponse
async def sync_event_sources(self,
request: SyncEventSourcesRequest) ‑> TaskResult[Union[SyncEventSourcesResponse1, SyncEventSourcesResponse2]]-
Expand source code
async def sync_event_sources( self, request: SyncEventSourcesRequest, ) -> TaskResult[SyncEventSourcesResponse]: """ Sync Event Sources. Args: request: Request parameters Returns: TaskResult containing SyncEventSourcesResponse """ self._validate_task_features("sync_event_sources") operation_id = create_operation_id() params = request.model_dump(mode="json", exclude_none=True) self._emit_activity( Activity( type=ActivityType.PROTOCOL_REQUEST, operation_id=operation_id, agent_id=self.agent_config.id, task_type="sync_event_sources", timestamp=datetime.now(timezone.utc).isoformat(), ) ) raw_result = await self.adapter.sync_event_sources(params) self._emit_activity( Activity( type=ActivityType.PROTOCOL_RESPONSE, operation_id=operation_id, agent_id=self.agent_config.id, task_type="sync_event_sources", status=raw_result.status, timestamp=datetime.now(timezone.utc).isoformat(), ) ) return self.adapter._parse_response(raw_result, SyncEventSourcesResponse)Sync Event Sources.
Args
request- Request parameters
Returns
TaskResult containing SyncEventSourcesResponse
async def sync_plans(self,
request: SyncPlansRequest) ‑> TaskResult[SyncPlansResponse]-
Expand source code
async def sync_plans( self, request: SyncPlansRequest, ) -> TaskResult[SyncPlansResponse]: """Sync campaign governance plans to the governance agent.""" operation_id = create_operation_id() params = request.model_dump(mode="json", exclude_none=True) self._emit_activity( Activity( type=ActivityType.PROTOCOL_REQUEST, operation_id=operation_id, agent_id=self.agent_config.id, task_type="sync_plans", timestamp=datetime.now(timezone.utc).isoformat(), ) ) raw_result = await self.adapter.sync_plans(params) self._emit_activity( Activity( type=ActivityType.PROTOCOL_RESPONSE, operation_id=operation_id, agent_id=self.agent_config.id, task_type="sync_plans", status=raw_result.status, timestamp=datetime.now(timezone.utc).isoformat(), ) ) return self.adapter._parse_response(raw_result, SyncPlansResponse)Sync campaign governance plans to the governance agent.
async def update_content_standards(self, request: UpdateContentStandardsRequest) ‑> TaskResult[Union[UpdateContentStandardsResponse1, UpdateContentStandardsResponse2]]-
Expand source code
async def update_content_standards( self, request: UpdateContentStandardsRequest, ) -> TaskResult[UpdateContentStandardsResponse]: """ Update a content standards configuration. Args: request: Request parameters including standards_id and updates Returns: TaskResult containing UpdateContentStandardsResponse """ operation_id = create_operation_id() params = request.model_dump(mode="json", exclude_none=True) self._emit_activity( Activity( type=ActivityType.PROTOCOL_REQUEST, operation_id=operation_id, agent_id=self.agent_config.id, task_type="update_content_standards", timestamp=datetime.now(timezone.utc).isoformat(), ) ) raw_result = await self.adapter.update_content_standards(params) self._emit_activity( Activity( type=ActivityType.PROTOCOL_RESPONSE, operation_id=operation_id, agent_id=self.agent_config.id, task_type="update_content_standards", status=raw_result.status, timestamp=datetime.now(timezone.utc).isoformat(), ) ) return self.adapter._parse_response(raw_result, UpdateContentStandardsResponse)Update a content standards configuration.
Args
request- Request parameters including standards_id and updates
Returns
TaskResult containing UpdateContentStandardsResponse
async def update_media_buy(self,
request: UpdateMediaBuyRequest) ‑> TaskResult[Union[UpdateMediaBuyResponse1, UpdateMediaBuyResponse2]]-
Expand source code
async def update_media_buy( self, request: UpdateMediaBuyRequest, ) -> TaskResult[UpdateMediaBuyResponse]: """ Update an existing media buy reservation. Modifies a previously created media buy by updating packages or publisher properties. The update operation uses discriminated unions to specify what to change - either package details or targeting properties. Args: request: Media buy update parameters including: - media_buy_id: Identifier from create_media_buy response - updates: Discriminated union specifying update type: * UpdateMediaBuyPackagesRequest: Modify package selections * UpdateMediaBuyPropertiesRequest: Change targeting properties Returns: TaskResult containing UpdateMediaBuyResponse with: - media_buy_id: The updated media buy identifier - status: Updated state of the media buy - packages: Updated package configurations - Additional platform-specific metadata Example: >>> from adcp import ADCPClient, UpdateMediaBuyPackagesRequest >>> client = ADCPClient(agent_config) >>> request = UpdateMediaBuyPackagesRequest( ... media_buy_id="mb_123", ... packages=[updated_package] ... ) >>> result = await client.update_media_buy(request) >>> if result.success: ... updated_packages = result.data.packages """ operation_id = create_operation_id() params = request.model_dump(mode="json", exclude_none=True) self._emit_activity( Activity( type=ActivityType.PROTOCOL_REQUEST, operation_id=operation_id, agent_id=self.agent_config.id, task_type="update_media_buy", timestamp=datetime.now(timezone.utc).isoformat(), ) ) raw_result = await self.adapter.update_media_buy(params) self._emit_activity( Activity( type=ActivityType.PROTOCOL_RESPONSE, operation_id=operation_id, agent_id=self.agent_config.id, task_type="update_media_buy", status=raw_result.status, timestamp=datetime.now(timezone.utc).isoformat(), ) ) return self.adapter._parse_response(raw_result, UpdateMediaBuyResponse)Update an existing media buy reservation.
Modifies a previously created media buy by updating packages or publisher properties. The update operation uses discriminated unions to specify what to change - either package details or targeting properties.
Args
request- Media buy update parameters including: - media_buy_id: Identifier from create_media_buy response - updates: Discriminated union specifying update type: * UpdateMediaBuyPackagesRequest: Modify package selections * UpdateMediaBuyPropertiesRequest: Change targeting properties
Returns
TaskResult containing UpdateMediaBuyResponse with: - media_buy_id: The updated media buy identifier - status: Updated state of the media buy - packages: Updated package configurations - Additional platform-specific metadata
Example
>>> from adcp import ADCPClient, UpdateMediaBuyPackagesRequest >>> client = ADCPClient(agent_config) >>> request = UpdateMediaBuyPackagesRequest( ... media_buy_id="mb_123", ... packages=[updated_package] ... ) >>> result = await client.update_media_buy(request) >>> if result.success: ... updated_packages = result.data.packages async def update_property_list(self, request: UpdatePropertyListRequest) ‑> TaskResult[UpdatePropertyListResponse]-
Expand source code
async def update_property_list( self, request: UpdatePropertyListRequest, ) -> TaskResult[UpdatePropertyListResponse]: """ Update a property list. Modifies the filters, brand manifest, or other parameters of an existing property list. Args: request: Request parameters with list_id and updates Returns: TaskResult containing UpdatePropertyListResponse """ operation_id = create_operation_id() params = request.model_dump(mode="json", exclude_none=True) self._emit_activity( Activity( type=ActivityType.PROTOCOL_REQUEST, operation_id=operation_id, agent_id=self.agent_config.id, task_type="update_property_list", timestamp=datetime.now(timezone.utc).isoformat(), ) ) raw_result = await self.adapter.update_property_list(params) self._emit_activity( Activity( type=ActivityType.PROTOCOL_RESPONSE, operation_id=operation_id, agent_id=self.agent_config.id, task_type="update_property_list", status=raw_result.status, timestamp=datetime.now(timezone.utc).isoformat(), ) ) return self.adapter._parse_response(raw_result, UpdatePropertyListResponse)Update a property list.
Modifies the filters, brand manifest, or other parameters of an existing property list.
Args
request- Request parameters with list_id and updates
Returns
TaskResult containing UpdatePropertyListResponse
async def validate_content_delivery(self, request: ValidateContentDeliveryRequest) ‑> TaskResult[Union[ValidateContentDeliveryResponse1, ValidateContentDeliveryResponse2]]-
Expand source code
async def validate_content_delivery( self, request: ValidateContentDeliveryRequest, ) -> TaskResult[ValidateContentDeliveryResponse]: """ Validate content delivery against standards. Validates that ad delivery records comply with content standards. Args: request: Request parameters including delivery records Returns: TaskResult containing ValidateContentDeliveryResponse """ operation_id = create_operation_id() params = request.model_dump(mode="json", exclude_none=True) self._emit_activity( Activity( type=ActivityType.PROTOCOL_REQUEST, operation_id=operation_id, agent_id=self.agent_config.id, task_type="validate_content_delivery", timestamp=datetime.now(timezone.utc).isoformat(), ) ) raw_result = await self.adapter.validate_content_delivery(params) self._emit_activity( Activity( type=ActivityType.PROTOCOL_RESPONSE, operation_id=operation_id, agent_id=self.agent_config.id, task_type="validate_content_delivery", status=raw_result.status, timestamp=datetime.now(timezone.utc).isoformat(), ) ) return self.adapter._parse_response(raw_result, ValidateContentDeliveryResponse)Validate content delivery against standards.
Validates that ad delivery records comply with content standards.
Args
request- Request parameters including delivery records
Returns
TaskResult containing ValidateContentDeliveryResponse
class ADCPConnectionError (message: str, agent_id: str | None = None, agent_uri: str | None = None)-
Expand source code
class ADCPConnectionError(ADCPError): """Connection to agent failed.""" def __init__(self, message: str, agent_id: str | None = None, agent_uri: str | None = None): """Initialize connection error.""" suggestion = ( "Check that the agent URI is correct and the agent is running.\n" " Try testing with: python -m adcp test --config <agent-id>" ) super().__init__(message, agent_id, agent_uri, suggestion)Connection to agent failed.
Initialize connection error.
Ancestors
- ADCPError
- builtins.Exception
- builtins.BaseException
class ADCPError (message: str,
agent_id: str | None = None,
agent_uri: str | None = None,
suggestion: str | None = None)-
Expand source code
class ADCPError(Exception): """Base exception for all AdCP client errors.""" def __init__( self, message: str, agent_id: str | None = None, agent_uri: str | None = None, suggestion: str | None = None, ): """Initialize exception with context.""" self.message = message self.agent_id = agent_id self.agent_uri = agent_uri self.suggestion = suggestion full_message = message if agent_id: full_message = f"[Agent: {agent_id}] {full_message}" if agent_uri: full_message = f"{full_message}\n URI: {agent_uri}" if suggestion: full_message = f"{full_message}\n 💡 {suggestion}" super().__init__(full_message)Base exception for all AdCP client errors.
Initialize exception with context.
Ancestors
- builtins.Exception
- builtins.BaseException
Subclasses
class ADCPFeatureUnsupportedError (unsupported_features: list[str],
declared_features: list[str] | None = None,
agent_id: str | None = None,
agent_uri: str | None = None)-
Expand source code
class ADCPFeatureUnsupportedError(ADCPError): """Seller does not support one or more required features.""" def __init__( self, unsupported_features: list[str], declared_features: list[str] | None = None, agent_id: str | None = None, agent_uri: str | None = None, ): """Initialize feature unsupported error. Args: unsupported_features: Features that are not supported. declared_features: Features the seller does declare. agent_id: Optional agent ID for context. agent_uri: Optional agent URI for context. """ self.unsupported_features = unsupported_features self.declared_features = declared_features or [] missing = ", ".join(unsupported_features) message = f"Seller does not support: {missing}" suggestion = None if self.declared_features: declared = ", ".join(sorted(self.declared_features)) suggestion = f"Declared features: {declared}" super().__init__(message, agent_id, agent_uri, suggestion)Seller does not support one or more required features.
Initialize feature unsupported error.
Args
unsupported_features- Features that are not supported.
declared_features- Features the seller does declare.
agent_id- Optional agent ID for context.
agent_uri- Optional agent URI for context.
Ancestors
- ADCPError
- builtins.Exception
- builtins.BaseException
class ADCPMultiAgentClient (agents: list[AgentConfig],
webhook_url_template: str | None = None,
webhook_secret: str | None = None,
on_activity: Callable[[Activity], None] | None = None,
handlers: dict[str, Callable[..., Any]] | None = None)-
Expand source code
class ADCPMultiAgentClient: """Client for managing multiple AdCP agents.""" def __init__( self, agents: list[AgentConfig], webhook_url_template: str | None = None, webhook_secret: str | None = None, on_activity: Callable[[Activity], None] | None = None, handlers: dict[str, Callable[..., Any]] | None = None, ): """ Initialize multi-agent client. Args: agents: List of agent configurations webhook_url_template: Template for webhook URLs webhook_secret: Secret for webhook verification on_activity: Callback for activity events handlers: Task completion handlers """ self.agents = { agent.id: ADCPClient( agent, webhook_url_template=webhook_url_template, webhook_secret=webhook_secret, on_activity=on_activity, ) for agent in agents } self.handlers = handlers or {} def agent(self, agent_id: str) -> ADCPClient: """Get client for specific agent.""" if agent_id not in self.agents: raise ValueError(f"Agent not found: {agent_id}") return self.agents[agent_id] @property def agent_ids(self) -> list[str]: """Get list of agent IDs.""" return list(self.agents.keys()) async def close(self) -> None: """Close all agent clients and clean up resources.""" import asyncio logger.debug("Closing all agent clients in multi-agent client") close_tasks = [client.close() for client in self.agents.values()] await asyncio.gather(*close_tasks, return_exceptions=True) async def __aenter__(self) -> ADCPMultiAgentClient: """Async context manager entry.""" return self async def __aexit__(self, exc_type: Any, exc_val: Any, exc_tb: Any) -> None: """Async context manager exit.""" await self.close() async def get_products( self, request: GetProductsRequest, ) -> list[TaskResult[GetProductsResponse]]: """ Execute get_products across all agents in parallel. Args: request: Request parameters Returns: List of TaskResults containing GetProductsResponse for each agent """ import asyncio tasks = [agent.get_products(request) for agent in self.agents.values()] return await asyncio.gather(*tasks) @classmethod def from_env(cls) -> ADCPMultiAgentClient: """Create client from environment variables.""" agents_json = os.getenv("ADCP_AGENTS") if not agents_json: raise ValueError("ADCP_AGENTS environment variable not set") agents_data = json.loads(agents_json) agents = [AgentConfig(**agent) for agent in agents_data] return cls( agents=agents, webhook_url_template=os.getenv("WEBHOOK_URL_TEMPLATE"), webhook_secret=os.getenv("WEBHOOK_SECRET"), )Client for managing multiple AdCP agents.
Initialize multi-agent client.
Args
agents- List of agent configurations
webhook_url_template- Template for webhook URLs
webhook_secret- Secret for webhook verification
on_activity- Callback for activity events
handlers- Task completion handlers
Static methods
def from_env() ‑> ADCPMultiAgentClient-
Create client from environment variables.
Instance variables
prop agent_ids : list[str]-
Expand source code
@property def agent_ids(self) -> list[str]: """Get list of agent IDs.""" return list(self.agents.keys())Get list of agent IDs.
Methods
def agent(self, agent_id: str) ‑> ADCPClient-
Expand source code
def agent(self, agent_id: str) -> ADCPClient: """Get client for specific agent.""" if agent_id not in self.agents: raise ValueError(f"Agent not found: {agent_id}") return self.agents[agent_id]Get client for specific agent.
async def close(self) ‑> None-
Expand source code
async def close(self) -> None: """Close all agent clients and clean up resources.""" import asyncio logger.debug("Closing all agent clients in multi-agent client") close_tasks = [client.close() for client in self.agents.values()] await asyncio.gather(*close_tasks, return_exceptions=True)Close all agent clients and clean up resources.
async def get_products(self,
request: GetProductsRequest) ‑> list[TaskResult[GetProductsResponse]]-
Expand source code
async def get_products( self, request: GetProductsRequest, ) -> list[TaskResult[GetProductsResponse]]: """ Execute get_products across all agents in parallel. Args: request: Request parameters Returns: List of TaskResults containing GetProductsResponse for each agent """ import asyncio tasks = [agent.get_products(request) for agent in self.agents.values()] return await asyncio.gather(*tasks)Execute get_products across all agents in parallel.
Args
request- Request parameters
Returns
List of TaskResults containing GetProductsResponse for each agent
class ADCPProtocolError (message: str, agent_id: str | None = None, protocol: str | None = None)-
Expand source code
class ADCPProtocolError(ADCPError): """Protocol-level error (malformed response, unexpected format).""" def __init__(self, message: str, agent_id: str | None = None, protocol: str | None = None): """Initialize protocol error.""" suggestion = ( f"The agent returned an unexpected {protocol} response format." if protocol else "Unexpected response format." ) suggestion += "\n Enable debug mode to see the full request/response." super().__init__(message, agent_id, None, suggestion)Protocol-level error (malformed response, unexpected format).
Initialize protocol error.
Ancestors
- ADCPError
- builtins.Exception
- builtins.BaseException
class ADCPTimeoutError (message: str,
agent_id: str | None = None,
agent_uri: str | None = None,
timeout: float | None = None)-
Expand source code
class ADCPTimeoutError(ADCPError): """Request timed out.""" def __init__( self, message: str, agent_id: str | None = None, agent_uri: str | None = None, timeout: float | None = None, ): """Initialize timeout error.""" suggestion = ( f"The request took longer than {timeout}s." if timeout else "The request timed out." ) suggestion += "\n Try increasing the timeout value or check if the agent is overloaded." super().__init__(message, agent_id, agent_uri, suggestion)Request timed out.
Initialize timeout error.
Ancestors
- ADCPError
- builtins.Exception
- builtins.BaseException
class ADCPToolNotFoundError (tool_name: str,
agent_id: str | None = None,
available_tools: list[str] | None = None)-
Expand source code
class ADCPToolNotFoundError(ADCPError): """Requested tool not found on agent.""" def __init__( self, tool_name: str, agent_id: str | None = None, available_tools: list[str] | None = None ): """Initialize tool not found error.""" message = f"Tool '{tool_name}' not found on agent" suggestion = "List available tools with: python -m adcp list-tools --config <agent-id>" if available_tools: tools_list = ", ".join(available_tools[:5]) if len(available_tools) > 5: tools_list += f", ... ({len(available_tools)} total)" suggestion = f"Available tools: {tools_list}" super().__init__(message, agent_id, None, suggestion)Requested tool not found on agent.
Initialize tool not found error.
Ancestors
- ADCPError
- builtins.Exception
- builtins.BaseException
class ADCPWebhookError (message: str,
agent_id: str | None = None,
agent_uri: str | None = None,
suggestion: str | None = None)-
Expand source code
class ADCPWebhookError(ADCPError): """Webhook handling error."""Webhook handling error.
Initialize exception with context.
Ancestors
- ADCPError
- builtins.Exception
- builtins.BaseException
Subclasses
class ADCPWebhookSignatureError (message: str = 'Invalid webhook signature', agent_id: str | None = None)-
Expand source code
class ADCPWebhookSignatureError(ADCPWebhookError): """Webhook signature verification failed.""" def __init__(self, message: str = "Invalid webhook signature", agent_id: str | None = None): """Initialize webhook signature error.""" suggestion = ( "Verify that the webhook_secret matches the secret configured on the agent.\n" " Webhook signatures use HMAC-SHA256 for security." ) super().__init__(message, agent_id, None, suggestion)Webhook signature verification failed.
Initialize webhook signature error.
Ancestors
- ADCPWebhookError
- ADCPError
- builtins.Exception
- builtins.BaseException
class AccountReference (root: RootModelRootType = PydanticUndefined, **data)-
Expand source code
class AccountReference(RootModel[AccountReference1 | AccountReference2]): root: Annotated[ AccountReference1 | AccountReference2, Field( description='Reference to an account by seller-assigned ID or natural key. Use account_id for explicit accounts (require_operator_auth: true, discovered via list_accounts). Use the natural key (brand + operator) for implicit accounts (require_operator_auth: false, declared via sync_accounts). For sandbox: explicit accounts use account_id (pre-existing test account), implicit accounts use the natural key with sandbox: true.', examples=[ {'account_id': 'acc_acme_001'}, {'brand': {'domain': 'acme-corp.com'}, 'operator': 'acme-corp.com'}, { 'brand': {'brand_id': 'spark', 'domain': 'nova-brands.com'}, 'operator': 'pinnacle-media.com', }, { 'brand': {'domain': 'acme-corp.com'}, 'operator': 'acme-corp.com', 'sandbox': True, }, ], title='Account Reference', ), ] def __getattr__(self, name: str) -> Any: """Proxy attribute access to the wrapped type.""" if name.startswith('_'): raise AttributeError(name) return getattr(self.root, name)Usage Documentation
A Pydantic
BaseModelfor the root object of the model.Attributes
root- The root object of the model.
__pydantic_root_model__- Whether the model is a RootModel.
__pydantic_private__- Private fields in the model.
__pydantic_extra__- Extra fields in the model.
Create a new model by parsing and validating input data from keyword arguments.
Raises [
ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.selfis explicitly positional-only to allowselfas a field name.Ancestors
- pydantic.root_model.RootModel[Union[AccountReference1, AccountReference2]]
- pydantic.root_model.RootModel
- pydantic.main.BaseModel
- typing.Generic
Class variables
var model_configvar root : AccountReference1 | AccountReference2
class AccountReferenceById (**data: Any)-
Expand source code
class AccountReference1(AdCPBaseModel): model_config = ConfigDict( extra='forbid', ) account_id: Annotated[ str, Field( description='Seller-assigned account identifier (from sync_accounts or list_accounts)' ), ]Base model for AdCP types with spec-compliant serialization.
Defaults to
extra='ignore'so that unknown fields from newer spec versions are silently dropped rather than causing validation errors. Generated types whose schemas setadditionalProperties: trueoverride this withextra='allow'in their ownmodel_config. Consumers who want strict validation can override withextra='forbid'.Create a new model by parsing and validating input data from keyword arguments.
Raises [
ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.selfis explicitly positional-only to allowselfas a field name.Ancestors
- AdCPBaseModel
- pydantic.main.BaseModel
Class variables
var account_id : strvar model_config
Inherited members
class AccountReferenceByNaturalKey (**data: Any)-
Expand source code
class AccountReference2(AdCPBaseModel): model_config = ConfigDict( extra='forbid', ) brand: Annotated[ brand_ref.BrandReference, Field(description='Brand reference identifying the advertiser') ] operator: Annotated[ str, Field( description="Domain of the entity operating on the brand's behalf. When the brand operates directly, this is the brand's domain.", pattern='^[a-z0-9]([a-z0-9-]*[a-z0-9])?(\\.[a-z0-9]([a-z0-9-]*[a-z0-9])?)*$', ), ] sandbox: Annotated[ bool | None, Field( description='When true, references the sandbox account for this brand/operator pair. Defaults to false (production account).' ), ] = FalseBase model for AdCP types with spec-compliant serialization.
Defaults to
extra='ignore'so that unknown fields from newer spec versions are silently dropped rather than causing validation errors. Generated types whose schemas setadditionalProperties: trueoverride this withextra='allow'in their ownmodel_config. Consumers who want strict validation can override withextra='forbid'.Create a new model by parsing and validating input data from keyword arguments.
Raises [
ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.selfis explicitly positional-only to allowselfas a field name.Ancestors
- AdCPBaseModel
- pydantic.main.BaseModel
Class variables
var brand : BrandReferencevar model_configvar operator : strvar sandbox : bool | None
Inherited members
class AccountScope (*args, **kwds)-
Expand source code
class AccountScope(Enum): operator = 'operator' brand = 'brand' operator_brand = 'operator_brand' agent = 'agent'Create a collection of name/value pairs.
Example enumeration:
>>> class Color(Enum): ... RED = 1 ... BLUE = 2 ... GREEN = 3Access them by:
- attribute access::
>>> Color.RED <Color.RED: 1>- value lookup:
>>> Color(1) <Color.RED: 1>- name lookup:
>>> Color['RED'] <Color.RED: 1>Enumerations can be iterated over, and know how many members they have:
>>> len(Color) 3>>> list(Color) [<Color.RED: 1>, <Color.BLUE: 2>, <Color.GREEN: 3>]Methods can be added to enumerations, and members can have their own attributes – see the documentation for details.
Ancestors
- enum.Enum
Class variables
var agentvar brandvar operatorvar operator_brand
class AcquireRightsRequest (**data: Any)-
Expand source code
class AcquireRightsRequest(AdCPBaseModel): model_config = ConfigDict( extra='allow', ) buyer: Annotated[brand_ref.BrandReference, Field(description="The buyer's brand identity")] campaign: Annotated[Campaign, Field(description='Campaign details for rights clearance')] context: context_1.ContextObject | None = None ext: ext_1.ExtensionObject | None = None idempotency_key: Annotated[ str | None, Field( description='Client-generated key for safe retries. Resubmitting with the same key returns the original response rather than creating a duplicate acquisition. MUST be unique per (seller, request) pair to prevent cross-seller correlation. Use a fresh UUID v4 for each request.', max_length=255, min_length=16, ), ] = None pricing_option_id: Annotated[ str, Field(description='Selected pricing option from the rights offering') ] push_notification_config: Annotated[ push_notification_config_1.PushNotificationConfig | None, Field( description='Webhook for async status updates if the acquisition requires approval. The rights agent sends a webhook notification when the status transitions to acquired or rejected.' ), ] = None revocation_webhook: Annotated[ push_notification_config_1.PushNotificationConfig, Field( description='Webhook for rights revocation notifications. If the rights holder needs to revoke rights (talent scandal, contract violation, etc.), they POST a revocation-notification to this URL. The buyer is responsible for stopping creative delivery upon receipt.' ), ] rights_id: Annotated[ str, Field(description='Rights offering identifier from get_rights response') ]Base model for AdCP types with spec-compliant serialization.
Defaults to
extra='ignore'so that unknown fields from newer spec versions are silently dropped rather than causing validation errors. Generated types whose schemas setadditionalProperties: trueoverride this withextra='allow'in their ownmodel_config. Consumers who want strict validation can override withextra='forbid'.Create a new model by parsing and validating input data from keyword arguments.
Raises [
ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.selfis explicitly positional-only to allowselfas a field name.Ancestors
- AdCPBaseModel
- pydantic.main.BaseModel
Class variables
var buyer : BrandReferencevar campaign : Campaignvar context : ContextObject | Nonevar ext : ExtensionObject | Nonevar idempotency_key : str | Nonevar model_configvar pricing_option_id : strvar push_notification_config : PushNotificationConfig | Nonevar revocation_webhook : PushNotificationConfigvar rights_id : str
Inherited members
class AcquireRightsAcquiredResponse (**data: Any)-
Expand source code
class AcquireRightsResponse1(AdCPBaseModel): model_config = ConfigDict( extra='allow', ) approval_webhook: Annotated[ push_notification_config.PushNotificationConfig | None, Field( description='Authenticated webhook for submitting creatives for approval. POST a creative-approval-request to the URL using the provided authentication. The response is a creative-approval-response.' ), ] = None brand_id: Annotated[str, Field(description='Brand identifier of the rights subject')] context: context_1.ContextObject | None = None disclosure: Annotated[ Disclosure | None, Field(description='Required disclosure for creatives using these rights') ] = None ext: ext_1.ExtensionObject | None = None generation_credentials: Annotated[ list[generation_credential.GenerationCredential], Field(description='Scoped credentials for generating rights-cleared content'), ] restrictions: Annotated[ list[str] | None, Field(description='Usage restrictions and requirements') ] = None rights_constraint: Annotated[ rights_constraint_1.RightsConstraint, Field( description='Pre-built rights constraint for embedding in creative manifests. Populated from the agreed terms — the buyer does not need to construct it manually.' ), ] rights_id: Annotated[str, Field(description='Rights grant identifier')] status: Annotated[ Literal['acquired'], Field(description='Rights have been cleared and credentials issued') ] terms: Annotated[rights_terms.RightsTerms, Field(description='Agreed contractual terms')] usage_reporting_url: Annotated[ AnyUrl | None, Field(description='Endpoint for reporting usage against these rights') ] = NoneBase model for AdCP types with spec-compliant serialization.
Defaults to
extra='ignore'so that unknown fields from newer spec versions are silently dropped rather than causing validation errors. Generated types whose schemas setadditionalProperties: trueoverride this withextra='allow'in their ownmodel_config. Consumers who want strict validation can override withextra='forbid'.Create a new model by parsing and validating input data from keyword arguments.
Raises [
ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.selfis explicitly positional-only to allowselfas a field name.Ancestors
- AdCPBaseModel
- pydantic.main.BaseModel
Class variables
var approval_webhook : PushNotificationConfig | Nonevar brand_id : strvar context : ContextObject | Nonevar disclosure : Disclosure | Nonevar ext : ExtensionObject | Nonevar generation_credentials : list[GenerationCredential]var model_configvar restrictions : list[str] | Nonevar rights_constraint : RightsConstraintvar rights_id : strvar status : Literal['acquired']var terms : RightsTermsvar usage_reporting_url : pydantic.networks.AnyUrl | None
Inherited members
class AcquireRightsPendingResponse (**data: Any)-
Expand source code
class AcquireRightsResponse2(AdCPBaseModel): model_config = ConfigDict( extra='allow', ) brand_id: str context: context_1.ContextObject | None = None detail: Annotated[str | None, Field(description='Explanation of what requires approval')] = None estimated_response_time: Annotated[ str | None, Field(description="Expected time for approval decision (e.g., '48h', '3 business days')"), ] = None ext: ext_1.ExtensionObject | None = None rights_id: str status: Annotated[ Literal['pending_approval'], Field(description='Rights require approval from the rights holder'), ]Base model for AdCP types with spec-compliant serialization.
Defaults to
extra='ignore'so that unknown fields from newer spec versions are silently dropped rather than causing validation errors. Generated types whose schemas setadditionalProperties: trueoverride this withextra='allow'in their ownmodel_config. Consumers who want strict validation can override withextra='forbid'.Create a new model by parsing and validating input data from keyword arguments.
Raises [
ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.selfis explicitly positional-only to allowselfas a field name.Ancestors
- AdCPBaseModel
- pydantic.main.BaseModel
Class variables
var brand_id : strvar context : ContextObject | Nonevar detail : str | Nonevar estimated_response_time : str | Nonevar ext : ExtensionObject | Nonevar model_configvar rights_id : strvar status : Literal['pending_approval']
Inherited members
class AcquireRightsRejectedResponse (**data: Any)-
Expand source code
class AcquireRightsResponse3(AdCPBaseModel): model_config = ConfigDict( extra='allow', ) brand_id: str context: context_1.ContextObject | None = None ext: ext_1.ExtensionObject | None = None reason: Annotated[ str, Field( description="Why the rights request was rejected. May be sanitized to protect confidential brand rules — e.g., 'This violates our public figures brand guidelines' rather than naming the specific rule." ), ] rights_id: str status: Annotated[Literal['rejected'], Field(description='Rights request was rejected')] suggestions: Annotated[ list[str] | None, Field( description='Actionable alternatives the buyer can try. If present, the rejection is fixable — the buyer can adjust their request. If absent, the rejection is final for this talent/rights combination.' ), ] = NoneBase model for AdCP types with spec-compliant serialization.
Defaults to
extra='ignore'so that unknown fields from newer spec versions are silently dropped rather than causing validation errors. Generated types whose schemas setadditionalProperties: trueoverride this withextra='allow'in their ownmodel_config. Consumers who want strict validation can override withextra='forbid'.Create a new model by parsing and validating input data from keyword arguments.
Raises [
ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.selfis explicitly positional-only to allowselfas a field name.Ancestors
- AdCPBaseModel
- pydantic.main.BaseModel
Class variables
var brand_id : strvar context : ContextObject | Nonevar ext : ExtensionObject | Nonevar model_configvar reason : strvar rights_id : strvar status : Literal['rejected']var suggestions : list[str] | None
Inherited members
class AcquireRightsErrorResponse (**data: Any)-
Expand source code
class AcquireRightsResponse4(AdCPBaseModel): model_config = ConfigDict( extra='allow', ) context: context_1.ContextObject | None = None errors: Annotated[list[error.Error], Field(min_length=1)] ext: ext_1.ExtensionObject | None = NoneBase model for AdCP types with spec-compliant serialization.
Defaults to
extra='ignore'so that unknown fields from newer spec versions are silently dropped rather than causing validation errors. Generated types whose schemas setadditionalProperties: trueoverride this withextra='allow'in their ownmodel_config. Consumers who want strict validation can override withextra='forbid'.Create a new model by parsing and validating input data from keyword arguments.
Raises [
ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.selfis explicitly positional-only to allowselfas a field name.Ancestors
- AdCPBaseModel
- pydantic.main.BaseModel
Class variables
var context : ContextObject | Nonevar errors : list[Error]var ext : ExtensionObject | Nonevar model_config
Inherited members
class ActivateSignalRequest (**data: Any)-
Expand source code
class ActivateSignalRequest(AdCPBaseModel): model_config = ConfigDict( extra='allow', ) account: Annotated[ account_ref.AccountReference | None, Field( description='Account for this activation. Associates with a commercial relationship established via sync_accounts.' ), ] = None action: Annotated[ Action | None, Field( description="Whether to activate or deactivate the signal. Deactivating removes the segment from downstream platforms, required when campaigns end to comply with data governance policies (GDPR, CCPA). Defaults to 'activate' when omitted." ), ] = Action.activate context: context_1.ContextObject | None = None destinations: Annotated[ list[destination.Destination], Field( description='Target destination(s) for activation. If the authenticated caller matches one of these destinations, activation keys will be included in the response.', min_length=1, ), ] ext: ext_1.ExtensionObject | None = None idempotency_key: Annotated[ str | None, Field( description='Client-generated unique key for this request. Prevents duplicate activations on retries. MUST be unique per (seller, request) pair to prevent cross-seller correlation. Use a fresh UUID v4 for each request.', max_length=255, min_length=16, ), ] = None pricing_option_id: Annotated[ str | None, Field( description="The pricing option selected from the signal's pricing_options in the get_signals response. Required when the signal has pricing options. Records the buyer's pricing commitment at activation time; pass this same value in report_usage for billing verification." ), ] = None signal_agent_segment_id: Annotated[ str, Field(description='The universal identifier for the signal to activate') ]Base model for AdCP types with spec-compliant serialization.
Defaults to
extra='ignore'so that unknown fields from newer spec versions are silently dropped rather than causing validation errors. Generated types whose schemas setadditionalProperties: trueoverride this withextra='allow'in their ownmodel_config. Consumers who want strict validation can override withextra='forbid'.Create a new model by parsing and validating input data from keyword arguments.
Raises [
ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.selfis explicitly positional-only to allowselfas a field name.Ancestors
- AdCPBaseModel
- pydantic.main.BaseModel
Class variables
var account : AccountReference | Nonevar action : Action | Nonevar context : ContextObject | Nonevar destinations : list[Destination]var ext : ExtensionObject | Nonevar idempotency_key : str | Nonevar model_configvar pricing_option_id : str | Nonevar signal_agent_segment_id : str
Inherited members
class ActivateSignalSuccessResponse (**data: Any)-
Expand source code
class ActivateSignalResponse1(AdCPBaseModel): model_config = ConfigDict( extra='allow', ) context: context_1.ContextObject | None = None deployments: Annotated[ list[deployment.Deployment], Field(description='Array of deployment results for each deployment target'), ] ext: ext_1.ExtensionObject | None = None sandbox: Annotated[ bool | None, Field(description='When true, this response contains simulated data from sandbox mode.'), ] = NoneBase model for AdCP types with spec-compliant serialization.
Defaults to
extra='ignore'so that unknown fields from newer spec versions are silently dropped rather than causing validation errors. Generated types whose schemas setadditionalProperties: trueoverride this withextra='allow'in their ownmodel_config. Consumers who want strict validation can override withextra='forbid'.Create a new model by parsing and validating input data from keyword arguments.
Raises [
ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.selfis explicitly positional-only to allowselfas a field name.Ancestors
- AdCPBaseModel
- pydantic.main.BaseModel
Class variables
var context : ContextObject | Nonevar deployments : list[Deployment]var ext : ExtensionObject | Nonevar model_configvar sandbox : bool | None
Inherited members
class ActivateSignalErrorResponse (**data: Any)-
Expand source code
class ActivateSignalResponse2(AdCPBaseModel): model_config = ConfigDict( extra='allow', ) context: context_1.ContextObject | None = None errors: Annotated[ list[error.Error], Field( description='Array of errors explaining why activation failed (e.g., platform connectivity issues, signal definition problems, authentication failures)', min_length=1, ), ] ext: ext_1.ExtensionObject | None = NoneBase model for AdCP types with spec-compliant serialization.
Defaults to
extra='ignore'so that unknown fields from newer spec versions are silently dropped rather than causing validation errors. Generated types whose schemas setadditionalProperties: trueoverride this withextra='allow'in their ownmodel_config. Consumers who want strict validation can override withextra='forbid'.Create a new model by parsing and validating input data from keyword arguments.
Raises [
ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.selfis explicitly positional-only to allowselfas a field name.Ancestors
- AdCPBaseModel
- pydantic.main.BaseModel
Class variables
var context : ContextObject | Nonevar errors : list[Error]var ext : ExtensionObject | Nonevar model_config
Inherited members
class SegmentIdActivationKey (**data: Any)-
Expand source code
class ActivationKey1(AdCPBaseModel): model_config = ConfigDict( extra='allow', ) segment_id: Annotated[ str, Field(description='The platform-specific segment identifier to use in campaign targeting'), ] type: Annotated[Literal['segment_id'], Field(description='Segment ID based targeting')]Base model for AdCP types with spec-compliant serialization.
Defaults to
extra='ignore'so that unknown fields from newer spec versions are silently dropped rather than causing validation errors. Generated types whose schemas setadditionalProperties: trueoverride this withextra='allow'in their ownmodel_config. Consumers who want strict validation can override withextra='forbid'.Create a new model by parsing and validating input data from keyword arguments.
Raises [
ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.selfis explicitly positional-only to allowselfas a field name.Ancestors
- AdCPBaseModel
- pydantic.main.BaseModel
Class variables
var model_configvar segment_id : strvar type : Literal['segment_id']
class PropertyIdActivationKey (**data: Any)-
Expand source code
class ActivationKey1(AdCPBaseModel): model_config = ConfigDict( extra='allow', ) segment_id: Annotated[ str, Field(description='The platform-specific segment identifier to use in campaign targeting'), ] type: Annotated[Literal['segment_id'], Field(description='Segment ID based targeting')]Base model for AdCP types with spec-compliant serialization.
Defaults to
extra='ignore'so that unknown fields from newer spec versions are silently dropped rather than causing validation errors. Generated types whose schemas setadditionalProperties: trueoverride this withextra='allow'in their ownmodel_config. Consumers who want strict validation can override withextra='forbid'.Create a new model by parsing and validating input data from keyword arguments.
Raises [
ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.selfis explicitly positional-only to allowselfas a field name.Ancestors
- AdCPBaseModel
- pydantic.main.BaseModel
Class variables
var model_configvar segment_id : strvar type : Literal['segment_id']
Inherited members
class KeyValueActivationKey (**data: Any)-
Expand source code
class ActivationKey2(AdCPBaseModel): model_config = ConfigDict( extra='allow', ) key: Annotated[str, Field(description='The targeting parameter key')] type: Annotated[Literal['key_value'], Field(description='Key-value pair based targeting')] value: Annotated[str, Field(description='The targeting parameter value')]Base model for AdCP types with spec-compliant serialization.
Defaults to
extra='ignore'so that unknown fields from newer spec versions are silently dropped rather than causing validation errors. Generated types whose schemas setadditionalProperties: trueoverride this withextra='allow'in their ownmodel_config. Consumers who want strict validation can override withextra='forbid'.Create a new model by parsing and validating input data from keyword arguments.
Raises [
ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.selfis explicitly positional-only to allowselfas a field name.Ancestors
- AdCPBaseModel
- pydantic.main.BaseModel
Class variables
var key : strvar model_configvar type : Literal['key_value']var value : str
class PropertyTagActivationKey (**data: Any)-
Expand source code
class ActivationKey2(AdCPBaseModel): model_config = ConfigDict( extra='allow', ) key: Annotated[str, Field(description='The targeting parameter key')] type: Annotated[Literal['key_value'], Field(description='Key-value pair based targeting')] value: Annotated[str, Field(description='The targeting parameter value')]Base model for AdCP types with spec-compliant serialization.
Defaults to
extra='ignore'so that unknown fields from newer spec versions are silently dropped rather than causing validation errors. Generated types whose schemas setadditionalProperties: trueoverride this withextra='allow'in their ownmodel_config. Consumers who want strict validation can override withextra='forbid'.Create a new model by parsing and validating input data from keyword arguments.
Raises [
ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.selfis explicitly positional-only to allowselfas a field name.Ancestors
- AdCPBaseModel
- pydantic.main.BaseModel
Class variables
var key : strvar model_configvar type : Literal['key_value']var value : str
Inherited members
class AdagentsNotFoundError (publisher_domain: str)-
Expand source code
class AdagentsNotFoundError(AdagentsValidationError): """adagents.json file not found (404).""" def __init__(self, publisher_domain: str): """Initialize not found error.""" message = f"adagents.json not found for domain: {publisher_domain}" suggestion = ( "Verify that the publisher has deployed adagents.json to:\n" f" https://{publisher_domain}/.well-known/adagents.json" ) super().__init__(message, None, None, suggestion)adagents.json file not found (404).
Initialize not found error.
Ancestors
- AdagentsValidationError
- ADCPError
- builtins.Exception
- builtins.BaseException
class AdagentsTimeoutError (publisher_domain: str, timeout: float)-
Expand source code
class AdagentsTimeoutError(AdagentsValidationError): """Request for adagents.json timed out.""" def __init__(self, publisher_domain: str, timeout: float): """Initialize timeout error.""" message = f"Request to fetch adagents.json timed out after {timeout}s" suggestion = ( "The publisher's server may be slow or unresponsive.\n" " Try increasing the timeout value or check the domain is correct." ) super().__init__(message, None, None, suggestion)Request for adagents.json timed out.
Initialize timeout error.
Ancestors
- AdagentsValidationError
- ADCPError
- builtins.Exception
- builtins.BaseException
class AdagentsValidationError (message: str,
agent_id: str | None = None,
agent_uri: str | None = None,
suggestion: str | None = None)-
Expand source code
class AdagentsValidationError(ADCPError): """Base error for adagents.json validation issues."""Base error for adagents.json validation issues.
Initialize exception with context.
Ancestors
- ADCPError
- builtins.Exception
- builtins.BaseException
Subclasses
class AgentCapabilities (**data: Any)-
Expand source code
class AgentCapabilities(RegistryBaseModel): tools_count: int tools: list[AgentTool] | None = None standard_operations: AgentStandardOperations | None = None creative_capabilities: AgentCreativeCapabilities | None = NoneBase model for registry API types.
Uses
extra='allow'so that new fields from the registry API are preserved rather than dropped. This differs from AdCPBaseModel which defaults toextra='ignore'for protocol types.Create a new model by parsing and validating input data from keyword arguments.
Raises [
ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.selfis explicitly positional-only to allowselfas a field name.Ancestors
- RegistryBaseModel
- pydantic.main.BaseModel
Class variables
var creative_capabilities : AgentCreativeCapabilities | Nonevar model_configvar standard_operations : AgentStandardOperations | Nonevar tools : list[AgentTool] | Nonevar tools_count : int
class AgentCompliance (**data: Any)-
Expand source code
class AgentCompliance(RegistryBaseModel): status: ComplianceStatus lifecycle_stage: AgentLifecycleStage tracks: Annotated[dict[str, str], Field(examples=[{"core": "pass", "products": "fail"}])] streak_days: int last_checked_at: str | None headline: str | NoneBase model for registry API types.
Uses
extra='allow'so that new fields from the registry API are preserved rather than dropped. This differs from AdCPBaseModel which defaults toextra='ignore'for protocol types.Create a new model by parsing and validating input data from keyword arguments.
Raises [
ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.selfis explicitly positional-only to allowselfas a field name.Ancestors
- RegistryBaseModel
- pydantic.main.BaseModel
Class variables
var headline : str | Nonevar last_checked_at : str | Nonevar lifecycle_stage : AgentLifecycleStagevar model_configvar status : ComplianceStatusvar streak_days : intvar tracks : dict[str, str]
class AgentConfig (**data: Any)-
Expand source code
class AgentConfig(BaseModel): """Agent configuration.""" id: str agent_uri: str protocol: Protocol auth_token: str | None = None requires_auth: bool = False auth_header: str = "x-adcp-auth" # Header name for authentication auth_type: str = "token" # "token" for direct value, "bearer" for "Bearer {token}" timeout: float = 30.0 # Request timeout in seconds mcp_transport: str = ( "streamable_http" # "streamable_http" (default, modern) or "sse" (legacy fallback) ) debug: bool = False # Enable debug mode to capture request/response details @field_validator("agent_uri") @classmethod def validate_agent_uri(cls, v: str) -> str: """Validate agent URI format.""" if not v: raise ValueError("agent_uri cannot be empty") if not v.startswith(("http://", "https://")): raise ValueError( f"agent_uri must start with http:// or https://, got: {v}\n" "Example: https://agent.example.com" ) # Remove trailing slash for consistency return v.rstrip("/") @field_validator("timeout") @classmethod def validate_timeout(cls, v: float) -> float: """Validate timeout is reasonable.""" if v <= 0: raise ValueError(f"timeout must be positive, got: {v}") if v > 300: # 5 minutes raise ValueError( f"timeout is very large ({v}s). Consider a value under 300 seconds.\n" "Large timeouts can cause long hangs if agent is unresponsive." ) return v @field_validator("mcp_transport") @classmethod def validate_mcp_transport(cls, v: str) -> str: """Validate MCP transport type.""" valid_transports = ["streamable_http", "sse"] if v not in valid_transports: raise ValueError( f"mcp_transport must be one of {valid_transports}, got: {v}\n" "Use 'streamable_http' for modern agents (recommended)" ) return v @field_validator("auth_type") @classmethod def validate_auth_type(cls, v: str) -> str: """Validate auth type.""" valid_types = ["token", "bearer"] if v not in valid_types: raise ValueError( f"auth_type must be one of {valid_types}, got: {v}\n" "Use 'bearer' for OAuth2/standard Authorization header" ) return vAgent configuration.
Create a new model by parsing and validating input data from keyword arguments.
Raises [
ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.selfis explicitly positional-only to allowselfas a field name.Ancestors
- pydantic.main.BaseModel
Class variables
var agent_uri : strvar auth_header : strvar auth_token : str | Nonevar auth_type : strvar debug : boolvar id : strvar mcp_transport : strvar model_configvar protocol : Protocolvar requires_auth : boolvar timeout : float
Static methods
def validate_agent_uri(v: str) ‑> str-
Validate agent URI format.
def validate_auth_type(v: str) ‑> str-
Validate auth type.
def validate_mcp_transport(v: str) ‑> str-
Validate MCP transport type.
def validate_timeout(v: float) ‑> float-
Validate timeout is reasonable.
class AgentHealth (**data: Any)-
Expand source code
class AgentHealth(RegistryBaseModel): online: bool checked_at: str response_time_ms: float | None = None tools_count: int | None = None resources_count: int | None = None error: str | None = NoneBase model for registry API types.
Uses
extra='allow'so that new fields from the registry API are preserved rather than dropped. This differs from AdCPBaseModel which defaults toextra='ignore'for protocol types.Create a new model by parsing and validating input data from keyword arguments.
Raises [
ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.selfis explicitly positional-only to allowselfas a field name.Ancestors
- RegistryBaseModel
- pydantic.main.BaseModel
Class variables
var checked_at : strvar error : str | Nonevar model_configvar online : boolvar resources_count : int | Nonevar response_time_ms : float | Nonevar tools_count : int | None
class AgentStats (**data: Any)-
Expand source code
class AgentStats(RegistryBaseModel): property_count: int | None = None publisher_count: int | None = None publishers: list[str] | None = None creative_formats: int | None = NoneBase model for registry API types.
Uses
extra='allow'so that new fields from the registry API are preserved rather than dropped. This differs from AdCPBaseModel which defaults toextra='ignore'for protocol types.Create a new model by parsing and validating input data from keyword arguments.
Raises [
ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.selfis explicitly positional-only to allowselfas a field name.Ancestors
- RegistryBaseModel
- pydantic.main.BaseModel
Class variables
var creative_formats : int | Nonevar model_configvar property_count : int | Nonevar publisher_count : int | Nonevar publishers : list[str] | None
class ArtifactWebhookPayload (**data: Any)-
Expand source code
class ArtifactWebhookPayload(AdCPBaseModel): model_config = ConfigDict( extra='allow', ) artifacts: Annotated[ list[Artifact], Field(description='Content artifacts from delivered impressions') ] batch_id: Annotated[ str, Field( description='Unique identifier for this batch of artifacts. Use for deduplication and acknowledgment.' ), ] ext: ext_1.ExtensionObject | None = None media_buy_id: Annotated[ str, Field(description='Media buy identifier these artifacts belong to') ] pagination: Annotated[ Pagination | None, Field(description='Pagination info when batching large artifact sets') ] = None timestamp: Annotated[ AwareDatetime, Field(description='When this batch was generated (ISO 8601)') ]Base model for AdCP types with spec-compliant serialization.
Defaults to
extra='ignore'so that unknown fields from newer spec versions are silently dropped rather than causing validation errors. Generated types whose schemas setadditionalProperties: trueoverride this withextra='allow'in their ownmodel_config. Consumers who want strict validation can override withextra='forbid'.Create a new model by parsing and validating input data from keyword arguments.
Raises [
ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.selfis explicitly positional-only to allowselfas a field name.Ancestors
- AdCPBaseModel
- pydantic.main.BaseModel
Class variables
var artifacts : list[Artifact]var batch_id : strvar ext : ExtensionObject | Nonevar media_buy_id : strvar model_configvar pagination : Pagination | Nonevar timestamp : pydantic.types.AwareDatetime
Inherited members
class AssetContentType (*args, **kwds)-
Expand source code
class AssetContentType(Enum): image = 'image' video = 'video' audio = 'audio' text = 'text' markdown = 'markdown' html = 'html' css = 'css' javascript = 'javascript' vast = 'vast' daast = 'daast' url = 'url' webhook = 'webhook' brief = 'brief' catalog = 'catalog'Create a collection of name/value pairs.
Example enumeration:
>>> class Color(Enum): ... RED = 1 ... BLUE = 2 ... GREEN = 3Access them by:
- attribute access::
>>> Color.RED <Color.RED: 1>- value lookup:
>>> Color(1) <Color.RED: 1>- name lookup:
>>> Color['RED'] <Color.RED: 1>Enumerations can be iterated over, and know how many members they have:
>>> len(Color) 3>>> list(Color) [<Color.RED: 1>, <Color.BLUE: 2>, <Color.GREEN: 3>]Methods can be added to enumerations, and members can have their own attributes – see the documentation for details.
Ancestors
- enum.Enum
Class variables
var audiovar briefvar catalogvar cssvar daastvar htmlvar imagevar javascriptvar markdownvar textvar urlvar vastvar videovar webhook
class SyncAudiencesAudience (**data: Any)-
Expand source code
class Audience(AdCPBaseModel): model_config = ConfigDict( extra='allow', ) add: Annotated[ list[audience_member.AudienceMember] | None, Field( description='Members to add to this audience. Hashed before sending — normalize emails to lowercase+trim, phones to E.164.', min_length=1, ), ] = None audience_id: Annotated[ str, Field( description="Buyer's identifier for this audience. Used to reference the audience in targeting overlays." ), ] audience_type: Annotated[ AudienceType | None, Field( description="Intended use for this audience. 'crm': target these users. 'suppression': exclude these users from delivery. 'lookalike_seed': use as a seed for the seller's lookalike modeling. Sellers may handle audiences differently based on type (e.g., suppression lists bypass minimum size requirements on some platforms)." ), ] = None consent_basis: Annotated[ consent_basis_1.ConsentBasis | None, Field( description='GDPR lawful basis for processing this audience list. Informational — not validated by the protocol, but required by some sellers operating in regulated markets (e.g. EU). When omitted, the buyer asserts they have a lawful basis appropriate to their jurisdiction.' ), ] = None delete: Annotated[ bool | None, Field( description='When true, delete this audience from the account entirely. All other fields on this audience object are ignored. Use this to delete a specific audience without affecting others.' ), ] = None description: Annotated[ str | None, Field( description="Human-readable description of this audience's composition or purpose (e.g., 'High-value customers who purchased in the last 90 days')." ), ] = None name: Annotated[str | None, Field(description='Human-readable name for this audience')] = None remove: Annotated[ list[audience_member.AudienceMember] | None, Field( description='Members to remove from this audience. If the same identifier appears in both add and remove in a single request, remove takes precedence.', min_length=1, ), ] = None tags: Annotated[ list[Tag] | None, Field( description="Buyer-defined tags for organizing and filtering audiences (e.g., 'holiday_2026', 'high_ltv'). Tags are stored by the seller and returned in discovery-only calls." ), ] = NoneBase model for AdCP types with spec-compliant serialization.
Defaults to
extra='ignore'so that unknown fields from newer spec versions are silently dropped rather than causing validation errors. Generated types whose schemas setadditionalProperties: trueoverride this withextra='allow'in their ownmodel_config. Consumers who want strict validation can override withextra='forbid'.Create a new model by parsing and validating input data from keyword arguments.
Raises [
ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.selfis explicitly positional-only to allowselfas a field name.Ancestors
- AdCPBaseModel
- pydantic.main.BaseModel
Class variables
var add : list[AudienceMember] | Nonevar audience_id : strvar audience_type : AudienceType | Nonevar consent_basis : ConsentBasis | Nonevar delete : bool | Nonevar description : str | Nonevar model_configvar name : str | Nonevar remove : list[AudienceMember] | None
Inherited members
class AudienceSource (*args, **kwds)-
Expand source code
class AudienceSource(Enum): synced = 'synced' platform = 'platform' third_party = 'third_party' lookalike = 'lookalike' retargeting = 'retargeting' unknown = 'unknown'Create a collection of name/value pairs.
Example enumeration:
>>> class Color(Enum): ... RED = 1 ... BLUE = 2 ... GREEN = 3Access them by:
- attribute access::
>>> Color.RED <Color.RED: 1>- value lookup:
>>> Color(1) <Color.RED: 1>- name lookup:
>>> Color['RED'] <Color.RED: 1>Enumerations can be iterated over, and know how many members they have:
>>> len(Color) 3>>> list(Color) [<Color.RED: 1>, <Color.BLUE: 2>, <Color.GREEN: 3>]Methods can be added to enumerations, and members can have their own attributes – see the documentation for details.
Ancestors
- enum.Enum
Class variables
var lookalikevar platformvar retargetingvar syncedvar third_partyvar unknown
class AuthorizationContext (properties: list[dict[str, Any]])-
Expand source code
class AuthorizationContext: """Authorization context for a publisher domain. Attributes: property_ids: List of property IDs the agent is authorized for property_tags: List of property tags the agent is authorized for raw_properties: Raw property data from adagents.json """ def __init__(self, properties: list[dict[str, Any]]): """Initialize from list of properties. Args: properties: List of property dictionaries from adagents.json """ self.property_ids: list[str] = [] self.property_tags: list[str] = [] self.raw_properties = properties # Extract property IDs and tags for prop in properties: if not isinstance(prop, dict): continue # Extract property ID (per AdCP v2 schema, the field is "property_id") prop_id = prop.get("property_id") if prop_id and isinstance(prop_id, str): self.property_ids.append(prop_id) # Extract tags tags = prop.get("tags", []) if isinstance(tags, list): for tag in tags: if isinstance(tag, str) and tag not in self.property_tags: self.property_tags.append(tag) def __repr__(self) -> str: return ( f"AuthorizationContext(" f"property_ids={self.property_ids}, " f"property_tags={self.property_tags})" )Authorization context for a publisher domain.
Attributes
property_ids- List of property IDs the agent is authorized for
property_tags- List of property tags the agent is authorized for
raw_properties- Raw property data from adagents.json
Initialize from list of properties.
Args
properties- List of property dictionaries from adagents.json
class AuthorizedAgentsByPropertyId (**data: Any)-
Expand source code
class AuthorizedAgents(AdCPBaseModel): model_config = ConfigDict( extra='allow', ) authorization_type: Annotated[ Literal['property_ids'], Field(description='Discriminator indicating authorization by specific property IDs'), ] authorized_for: Annotated[ str, Field( description='Human-readable description of what this agent is authorized to sell', max_length=500, min_length=1, ), ] collections: Annotated[ list[collection_selector.CollectionSelector] | None, Field( description='Optional collection constraints. When present, authorization only applies to inventory associated with these collections.', min_length=1, ), ] = None countries: Annotated[ list[Country] | None, Field( description='Optional ISO 3166-1 alpha-2 country codes limiting where this authorization applies. Omit for worldwide authorization.', min_length=1, ), ] = None delegation_type: Annotated[ DelegationType | None, Field( description="Commercial relationship for this inventory path. 'direct' means the publisher treats this as a direct way to buy from them, even if a third party operates the software. 'delegated' means the agent is authorized to sell on the publisher's behalf. 'ad_network' means the inventory is sold as part of a network/package context rather than as the publisher's direct endpoint." ), ] = None effective_from: Annotated[ AwareDatetime | None, Field(description='Optional start time for this authorization window.'), ] = None effective_until: Annotated[ AwareDatetime | None, Field(description='Optional end time for this authorization window.') ] = None exclusive: Annotated[ bool | None, Field( description="Whether this agent is the publisher's sole authorized path for the scoped inventory slice. When false or absent, other authorized agents may also sell the same inventory." ), ] = None placement_ids: Annotated[ list[str] | None, Field( description='Optional placement constraints. When present, authorization only applies to these placement IDs from the top-level placements array in this file.', min_length=1, ), ] = None placement_tags: Annotated[ list[str] | None, Field( description='Optional placement tag constraints. When present, authorization only applies to placements whose tags include any of these publisher-defined values.', min_length=1, ), ] = None property_ids: Annotated[ list[property_id.PropertyId], Field( description='Property IDs this agent is authorized for. Resolved against the top-level properties array in this file', min_length=1, ), ] signing_keys: Annotated[ list[agent_signing_key.AgentSigningKey] | None, Field( description='Optional publisher-attested public signing keys for this agent. Use these as the trust anchor for verifying signed agent responses instead of relying on key discovery from the agent domain alone.', min_length=1, ), ] = None url: Annotated[AnyUrl, Field(description="The authorized agent's API endpoint URL")]Base model for AdCP types with spec-compliant serialization.
Defaults to
extra='ignore'so that unknown fields from newer spec versions are silently dropped rather than causing validation errors. Generated types whose schemas setadditionalProperties: trueoverride this withextra='allow'in their ownmodel_config. Consumers who want strict validation can override withextra='forbid'.Create a new model by parsing and validating input data from keyword arguments.
Raises [
ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.selfis explicitly positional-only to allowselfas a field name.Ancestors
- AdCPBaseModel
- pydantic.main.BaseModel
Class variables
var collections : list[CollectionSelector] | Nonevar countries : list[Country] | Nonevar delegation_type : DelegationType | Nonevar effective_from : pydantic.types.AwareDatetime | Nonevar effective_until : pydantic.types.AwareDatetime | Nonevar exclusive : bool | Nonevar model_configvar placement_ids : list[str] | Nonevar property_ids : list[PropertyId]var signing_keys : list[AgentSigningKey] | Nonevar url : pydantic.networks.AnyUrl
Inherited members
class AuthorizedAgentsByPropertyTag (**data: Any)-
Expand source code
class AuthorizedAgents1(AdCPBaseModel): model_config = ConfigDict( extra='allow', ) authorization_type: Annotated[ Literal['property_tags'], Field(description='Discriminator indicating authorization by property tags'), ] authorized_for: Annotated[ str, Field( description='Human-readable description of what this agent is authorized to sell', max_length=500, min_length=1, ), ] collections: Annotated[ list[collection_selector.CollectionSelector] | None, Field( description='Optional collection constraints. When present, authorization only applies to inventory associated with these collections.', min_length=1, ), ] = None countries: Annotated[ list[Country] | None, Field( description='Optional ISO 3166-1 alpha-2 country codes limiting where this authorization applies. Omit for worldwide authorization.', min_length=1, ), ] = None delegation_type: Annotated[ DelegationType | None, Field( description="Commercial relationship for this inventory path. 'direct' means the publisher treats this as a direct way to buy from them, even if a third party operates the software. 'delegated' means the agent is authorized to sell on the publisher's behalf. 'ad_network' means the inventory is sold as part of a network/package context rather than as the publisher's direct endpoint." ), ] = None effective_from: Annotated[ AwareDatetime | None, Field(description='Optional start time for this authorization window.'), ] = None effective_until: Annotated[ AwareDatetime | None, Field(description='Optional end time for this authorization window.') ] = None exclusive: Annotated[ bool | None, Field( description="Whether this agent is the publisher's sole authorized path for the scoped inventory slice. When false or absent, other authorized agents may also sell the same inventory." ), ] = None placement_ids: Annotated[ list[str] | None, Field( description='Optional placement constraints. When present, authorization only applies to these placement IDs from the top-level placements array in this file.', min_length=1, ), ] = None placement_tags: Annotated[ list[str] | None, Field( description='Optional placement tag constraints. When present, authorization only applies to placements whose tags include any of these publisher-defined values.', min_length=1, ), ] = None property_tags: Annotated[ list[property_tag.PropertyTag], Field( description='Tags identifying which properties this agent is authorized for. Resolved against the top-level properties array in this file using tag matching', min_length=1, ), ] signing_keys: Annotated[ list[agent_signing_key.AgentSigningKey] | None, Field( description='Optional publisher-attested public signing keys for this agent. Use these as the trust anchor for verifying signed agent responses instead of relying on key discovery from the agent domain alone.', min_length=1, ), ] = None url: Annotated[AnyUrl, Field(description="The authorized agent's API endpoint URL")]Base model for AdCP types with spec-compliant serialization.
Defaults to
extra='ignore'so that unknown fields from newer spec versions are silently dropped rather than causing validation errors. Generated types whose schemas setadditionalProperties: trueoverride this withextra='allow'in their ownmodel_config. Consumers who want strict validation can override withextra='forbid'.Create a new model by parsing and validating input data from keyword arguments.
Raises [
ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.selfis explicitly positional-only to allowselfas a field name.Ancestors
- AdCPBaseModel
- pydantic.main.BaseModel
Class variables
var collections : list[CollectionSelector] | Nonevar countries : list[Country] | Nonevar delegation_type : DelegationType | Nonevar effective_from : pydantic.types.AwareDatetime | Nonevar effective_until : pydantic.types.AwareDatetime | Nonevar exclusive : bool | Nonevar model_configvar placement_ids : list[str] | Nonevar signing_keys : list[AgentSigningKey] | Nonevar url : pydantic.networks.AnyUrl
Inherited members
class AuthorizedAgentsByInlineProperties (**data: Any)-
Expand source code
class AuthorizedAgents2(AdCPBaseModel): model_config = ConfigDict( extra='allow', ) authorization_type: Annotated[ Literal['inline_properties'], Field(description='Discriminator indicating authorization by inline property definitions'), ] authorized_for: Annotated[ str, Field( description='Human-readable description of what this agent is authorized to sell', max_length=500, min_length=1, ), ] collections: Annotated[ list[collection_selector.CollectionSelector] | None, Field( description='Optional collection constraints. When present, authorization only applies to inventory associated with these collections.', min_length=1, ), ] = None countries: Annotated[ list[Country] | None, Field( description='Optional ISO 3166-1 alpha-2 country codes limiting where this authorization applies. Omit for worldwide authorization.', min_length=1, ), ] = None delegation_type: Annotated[ DelegationType | None, Field( description="Commercial relationship for this inventory path. 'direct' means the publisher treats this as a direct way to buy from them, even if a third party operates the software. 'delegated' means the agent is authorized to sell on the publisher's behalf. 'ad_network' means the inventory is sold as part of a network/package context rather than as the publisher's direct endpoint." ), ] = None effective_from: Annotated[ AwareDatetime | None, Field(description='Optional start time for this authorization window.'), ] = None effective_until: Annotated[ AwareDatetime | None, Field(description='Optional end time for this authorization window.') ] = None exclusive: Annotated[ bool | None, Field( description="Whether this agent is the publisher's sole authorized path for the scoped inventory slice. When false or absent, other authorized agents may also sell the same inventory." ), ] = None placement_ids: Annotated[ list[str] | None, Field( description='Optional placement constraints. When present, authorization only applies to these placement IDs from the top-level placements array in this file.', min_length=1, ), ] = None placement_tags: Annotated[ list[str] | None, Field( description='Optional placement tag constraints. When present, authorization only applies to placements whose tags include any of these publisher-defined values.', min_length=1, ), ] = None properties: Annotated[ list[property.Property], Field( description='Specific properties this agent is authorized for (alternative to property_ids/property_tags)', min_length=1, ), ] signing_keys: Annotated[ list[agent_signing_key.AgentSigningKey] | None, Field( description='Optional publisher-attested public signing keys for this agent. Use these as the trust anchor for verifying signed agent responses instead of relying on key discovery from the agent domain alone.', min_length=1, ), ] = None url: Annotated[AnyUrl, Field(description="The authorized agent's API endpoint URL")]Base model for AdCP types with spec-compliant serialization.
Defaults to
extra='ignore'so that unknown fields from newer spec versions are silently dropped rather than causing validation errors. Generated types whose schemas setadditionalProperties: trueoverride this withextra='allow'in their ownmodel_config. Consumers who want strict validation can override withextra='forbid'.Create a new model by parsing and validating input data from keyword arguments.
Raises [
ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.selfis explicitly positional-only to allowselfas a field name.Ancestors
- AdCPBaseModel
- pydantic.main.BaseModel
Class variables
var collections : list[CollectionSelector] | Nonevar countries : list[Country] | Nonevar delegation_type : DelegationType | Nonevar effective_from : pydantic.types.AwareDatetime | Nonevar effective_until : pydantic.types.AwareDatetime | Nonevar exclusive : bool | Nonevar model_configvar placement_ids : list[str] | Nonevar properties : list[Property]var signing_keys : list[AgentSigningKey] | Nonevar url : pydantic.networks.AnyUrl
Inherited members
class AuthorizedAgentsByPublisherProperties (**data: Any)-
Expand source code
class AuthorizedAgents3(AdCPBaseModel): model_config = ConfigDict( extra='allow', ) authorization_type: Annotated[ Literal['publisher_properties'], Field( description='Discriminator indicating authorization for properties from other publisher domains' ), ] authorized_for: Annotated[ str, Field( description='Human-readable description of what this agent is authorized to sell', max_length=500, min_length=1, ), ] collections: Annotated[ list[collection_selector.CollectionSelector] | None, Field( description='Optional collection constraints. When present, authorization only applies to inventory associated with these collections.', min_length=1, ), ] = None countries: Annotated[ list[Country] | None, Field( description='Optional ISO 3166-1 alpha-2 country codes limiting where this authorization applies. Omit for worldwide authorization.', min_length=1, ), ] = None delegation_type: Annotated[ DelegationType | None, Field( description="Commercial relationship for this inventory path. 'direct' means the publisher treats this as a direct way to buy from them, even if a third party operates the software. 'delegated' means the agent is authorized to sell on the publisher's behalf. 'ad_network' means the inventory is sold as part of a network/package context rather than as the publisher's direct endpoint." ), ] = None effective_from: Annotated[ AwareDatetime | None, Field(description='Optional start time for this authorization window.'), ] = None effective_until: Annotated[ AwareDatetime | None, Field(description='Optional end time for this authorization window.') ] = None exclusive: Annotated[ bool | None, Field( description="Whether this agent is the publisher's sole authorized path for the scoped inventory slice. When false or absent, other authorized agents may also sell the same inventory." ), ] = None placement_ids: Annotated[ list[str] | None, Field( description='Optional placement constraints. When present, authorization only applies to these placement IDs from the top-level placements array in this file.', min_length=1, ), ] = None placement_tags: Annotated[ list[str] | None, Field( description='Optional placement tag constraints. When present, authorization only applies to placements whose tags include any of these publisher-defined values.', min_length=1, ), ] = None publisher_properties: Annotated[ list[publisher_property_selector.PublisherPropertySelector], Field( description='Properties from other publisher domains this agent is authorized for. Each entry specifies a publisher domain and which of their properties this agent can sell', min_length=1, ), ] signing_keys: Annotated[ list[agent_signing_key.AgentSigningKey] | None, Field( description='Optional publisher-attested public signing keys for this agent. Use these as the trust anchor for verifying signed agent responses instead of relying on key discovery from the agent domain alone.', min_length=1, ), ] = None url: Annotated[AnyUrl, Field(description="The authorized agent's API endpoint URL")]Base model for AdCP types with spec-compliant serialization.
Defaults to
extra='ignore'so that unknown fields from newer spec versions are silently dropped rather than causing validation errors. Generated types whose schemas setadditionalProperties: trueoverride this withextra='allow'in their ownmodel_config. Consumers who want strict validation can override withextra='forbid'.Create a new model by parsing and validating input data from keyword arguments.
Raises [
ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.selfis explicitly positional-only to allowselfas a field name.Ancestors
- AdCPBaseModel
- pydantic.main.BaseModel
Class variables
var collections : list[CollectionSelector] | Nonevar countries : list[Country] | Nonevar delegation_type : DelegationType | Nonevar effective_from : pydantic.types.AwareDatetime | Nonevar effective_until : pydantic.types.AwareDatetime | Nonevar exclusive : bool | Nonevar model_configvar placement_ids : list[str] | Nonevar publisher_properties : list[PublisherPropertySelector]var signing_keys : list[AgentSigningKey] | Nonevar url : pydantic.networks.AnyUrl
Inherited members
class AuthorizedAgentsBySignalId (**data: Any)-
Expand source code
class AuthorizedAgents4(AdCPBaseModel): model_config = ConfigDict( extra='allow', ) authorization_type: Annotated[ Literal['signal_ids'], Field(description='Discriminator indicating authorization by specific signal IDs'), ] authorized_for: Annotated[ str, Field( description='Human-readable description of what signals this agent is authorized to resell', max_length=500, min_length=1, ), ] signal_ids: Annotated[ list[SignalId], Field( description='Signal IDs this agent is authorized to resell. Resolved against the top-level signals array in this file', min_length=1, ), ] signing_keys: Annotated[ list[agent_signing_key.AgentSigningKey] | None, Field( description='Optional publisher-attested public signing keys for this agent. Use these as the trust anchor for verifying signed agent responses instead of relying on key discovery from the agent domain alone.', min_length=1, ), ] = None url: Annotated[AnyUrl, Field(description="The authorized signals agent's API endpoint URL")]Base model for AdCP types with spec-compliant serialization.
Defaults to
extra='ignore'so that unknown fields from newer spec versions are silently dropped rather than causing validation errors. Generated types whose schemas setadditionalProperties: trueoverride this withextra='allow'in their ownmodel_config. Consumers who want strict validation can override withextra='forbid'.Create a new model by parsing and validating input data from keyword arguments.
Raises [
ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.selfis explicitly positional-only to allowselfas a field name.Ancestors
- AdCPBaseModel
- pydantic.main.BaseModel
Class variables
var model_configvar signal_ids : list[SignalId]var signing_keys : list[AgentSigningKey] | Nonevar url : pydantic.networks.AnyUrl
Inherited members
class AuthorizedAgentsBySignalTag (**data: Any)-
Expand source code
class AuthorizedAgents5(AdCPBaseModel): model_config = ConfigDict( extra='allow', ) authorization_type: Annotated[ Literal['signal_tags'], Field(description='Discriminator indicating authorization by signal tags'), ] authorized_for: Annotated[ str, Field( description='Human-readable description of what signals this agent is authorized to resell', max_length=500, min_length=1, ), ] signal_tags: Annotated[ list[SignalTag], Field( description='Signal tags this agent is authorized for. Agent can resell all signals with these tags', min_length=1, ), ] signing_keys: Annotated[ list[agent_signing_key.AgentSigningKey] | None, Field( description='Optional publisher-attested public signing keys for this agent. Use these as the trust anchor for verifying signed agent responses instead of relying on key discovery from the agent domain alone.', min_length=1, ), ] = None url: Annotated[AnyUrl, Field(description="The authorized signals agent's API endpoint URL")]Base model for AdCP types with spec-compliant serialization.
Defaults to
extra='ignore'so that unknown fields from newer spec versions are silently dropped rather than causing validation errors. Generated types whose schemas setadditionalProperties: trueoverride this withextra='allow'in their ownmodel_config. Consumers who want strict validation can override withextra='forbid'.Create a new model by parsing and validating input data from keyword arguments.
Raises [
ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.selfis explicitly positional-only to allowselfas a field name.Ancestors
- AdCPBaseModel
- pydantic.main.BaseModel
Class variables
var model_configvar signing_keys : list[AgentSigningKey] | Nonevar url : pydantic.networks.AnyUrl
Inherited members
class BrandActivity (**data: Any)-
Expand source code
class BrandActivity(RegistryBaseModel): domain: Annotated[str, Field(examples=["acmecorp.com"])] total: Annotated[int, Field(examples=[3])] revisions: list[ActivityRevision]Base model for registry API types.
Uses
extra='allow'so that new fields from the registry API are preserved rather than dropped. This differs from AdCPBaseModel which defaults toextra='ignore'for protocol types.Create a new model by parsing and validating input data from keyword arguments.
Raises [
ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.selfis explicitly positional-only to allowselfas a field name.Ancestors
- RegistryBaseModel
- pydantic.main.BaseModel
Class variables
var domain : strvar model_configvar revisions : list[ActivityRevision]var total : int
class BrandReference (**data: Any)-
Expand source code
class BrandReference(AdCPBaseModel): model_config = ConfigDict( extra='forbid', ) brand_id: Annotated[ brand_id_1.BrandId | None, Field( description='Brand identifier within the house portfolio. Optional for single-brand domains.' ), ] = None domain: Annotated[ str, Field( description="Domain where /.well-known/brand.json is hosted, or the brand's operating domain", pattern='^[a-z0-9]([a-z0-9-]*[a-z0-9])?(\\.[a-z0-9]([a-z0-9-]*[a-z0-9])?)*$', ), ]Base model for AdCP types with spec-compliant serialization.
Defaults to
extra='ignore'so that unknown fields from newer spec versions are silently dropped rather than causing validation errors. Generated types whose schemas setadditionalProperties: trueoverride this withextra='allow'in their ownmodel_config. Consumers who want strict validation can override withextra='forbid'.Create a new model by parsing and validating input data from keyword arguments.
Raises [
ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.selfis explicitly positional-only to allowselfas a field name.Ancestors
- AdCPBaseModel
- pydantic.main.BaseModel
Class variables
var brand_id : BrandId | Nonevar domain : strvar model_config
Inherited members
class BrandRegistryItem (**data: Any)-
Expand source code
class BrandRegistryItem(RegistryBaseModel): domain: Annotated[str, Field(examples=["acmecorp.com"])] brand_name: Annotated[str | None, Field(examples=["Acme Corp"])] = None source: BrandRegistrySource has_manifest: bool verified: bool house_domain: str | None = None keller_type: KellerType | None = NoneBase model for registry API types.
Uses
extra='allow'so that new fields from the registry API are preserved rather than dropped. This differs from AdCPBaseModel which defaults toextra='ignore'for protocol types.Create a new model by parsing and validating input data from keyword arguments.
Raises [
ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.selfis explicitly positional-only to allowselfas a field name.Ancestors
- RegistryBaseModel
- pydantic.main.BaseModel
Class variables
var brand_name : str | Nonevar domain : strvar has_manifest : boolvar house_domain : str | Nonevar keller_type : KellerType | Nonevar model_configvar source : BrandRegistrySourcevar verified : bool
class BuildCreativeRequest (**data: Any)-
Expand source code
class BuildCreativeRequest(AdCPBaseModel): model_config = ConfigDict( extra='allow', ) brand: Annotated[ brand_ref.BrandReference | None, Field( description='Brand reference for creative generation. Resolved to full brand identity (colors, logos, tone) at execution time.' ), ] = None concept_id: Annotated[ str | None, Field( description='Creative concept containing the creative. Creative agents SHOULD assign globally unique creative_id values; when they cannot guarantee uniqueness, concept_id is REQUIRED to disambiguate.' ), ] = None context: context_1.ContextObject | None = None creative_id: Annotated[ str | None, Field( description="Reference to a creative in the agent's library. The creative agent resolves this to a manifest from its library. Use this instead of creative_manifest when retrieving an existing creative for tag generation or format adaptation." ), ] = None creative_manifest: Annotated[ creative_manifest_1.CreativeManifest | None, Field( description='Creative manifest to transform or generate from. For pure generation, this should include the target format_id and any required input assets. For transformation (e.g., resizing, reformatting), this is the complete creative to adapt. When creative_id is provided, the agent resolves the creative from its library and this field is ignored.' ), ] = None ext: ext_1.ExtensionObject | None = None idempotency_key: Annotated[ str | None, Field( description='Client-generated unique key for this request. Prevents duplicate creative generation on retries. MUST be unique per (seller, request) pair to prevent cross-seller correlation. Use a fresh UUID v4 for each request.', max_length=255, min_length=16, ), ] = None include_preview: Annotated[ bool | None, Field( description="When true, requests the creative agent to include preview renders in the response alongside the manifest. Agents that support this return a 'preview' object in the response using the same structure as preview_creative. Agents that do not support inline preview simply omit the field. This avoids a separate preview_creative round trip for platforms that generate previews as a byproduct of building." ), ] = None item_limit: Annotated[ int | None, Field( description="Maximum number of catalog items to use when generating. When a catalog asset contains more items than this limit, the creative agent selects the top items based on relevance or catalog ordering. When item_limit exceeds the format's max_items, the creative agent SHOULD use the lesser of the two. Ignored when the manifest contains no catalog assets.", ge=1, ), ] = None macro_values: Annotated[ dict[str, str] | None, Field( description="Macro values to pre-substitute into the output manifest's assets. Keys are universal macro names (e.g., CLICK_URL, CACHEBUSTER); values are the substitution strings. The creative agent translates universal macros to its platform's native syntax. Substitution is literal — all occurrences of each macro in output assets are replaced with the provided value. The caller is responsible for URL-encoding values if the output context requires it. Macros not provided here remain as {MACRO} placeholders for the sales agent to resolve at serve time. Creative agents MUST ignore keys they do not recognize — unknown macro names are not an error." ), ] = None media_buy_id: Annotated[ str | None, Field( description='Media buy identifier for tag generation context. When the creative agent is also the ad server, this provides the trafficking context needed to generate placement-specific tags (e.g., CM360 placement ID). Not needed when tags are generated at the creative level (most creative platforms).' ), ] = None message: Annotated[ str | None, Field( description='Natural language instructions for the transformation or generation. For pure generation, this is the creative brief. For transformation, this provides guidance on how to adapt the creative. For refinement, this describes the desired changes.' ), ] = None package_id: Annotated[ str | None, Field( description='Package identifier within the media buy. Used with media_buy_id when the creative agent needs line-item-level context for tag generation. Omit to get a tag not scoped to a specific package.' ), ] = None preview_inputs: Annotated[ list[PreviewInput] | None, Field( description='Input sets for preview generation when include_preview is true. Each input set defines macros and context values for one preview variant. If include_preview is true but this is omitted, the agent generates a single default preview. Only supported with target_format_id (single-format requests). Ignored when using target_format_ids — multi-format requests generate one default preview per format. Ignored when include_preview is false or omitted.', min_length=1, ), ] = None preview_output_format: Annotated[ preview_output_format_1.PreviewOutputFormat | None, Field( description="Output format for preview renders when include_preview is true. 'url' returns preview_url (iframe-embeddable URL), 'html' returns preview_html (raw HTML). Ignored when include_preview is false or omitted." ), ] = preview_output_format_1.PreviewOutputFormat.url preview_quality: Annotated[ creative_quality.CreativeQuality | None, Field( description="Render quality for inline preview when include_preview is true. 'draft' produces fast, lower-fidelity renderings. 'production' produces full-quality renderings. Independent of the build quality parameter — you can build at draft quality and preview at production quality, or vice versa. If omitted, the creative agent uses its own default. Ignored when include_preview is false or omitted." ), ] = None quality: Annotated[ creative_quality.CreativeQuality | None, Field( description="Quality tier for generation. 'draft' produces fast, lower-fidelity output for iteration and review. 'production' produces full-quality output for final delivery. If omitted, the creative agent uses its own default. For non-generative transforms (e.g., format resizing), creative agents MAY ignore this field." ), ] = None target_format_id: Annotated[ format_id.FormatId | None, Field( description='Single format ID to generate. Mutually exclusive with target_format_ids. The format definition specifies required input assets and output structure.' ), ] = None target_format_ids: Annotated[ list[format_id.FormatId] | None, Field( description='Array of format IDs to generate in a single call. Mutually exclusive with target_format_id. The creative agent produces one manifest per format. Each format definition specifies its own required input assets and output structure.', min_length=1, ), ] = NoneBase model for AdCP types with spec-compliant serialization.
Defaults to
extra='ignore'so that unknown fields from newer spec versions are silently dropped rather than causing validation errors. Generated types whose schemas setadditionalProperties: trueoverride this withextra='allow'in their ownmodel_config. Consumers who want strict validation can override withextra='forbid'.Create a new model by parsing and validating input data from keyword arguments.
Raises [
ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.selfis explicitly positional-only to allowselfas a field name.Ancestors
- AdCPBaseModel
- pydantic.main.BaseModel
Class variables
var brand : BrandReference | Nonevar concept_id : str | Nonevar context : ContextObject | Nonevar creative_id : str | Nonevar creative_manifest : CreativeManifest | Nonevar ext : ExtensionObject | Nonevar idempotency_key : str | Nonevar include_preview : bool | Nonevar item_limit : int | Nonevar macro_values : dict[str, str] | Nonevar media_buy_id : str | Nonevar message : str | Nonevar model_configvar package_id : str | Nonevar preview_inputs : list[PreviewInput] | Nonevar preview_output_format : PreviewOutputFormat | Nonevar preview_quality : CreativeQuality | Nonevar quality : CreativeQuality | Nonevar target_format_id : FormatId | Nonevar target_format_ids : list[FormatId] | None
Inherited members
class BuildCreativeSuccessResponse (**data: Any)-
Expand source code
class BuildCreativeResponse1(AdCPBaseModel): model_config = ConfigDict( extra='allow', ) context: context_1.ContextObject | None = None creative_manifest: Annotated[ creative_manifest_1.CreativeManifest, Field(description='The generated or transformed creative manifest'), ] expires_at: Annotated[ AwareDatetime | None, Field( description='ISO 8601 timestamp when generated asset URLs in the manifest expire. Set to the earliest expiration across all generated assets. Re-build the creative after this time to get fresh URLs.' ), ] = None ext: ext_1.ExtensionObject | None = None preview: Annotated[ Preview | None, Field( description='Preview renders included when the request set include_preview to true and the agent supports it. Contains the same content fields as a preview_creative single response (previews, interactive_url, expires_at) minus the response_type discriminator, so clients can reuse the same preview rendering logic.' ), ] = None preview_error: Annotated[ error.Error | None, Field( description="When include_preview was true in the request but preview generation failed. Uses the standard error structure with code, message, and recovery classification. Distinguishes 'agent does not support inline preview' (preview and preview_error both absent) from 'preview generation failed' (preview absent, preview_error present). Omitted when preview succeeded or was not requested." ), ] = None sandbox: Annotated[ bool | None, Field(description='When true, this response contains simulated data from sandbox mode.'), ] = NoneBase model for AdCP types with spec-compliant serialization.
Defaults to
extra='ignore'so that unknown fields from newer spec versions are silently dropped rather than causing validation errors. Generated types whose schemas setadditionalProperties: trueoverride this withextra='allow'in their ownmodel_config. Consumers who want strict validation can override withextra='forbid'.Create a new model by parsing and validating input data from keyword arguments.
Raises [
ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.selfis explicitly positional-only to allowselfas a field name.Ancestors
- AdCPBaseModel
- pydantic.main.BaseModel
Class variables
var context : ContextObject | Nonevar creative_manifest : CreativeManifestvar expires_at : pydantic.types.AwareDatetime | Nonevar ext : ExtensionObject | Nonevar model_configvar preview : Preview | Nonevar preview_error : Error | Nonevar sandbox : bool | None
Inherited members
class BuildCreativeErrorResponse (**data: Any)-
Expand source code
class BuildCreativeResponse2(AdCPBaseModel): model_config = ConfigDict( extra='allow', ) context: context_1.ContextObject | None = None creative_manifests: Annotated[ list[creative_manifest_1.CreativeManifest], Field( description='Array of generated creative manifests, one per requested format. Each manifest contains its own format_id identifying which format it was generated for.', min_length=1, ), ] expires_at: Annotated[ AwareDatetime | None, Field( description='ISO 8601 timestamp when the earliest generated asset URL expires across all manifests. Re-build after this time to get fresh URLs.' ), ] = None ext: ext_1.ExtensionObject | None = None preview: Annotated[ Preview2 | None, Field( description='Preview renders included when the request set include_preview to true and the agent supports it. Contains one default preview per requested format. preview_inputs is ignored for multi-format requests.' ), ] = None preview_error: Annotated[ error.Error | None, Field( description='When include_preview was true in the request but preview generation failed. Uses the standard error structure with code, message, and recovery classification. Omitted when preview succeeded or was not requested.' ), ] = None sandbox: Annotated[ bool | None, Field(description='When true, this response contains simulated data from sandbox mode.'), ] = NoneBase model for AdCP types with spec-compliant serialization.
Defaults to
extra='ignore'so that unknown fields from newer spec versions are silently dropped rather than causing validation errors. Generated types whose schemas setadditionalProperties: trueoverride this withextra='allow'in their ownmodel_config. Consumers who want strict validation can override withextra='forbid'.Create a new model by parsing and validating input data from keyword arguments.
Raises [
ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.selfis explicitly positional-only to allowselfas a field name.Ancestors
- AdCPBaseModel
- pydantic.main.BaseModel
Class variables
var context : ContextObject | Nonevar creative_manifests : list[CreativeManifest]var expires_at : pydantic.types.AwareDatetime | Nonevar ext : ExtensionObject | Nonevar model_configvar preview : Preview2 | Nonevar preview_error : Error | Nonevar sandbox : bool | None
Inherited members
class BuyingMode (*args, **kwds)-
Expand source code
class BuyingMode(Enum): brief = 'brief' wholesale = 'wholesale' refine = 'refine'Create a collection of name/value pairs.
Example enumeration:
>>> class Color(Enum): ... RED = 1 ... BLUE = 2 ... GREEN = 3Access them by:
- attribute access::
>>> Color.RED <Color.RED: 1>- value lookup:
>>> Color(1) <Color.RED: 1>- name lookup:
>>> Color['RED'] <Color.RED: 1>Enumerations can be iterated over, and know how many members they have:
>>> len(Color) 3>>> list(Color) [<Color.RED: 1>, <Color.BLUE: 2>, <Color.GREEN: 3>]Methods can be added to enumerations, and members can have their own attributes – see the documentation for details.
Ancestors
- enum.Enum
Class variables
var briefvar refinevar wholesale
class CalibrateContentSuccessResponse (**data: Any)-
Expand source code
class CalibrateContentResponse1(AdCPBaseModel): confidence: Annotated[ float | None, Field(description='Model confidence in the verdict (0-1)', ge=0.0, le=1.0) ] = None context: context_1.ContextObject | None = None explanation: Annotated[ str | None, Field(description='Detailed natural language explanation of the decision') ] = None ext: ext_1.ExtensionObject | None = None features: Annotated[ list[Feature] | None, Field(description='Per-feature breakdown with explanations') ] = None verdict: Annotated[ Verdict, Field(description='Overall pass/fail verdict for the content evaluation') ]Base model for AdCP types with spec-compliant serialization.
Defaults to
extra='ignore'so that unknown fields from newer spec versions are silently dropped rather than causing validation errors. Generated types whose schemas setadditionalProperties: trueoverride this withextra='allow'in their ownmodel_config. Consumers who want strict validation can override withextra='forbid'.Create a new model by parsing and validating input data from keyword arguments.
Raises [
ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.selfis explicitly positional-only to allowselfas a field name.Ancestors
- AdCPBaseModel
- pydantic.main.BaseModel
Class variables
var confidence : float | Nonevar context : ContextObject | Nonevar explanation : str | Nonevar ext : ExtensionObject | Nonevar features : list[Feature] | Nonevar model_configvar verdict : Verdict
Inherited members
class CalibrateContentErrorResponse (**data: Any)-
Expand source code
class CalibrateContentResponse2(AdCPBaseModel): context: context_1.ContextObject | None = None errors: list[error.Error] ext: ext_1.ExtensionObject | None = NoneBase model for AdCP types with spec-compliant serialization.
Defaults to
extra='ignore'so that unknown fields from newer spec versions are silently dropped rather than causing validation errors. Generated types whose schemas setadditionalProperties: trueoverride this withextra='allow'in their ownmodel_config. Consumers who want strict validation can override withextra='forbid'.Create a new model by parsing and validating input data from keyword arguments.
Raises [
ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.selfis explicitly positional-only to allowselfas a field name.Ancestors
- AdCPBaseModel
- pydantic.main.BaseModel
Class variables
var context : ContextObject | Nonevar errors : list[Error]var ext : ExtensionObject | Nonevar model_config
Inherited members
class Catalog (**data: Any)-
Expand source code
class Catalog(AdCPBaseModel): model_config = ConfigDict( extra='allow', ) catalog_id: Annotated[ str | None, Field( description="Buyer's identifier for this catalog. Required when syncing via sync_catalogs. When used in creatives, references a previously synced catalog on the account." ), ] = None category: Annotated[ str | None, Field( description="Filter catalog to items in this category (e.g., 'beverages/soft-drinks', 'chef-positions')." ), ] = None content_id_type: Annotated[ content_id_type_1.ContentIdType | None, Field( description="Identifier type that the event's content_ids field should be matched against for items in this catalog. For example, 'gtin' means content_ids values are Global Trade Item Numbers, 'sku' means retailer SKUs. Omit when using a custom identifier scheme not listed in the enum." ), ] = None conversion_events: Annotated[ list[event_type.EventType] | None, Field( description="Event types that represent conversions for items in this catalog. Declares what events the platform should attribute to catalog items — e.g., a job catalog converts via submit_application, a product catalog via purchase. The event's content_ids field carries the item IDs that connect back to catalog items. Use content_id_type to declare what identifier type content_ids values represent.", min_length=1, ), ] = None feed_field_mappings: Annotated[ list[catalog_field_mapping.CatalogFieldMapping] | None, Field( description='Declarative normalization rules for external feeds. Maps non-standard feed field names, date formats, price encodings, and image URLs to the AdCP catalog item schema. Applied during sync_catalogs ingestion. Supports field renames, named transforms (date, divide, boolean, split), static literal injection, and assignment of image URLs to typed asset pools.', min_length=1, ), ] = None feed_format: Annotated[ feed_format_1.FeedFormat | None, Field( description='Format of the external feed at url. Required when url points to a non-AdCP feed (e.g., Google Merchant Center XML, Meta Product Catalog). Omit for offering-type catalogs where the feed is native AdCP JSON.' ), ] = None gtins: Annotated[ list[Gtin] | None, Field( description="Filter product-type catalogs by GTIN identifiers for cross-retailer catalog matching. Accepts standard GTIN formats (GTIN-8, UPC-A/GTIN-12, EAN-13/GTIN-13, GTIN-14). Only applicable when type is 'product'.", min_length=1, ), ] = None ids: Annotated[ list[str] | None, Field( description='Filter catalog to specific item IDs. For offering-type catalogs, these are offering_id values. For product-type catalogs, these are SKU identifiers.', min_length=1, ), ] = None items: Annotated[ list[dict[str, Any]] | None, Field( description="Inline catalog data. The item schema depends on the catalog type: Offering objects for 'offering', StoreItem for 'store', HotelItem for 'hotel', FlightItem for 'flight', JobItem for 'job', VehicleItem for 'vehicle', RealEstateItem for 'real_estate', EducationItem for 'education', DestinationItem for 'destination', AppItem for 'app', or freeform objects for 'product', 'inventory', and 'promotion'. Mutually exclusive with url — provide one or the other, not both. Implementations should validate items against the type-specific schema.", min_length=1, ), ] = None name: Annotated[ str | None, Field( description="Human-readable name for this catalog (e.g., 'Summer Products 2025', 'Amsterdam Store Locations')." ), ] = None query: Annotated[ str | None, Field( description="Natural language filter for catalog items (e.g., 'all pasta sauces under $5', 'amsterdam vacancies')." ), ] = None tags: Annotated[ list[str] | None, Field( description='Filter catalog to items with these tags. Tags are matched using OR logic — items matching any tag are included.', min_length=1, ), ] = None type: Annotated[ catalog_type.CatalogType, Field( description="Catalog type. Structural types: 'offering' (AdCP Offering objects), 'product' (ecommerce entries), 'inventory' (stock per location), 'store' (physical locations), 'promotion' (deals and pricing). Vertical types: 'hotel', 'flight', 'job', 'vehicle', 'real_estate', 'education', 'destination', 'app' — each with an industry-specific item schema." ), ] update_frequency: Annotated[ update_frequency_1.UpdateFrequency | None, Field( description='How often the platform should re-fetch the feed from url. Only applicable when url is provided. Platforms may use this as a hint for polling schedules.' ), ] = None url: Annotated[ AnyUrl | None, Field( description="URL to an external catalog feed. The platform fetches and resolves items from this URL. For offering-type catalogs, the feed contains an array of Offering objects. For other types, the feed format is determined by feed_format. When omitted with type 'product', the platform uses its synced copy of the brand's product catalog." ), ] = NoneBase model for AdCP types with spec-compliant serialization.
Defaults to
extra='ignore'so that unknown fields from newer spec versions are silently dropped rather than causing validation errors. Generated types whose schemas setadditionalProperties: trueoverride this withextra='allow'in their ownmodel_config. Consumers who want strict validation can override withextra='forbid'.Create a new model by parsing and validating input data from keyword arguments.
Raises [
ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.selfis explicitly positional-only to allowselfas a field name.Ancestors
- AdCPBaseModel
- pydantic.main.BaseModel
Subclasses
Class variables
var catalog_id : str | Nonevar category : str | Nonevar content_id_type : ContentIdType | Nonevar conversion_events : list[EventType] | Nonevar feed_field_mappings : list[CatalogFieldMapping] | Nonevar feed_format : FeedFormat | Nonevar gtins : list[Gtin] | Nonevar ids : list[str] | Nonevar items : list[dict[str, typing.Any]] | Nonevar model_configvar name : str | Nonevar query : str | Nonevar type : CatalogTypevar update_frequency : UpdateFrequency | Nonevar url : pydantic.networks.AnyUrl | None
class SyncCatalogResult (**data: Any)-
Expand source code
class Catalog(AdCPBaseModel): model_config = ConfigDict( extra='allow', ) action: Annotated[ catalog_action.CatalogAction, Field(description='Action taken for this catalog') ] catalog_id: Annotated[str, Field(description='Catalog ID from the request')] changes: Annotated[ list[str] | None, Field(description="Field names that were modified (only present when action='updated')"), ] = None errors: Annotated[ list[str] | None, Field(description="Validation or processing errors (only present when action='failed')"), ] = None item_count: Annotated[ int | None, Field(description='Total number of items in the catalog after sync', ge=0) ] = None item_issues: Annotated[ list[ItemIssue] | None, Field( description='Per-item issues reported by the platform (rejections, warnings). Only present when the platform performs item-level review.' ), ] = None items_approved: Annotated[ int | None, Field( description='Number of items approved by the platform. Populated when the platform performs item-level review.', ge=0, ), ] = None items_pending: Annotated[ int | None, Field( description='Number of items pending platform review. Common for product catalogs where items must pass content policy checks.', ge=0, ), ] = None items_rejected: Annotated[ int | None, Field( description='Number of items rejected by the platform. Check item_issues for rejection reasons.', ge=0, ), ] = None last_synced_at: Annotated[ AwareDatetime | None, Field( description='ISO 8601 timestamp of when the most recent sync was accepted by the platform' ), ] = None next_fetch_at: Annotated[ AwareDatetime | None, Field( description='ISO 8601 timestamp of when the platform will next fetch the feed URL. Only present for URL-based catalogs with update_frequency.' ), ] = None platform_id: Annotated[ str | None, Field(description='Platform-specific ID assigned to the catalog') ] = None warnings: Annotated[ list[str] | None, Field(description='Non-fatal warnings about this catalog') ] = NoneBase model for AdCP types with spec-compliant serialization.
Defaults to
extra='ignore'so that unknown fields from newer spec versions are silently dropped rather than causing validation errors. Generated types whose schemas setadditionalProperties: trueoverride this withextra='allow'in their ownmodel_config. Consumers who want strict validation can override withextra='forbid'.Create a new model by parsing and validating input data from keyword arguments.
Raises [
ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.selfis explicitly positional-only to allowselfas a field name.Ancestors
- AdCPBaseModel
- pydantic.main.BaseModel
Class variables
var action : CatalogActionvar catalog_id : strvar changes : list[str] | Nonevar errors : list[str] | Nonevar item_count : int | Nonevar item_issues : list[ItemIssue] | Nonevar items_approved : int | Nonevar items_pending : int | Nonevar items_rejected : int | Nonevar last_synced_at : pydantic.types.AwareDatetime | Nonevar model_configvar next_fetch_at : pydantic.types.AwareDatetime | Nonevar platform_id : str | Nonevar warnings : list[str] | None
Inherited members
class CatalogAction (*args, **kwds)-
Expand source code
class CatalogAction(Enum): created = 'created' updated = 'updated' unchanged = 'unchanged' failed = 'failed' deleted = 'deleted'Create a collection of name/value pairs.
Example enumeration:
>>> class Color(Enum): ... RED = 1 ... BLUE = 2 ... GREEN = 3Access them by:
- attribute access::
>>> Color.RED <Color.RED: 1>- value lookup:
>>> Color(1) <Color.RED: 1>- name lookup:
>>> Color['RED'] <Color.RED: 1>Enumerations can be iterated over, and know how many members they have:
>>> len(Color) 3>>> list(Color) [<Color.RED: 1>, <Color.BLUE: 2>, <Color.GREEN: 3>]Methods can be added to enumerations, and members can have their own attributes – see the documentation for details.
Ancestors
- enum.Enum
Class variables
var createdvar deletedvar failedvar unchangedvar updated
class CatalogFieldBinding (root: RootModelRootType = PydanticUndefined, **data)-
Expand source code
class CatalogFieldBinding(RootModel[ScalarBinding | AssetPoolBinding | CatalogFieldBinding1]): root: Annotated[ ScalarBinding | AssetPoolBinding | CatalogFieldBinding1, Field( description="Maps a format template slot to a catalog item field or typed asset pool. The 'kind' field identifies the binding variant. All bindings are optional — agents can still infer mappings without them.", examples=[ { 'data': {'asset_id': 'headline', 'catalog_field': 'name', 'kind': 'scalar'}, 'description': 'Scalar binding — hotel name to headline slot', }, { 'data': { 'asset_id': 'price_badge', 'catalog_field': 'price.amount', 'kind': 'scalar', }, 'description': 'Scalar binding — nested field (nightly rate)', }, { 'data': { 'asset_group_id': 'images_landscape', 'asset_id': 'hero_image', 'kind': 'asset_pool', }, 'description': 'Asset pool binding — hero image from landscape pool', }, { 'data': { 'asset_group_id': 'images_vertical', 'asset_id': 'snap_background', 'kind': 'asset_pool', }, 'description': 'Asset pool binding — Snap vertical background from vertical pool', }, { 'data': { 'catalog_item': True, 'format_group_id': 'slide', 'kind': 'catalog_group', 'per_item_bindings': [ {'asset_id': 'title', 'catalog_field': 'name', 'kind': 'scalar'}, { 'asset_id': 'price', 'catalog_field': 'price.amount', 'kind': 'scalar', }, { 'asset_group_id': 'images_landscape', 'asset_id': 'image', 'kind': 'asset_pool', }, ], }, 'description': 'Catalog group binding — carousel where each slide is one hotel', }, ], title='Catalog Field Binding', ), ] def __getattr__(self, name: str) -> Any: """Proxy attribute access to the wrapped type.""" if name.startswith('_'): raise AttributeError(name) return getattr(self.root, name)Usage Documentation
A Pydantic
BaseModelfor the root object of the model.Attributes
root- The root object of the model.
__pydantic_root_model__- Whether the model is a RootModel.
__pydantic_private__- Private fields in the model.
__pydantic_extra__- Extra fields in the model.
Create a new model by parsing and validating input data from keyword arguments.
Raises [
ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.selfis explicitly positional-only to allowselfas a field name.Ancestors
- pydantic.root_model.RootModel[Union[ScalarBinding, AssetPoolBinding, CatalogFieldBinding1]]
- pydantic.root_model.RootModel
- pydantic.main.BaseModel
- typing.Generic
Class variables
var model_configvar root : ScalarBinding | AssetPoolBinding | CatalogFieldBinding1
class CatalogGroupBinding (**data: Any)-
Expand source code
class CatalogFieldBinding1(AdCPBaseModel): model_config = ConfigDict( extra='allow', ) catalog_item: Annotated[ Literal[True], Field( description="Each repetition of the format's repeatable_group maps to one item from the catalog." ), ] ext: ext_1.ExtensionObject | None = None format_group_id: Annotated[ str, Field(description="The asset_group_id of a repeatable_group in the format's assets array."), ] kind: Literal['catalog_group'] per_item_bindings: Annotated[ list[ScalarBinding | AssetPoolBinding] | None, Field( description='Scalar and asset pool bindings that apply within each repetition of the group. Nested catalog_group bindings are not permitted.', min_length=1, ), ] = NoneBase model for AdCP types with spec-compliant serialization.
Defaults to
extra='ignore'so that unknown fields from newer spec versions are silently dropped rather than causing validation errors. Generated types whose schemas setadditionalProperties: trueoverride this withextra='allow'in their ownmodel_config. Consumers who want strict validation can override withextra='forbid'.Create a new model by parsing and validating input data from keyword arguments.
Raises [
ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.selfis explicitly positional-only to allowselfas a field name.Ancestors
- AdCPBaseModel
- pydantic.main.BaseModel
Class variables
var catalog_item : Literal[True]var ext : ExtensionObject | Nonevar format_group_id : strvar kind : Literal['catalog_group']var model_configvar per_item_bindings : list[ScalarBinding | AssetPoolBinding] | None
Inherited members
class CatalogFieldMapping (**data: Any)-
Expand source code
class CatalogFieldMapping(AdCPBaseModel): model_config = ConfigDict( extra='allow', ) asset_group_id: Annotated[ str | None, Field( description="Places the feed field value (a URL) into a typed asset pool on the catalog item's assets array. The value is wrapped as an image or video asset in a group with this ID. Use standard group IDs: 'images_landscape', 'images_vertical', 'images_square', 'logo', 'video'. Mutually exclusive with catalog_field." ), ] = None by: Annotated[ float | None, Field( description="For transform 'divide': the divisor to apply (e.g., 100 to convert integer cents to decimal dollars).", gt=0.0, ), ] = None catalog_field: Annotated[ str | None, Field( description="Target field on the catalog item schema, using dot notation for nested fields (e.g., 'name', 'price.amount', 'location.city'). Mutually exclusive with asset_group_id." ), ] = None default: Annotated[ Any | None, Field( description='Fallback value to use when feed_field is absent, null, or empty. Applied after any transform would have been applied. Allows optional feed fields to have a guaranteed baseline value.' ), ] = None ext: ext_1.ExtensionObject | None = None feed_field: Annotated[ str | None, Field( description='Field name in the external feed record. Omit when injecting a static literal value (use the value property instead).' ), ] = None format: Annotated[ str | None, Field( description="For transform 'date': the input date format string (e.g., 'YYYYMMDD', 'MM/DD/YYYY', 'DD-MM-YYYY'). Output is always ISO 8601 (e.g., '2025-03-01'). Uses Unicode date pattern tokens." ), ] = None separator: Annotated[ str | None, Field( description="For transform 'split': the separator character or string to split on. Defaults to ','." ), ] = ',' timezone: Annotated[ str | None, Field( description="For transform 'date': the timezone of the input value. IANA timezone identifier (e.g., 'UTC', 'America/New_York', 'Europe/Amsterdam'). Defaults to UTC when omitted." ), ] = None transform: Annotated[ Transform | None, Field( description='Named transform to apply to the feed field value before writing to the catalog schema. See transform-specific parameters (format, timezone, by, separator).' ), ] = None value: Annotated[ Any | None, Field( description='Static literal value to inject into catalog_field for every item, regardless of what the feed contains. Mutually exclusive with feed_field. Useful for fields the feed omits (e.g., currency when price is always USD, or a constant category value).' ), ] = NoneBase model for AdCP types with spec-compliant serialization.
Defaults to
extra='ignore'so that unknown fields from newer spec versions are silently dropped rather than causing validation errors. Generated types whose schemas setadditionalProperties: trueoverride this withextra='allow'in their ownmodel_config. Consumers who want strict validation can override withextra='forbid'.Create a new model by parsing and validating input data from keyword arguments.
Raises [
ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.selfis explicitly positional-only to allowselfas a field name.Ancestors
- AdCPBaseModel
- pydantic.main.BaseModel
Class variables
var asset_group_id : str | Nonevar by : float | Nonevar catalog_field : str | Nonevar default : typing.Any | Nonevar ext : ExtensionObject | Nonevar feed_field : str | Nonevar format : str | Nonevar model_configvar separator : str | Nonevar timezone : str | Nonevar transform : Transform | Nonevar value : typing.Any | None
Inherited members
class CatalogItemStatus (*args, **kwds)-
Expand source code
class CatalogItemStatus(Enum): approved = 'approved' pending = 'pending' rejected = 'rejected' warning = 'warning'Create a collection of name/value pairs.
Example enumeration:
>>> class Color(Enum): ... RED = 1 ... BLUE = 2 ... GREEN = 3Access them by:
- attribute access::
>>> Color.RED <Color.RED: 1>- value lookup:
>>> Color(1) <Color.RED: 1>- name lookup:
>>> Color['RED'] <Color.RED: 1>Enumerations can be iterated over, and know how many members they have:
>>> len(Color) 3>>> list(Color) [<Color.RED: 1>, <Color.BLUE: 2>, <Color.GREEN: 3>]Methods can be added to enumerations, and members can have their own attributes – see the documentation for details.
Ancestors
- enum.Enum
Class variables
var approvedvar pendingvar rejectedvar warning
class CatalogRequirements (**data: Any)-
Expand source code
class CatalogRequirements(AdCPBaseModel): model_config = ConfigDict( extra='allow', ) catalog_type: Annotated[ catalog_type_1.CatalogType, Field(description='The catalog type this requirement applies to'), ] feed_formats: Annotated[ list[feed_format.FeedFormat] | None, Field( description='Accepted feed formats for this catalog type. When specified, the synced catalog must use one of these formats. When omitted, any format is accepted.', min_length=1, ), ] = None field_bindings: Annotated[ list[catalog_field_binding.CatalogFieldBinding] | None, Field( description='Explicit mappings from format template slots to catalog item fields or typed asset pools. Optional — creative agents can infer mappings without them, but bindings make the relationship self-describing and enable validation. Covers scalar fields (asset_id → catalog_field), asset pools (asset_id → asset_group_id on the catalog item), and repeatable groups that iterate over catalog items.', min_length=1, ), ] = None max_items: Annotated[ int | None, Field( description='Maximum number of items the format can render. Items beyond this limit are ignored. Useful for fixed-slot layouts (e.g., a 3-product card) or feed-size constraints.', ge=1, ), ] = None min_items: Annotated[ int | None, Field( description='Minimum number of items the catalog must contain for this format to render properly (e.g., a carousel might require at least 3 products)', ge=1, ), ] = None offering_asset_constraints: Annotated[ list[offering_asset_constraint.OfferingAssetConstraint] | None, Field( description="Per-item creative asset requirements. Declares what asset groups (headlines, images, videos) each catalog item must provide in its assets array, along with count bounds and per-asset technical constraints. Applicable to 'offering' and all vertical catalog types (hotel, flight, job, etc.) whose items carry typed assets.", min_length=1, ), ] = None required: Annotated[ bool | None, Field( description='Whether this catalog type must be present. When true, creatives using this format must reference a synced catalog of this type.' ), ] = True required_fields: Annotated[ list[str] | None, Field( description="Fields that must be present and non-empty on every item in the catalog. Field names are catalog-type-specific (e.g., 'title', 'price', 'image_url' for product catalogs; 'store_id', 'quantity' for inventory feeds).", min_length=1, ), ] = NoneBase model for AdCP types with spec-compliant serialization.
Defaults to
extra='ignore'so that unknown fields from newer spec versions are silently dropped rather than causing validation errors. Generated types whose schemas setadditionalProperties: trueoverride this withextra='allow'in their ownmodel_config. Consumers who want strict validation can override withextra='forbid'.Create a new model by parsing and validating input data from keyword arguments.
Raises [
ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.selfis explicitly positional-only to allowselfas a field name.Ancestors
- AdCPBaseModel
- pydantic.main.BaseModel
Class variables
var catalog_type : CatalogTypevar feed_formats : list[FeedFormat] | Nonevar field_bindings : list[CatalogFieldBinding] | Nonevar max_items : int | Nonevar min_items : int | Nonevar model_configvar offering_asset_constraints : list[OfferingAssetConstraint] | Nonevar required : bool | Nonevar required_fields : list[str] | None
Inherited members
class CatalogType (*args, **kwds)-
Expand source code
class CatalogType(Enum): offering = 'offering' product = 'product' inventory = 'inventory' store = 'store' promotion = 'promotion' hotel = 'hotel' flight = 'flight' job = 'job' vehicle = 'vehicle' real_estate = 'real_estate' education = 'education' destination = 'destination' app = 'app'Create a collection of name/value pairs.
Example enumeration:
>>> class Color(Enum): ... RED = 1 ... BLUE = 2 ... GREEN = 3Access them by:
- attribute access::
>>> Color.RED <Color.RED: 1>- value lookup:
>>> Color(1) <Color.RED: 1>- name lookup:
>>> Color['RED'] <Color.RED: 1>Enumerations can be iterated over, and know how many members they have:
>>> len(Color) 3>>> list(Color) [<Color.RED: 1>, <Color.BLUE: 2>, <Color.GREEN: 3>]Methods can be added to enumerations, and members can have their own attributes – see the documentation for details.
Ancestors
- enum.Enum
Class variables
var appvar destinationvar educationvar flightvar hotelvar inventoryvar jobvar offeringvar productvar promotionvar real_estatevar storevar vehicle
class CheckGovernanceRequest (**data: Any)-
Expand source code
class CheckGovernanceRequest(AdCPBaseModel): model_config = ConfigDict( extra='forbid', ) caller: Annotated[AnyUrl, Field(description='URL of the agent making the request.')] delivery_metrics: Annotated[ DeliveryMetrics | None, Field( description="Actual delivery performance data. MUST be present for 'delivery' phase. The governance agent compares these metrics against the planned delivery to detect drift." ), ] = None governance_context: Annotated[ str | None, Field( description='Opaque governance context from a prior check_governance response. Pass this on subsequent checks for the same media buy so the governance agent can maintain continuity across the lifecycle. Issued by the governance agent, never interpreted by callers.', max_length=4096, min_length=1, pattern='^[\\x20-\\x7E]+$', ), ] = None invoice_recipient: Annotated[ business_entity.BusinessEntity | None, Field( description='Per-buy invoice recipient from create_media_buy or update_media_buy. MUST be present when the tool payload includes invoice_recipient, so the governance agent can validate billing changes.' ), ] = None media_buy_id: Annotated[ str | None, Field( description="The seller's identifier for the media buy. Present on execution checks (seller). The governance agent uses the presence of media_buy_id+planned_delivery to identify an execution check." ), ] = None modification_summary: Annotated[ str | None, Field( description="Human-readable summary of what changed. SHOULD be present for 'modification' phase.", max_length=1000, ), ] = None payload: Annotated[ dict[str, Any] | None, Field( description='The full tool arguments as they would be sent to the seller. Present on intent checks. The governance agent can inspect any field to validate against the plan.' ), ] = None phase: Annotated[ governance_phase.GovernancePhase | None, Field( description="The phase of the media buy lifecycle. 'purchase': initial create_media_buy. 'modification': update_media_buy. 'delivery': periodic delivery reporting. Defaults to 'purchase' if omitted." ), ] = governance_phase.GovernancePhase.purchase plan_id: Annotated[str, Field(description='Campaign governance plan identifier.')] planned_delivery: Annotated[ planned_delivery_1.PlannedDelivery | None, Field(description='What the seller will actually deliver. Present on execution checks.'), ] = None tool: Annotated[ str | None, Field( description="The AdCP tool being checked (e.g., 'create_media_buy', 'get_products'). Present on intent checks (orchestrator). The governance agent uses the presence of tool+payload to identify an intent check." ), ] = NoneBase model for AdCP types with spec-compliant serialization.
Defaults to
extra='ignore'so that unknown fields from newer spec versions are silently dropped rather than causing validation errors. Generated types whose schemas setadditionalProperties: trueoverride this withextra='allow'in their ownmodel_config. Consumers who want strict validation can override withextra='forbid'.Create a new model by parsing and validating input data from keyword arguments.
Raises [
ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.selfis explicitly positional-only to allowselfas a field name.Ancestors
- AdCPBaseModel
- pydantic.main.BaseModel
Class variables
var caller : pydantic.networks.AnyUrlvar delivery_metrics : DeliveryMetrics | Nonevar governance_context : str | Nonevar invoice_recipient : BusinessEntity | Nonevar media_buy_id : str | Nonevar model_configvar modification_summary : str | Nonevar payload : dict[str, typing.Any] | Nonevar phase : GovernancePhase | Nonevar plan_id : strvar planned_delivery : PlannedDelivery | Nonevar tool : str | None
Inherited members
class CheckGovernanceResponse (**data: Any)-
Expand source code
class CheckGovernanceResponse(AdCPBaseModel): model_config = ConfigDict( extra='forbid', ) categories_evaluated: Annotated[ list[str] | None, Field(description='Governance categories evaluated during this check.') ] = None check_id: Annotated[ str, Field( description='Unique identifier for this governance check record. Use in report_plan_outcome to link outcomes to the check that authorized them.' ), ] conditions: Annotated[ list[Condition] | None, Field( description="Present when status is 'conditions'. Specific adjustments the caller must make. After applying conditions, the caller MUST re-call check_governance with the adjusted parameters before proceeding." ), ] = None expires_at: Annotated[ AwareDatetime | None, Field( description="When this approval expires. Present when status is 'approved' or 'conditions'. The caller must act before this time or re-call check_governance. A lapsed approval is no approval." ), ] = None explanation: Annotated[ str, Field(description='Human-readable explanation of the governance decision.') ] findings: Annotated[ list[Finding] | None, Field( description="Specific issues found during the governance check. Present when status is 'denied' or 'conditions'. MAY also be present on 'approved' for informational findings (e.g., budget approaching limit)." ), ] = None governance_context: Annotated[ str | None, Field( description="Opaque governance context for this media buy. The buyer MUST attach this to the protocol envelope when sending the media buy to the seller. The seller MUST persist it and include it on all subsequent check_governance calls for this media buy's lifecycle. Only the issuing governance agent interprets this value.", max_length=4096, min_length=1, pattern='^[\\x20-\\x7E]+$', ), ] = None next_check: Annotated[ AwareDatetime | None, Field( description='When the seller should next call check_governance with delivery metrics. Present when the governance agent expects ongoing delivery reporting.' ), ] = None plan_id: Annotated[str, Field(description='Echoed from request.')] policies_evaluated: Annotated[ list[str] | None, Field(description='Registry policy IDs evaluated during this check.') ] = None status: Annotated[ Status, Field( description="Governance decision. 'approved': proceed as planned. 'denied': do not proceed. 'conditions': approved if the caller accepts the listed conditions, then re-calls check_governance with the adjusted parameters." ), ]Base model for AdCP types with spec-compliant serialization.
Defaults to
extra='ignore'so that unknown fields from newer spec versions are silently dropped rather than causing validation errors. Generated types whose schemas setadditionalProperties: trueoverride this withextra='allow'in their ownmodel_config. Consumers who want strict validation can override withextra='forbid'.Create a new model by parsing and validating input data from keyword arguments.
Raises [
ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.selfis explicitly positional-only to allowselfas a field name.Ancestors
- AdCPBaseModel
- pydantic.main.BaseModel
Class variables
var categories_evaluated : list[str] | Nonevar check_id : strvar conditions : list[Condition] | Nonevar expires_at : pydantic.types.AwareDatetime | Nonevar explanation : strvar findings : list[Finding] | Nonevar governance_context : str | Nonevar model_configvar next_check : pydantic.types.AwareDatetime | Nonevar plan_id : strvar policies_evaluated : list[str] | Nonevar status : Status
Inherited members
class ConsentBasis (*args, **kwds)-
Expand source code
class ConsentBasis(Enum): consent = 'consent' legitimate_interest = 'legitimate_interest' contract = 'contract' legal_obligation = 'legal_obligation'Create a collection of name/value pairs.
Example enumeration:
>>> class Color(Enum): ... RED = 1 ... BLUE = 2 ... GREEN = 3Access them by:
- attribute access::
>>> Color.RED <Color.RED: 1>- value lookup:
>>> Color(1) <Color.RED: 1>- name lookup:
>>> Color['RED'] <Color.RED: 1>Enumerations can be iterated over, and know how many members they have:
>>> len(Color) 3>>> list(Color) [<Color.RED: 1>, <Color.BLUE: 2>, <Color.GREEN: 3>]Methods can be added to enumerations, and members can have their own attributes – see the documentation for details.
Ancestors
- enum.Enum
Class variables
var consentvar contractvar legal_obligationvar legitimate_interest
class ContentIdType (*args, **kwds)-
Expand source code
class ContentIdType(Enum): sku = 'sku' gtin = 'gtin' offering_id = 'offering_id' job_id = 'job_id' hotel_id = 'hotel_id' flight_id = 'flight_id' vehicle_id = 'vehicle_id' listing_id = 'listing_id' store_id = 'store_id' program_id = 'program_id' destination_id = 'destination_id' app_id = 'app_id'Create a collection of name/value pairs.
Example enumeration:
>>> class Color(Enum): ... RED = 1 ... BLUE = 2 ... GREEN = 3Access them by:
- attribute access::
>>> Color.RED <Color.RED: 1>- value lookup:
>>> Color(1) <Color.RED: 1>- name lookup:
>>> Color['RED'] <Color.RED: 1>Enumerations can be iterated over, and know how many members they have:
>>> len(Color) 3>>> list(Color) [<Color.RED: 1>, <Color.BLUE: 2>, <Color.GREEN: 3>]Methods can be added to enumerations, and members can have their own attributes – see the documentation for details.
Ancestors
- enum.Enum
Class variables
var app_idvar destination_idvar flight_idvar gtinvar hotel_idvar job_idvar listing_idvar offering_idvar program_idvar skuvar store_idvar vehicle_id
class ContextMatchRequest (**data: Any)-
Expand source code
class ContextMatchRequest(AdCPBaseModel): model_config = ConfigDict( extra='forbid', ) field_schema: Annotated[ AnyUrl | None, Field( alias='$schema', description='Optional schema URI for validation. Ignored at runtime.' ), ] = None artifact: Annotated[ artifact_1.Artifact | None, Field( description='Full content artifact adjacent to this ad opportunity. Same schema used for content standards evaluation. The publisher sends the artifact when they want the buyer to evaluate the full content. Contractual protections govern buyer use. TEE deployment upgrades contractual trust to cryptographic verification. Publishers MUST NOT include asset access credentials (bearer tokens, service accounts) — the router fans out to multiple buyer agents. For secured assets, use signed URLs with short expiry. Routers MUST strip access fields from artifacts before forwarding.' ), ] = None artifact_refs: Annotated[ list[ArtifactRef] | None, Field( description='Public content references adjacent to this ad opportunity. Each artifact identifies content via a public identifier the buyer can resolve independently — no private registry sync required.', max_length=20, min_length=1, ), ] = None context_signals: Annotated[ ContextSignals | None, Field( description='Pre-computed classifier outputs for the content environment. Use when the publisher wants to provide classified context without sharing content or public references. Can supplement artifact_refs (e.g., URL + pre-classified topics) or replace them entirely (e.g., ephemeral conversation turns). Raw content MUST NOT be included — only classified outputs. The publisher is the classifier boundary.' ), ] = None geo: Annotated[ Geo | None, Field( description='Coarse geographic location of the viewer. Publisher controls granularity — country is sufficient for regulatory compliance and volume filtering, region or metro helps with campaign targeting and valuation. Coarsened to prevent user identification: no postcode, no coordinates. All fields optional.' ), ] = None package_ids: Annotated[ list[str] | None, Field( description='Restrict evaluation to specific packages. When omitted, the provider evaluates all eligible packages for this placement (the common case). MUST NOT vary by user — the same package_ids must be sent for every user on a given placement. User-dependent filtering leaks identity into the context path.', max_length=500, min_length=1, ), ] = None placement_id: Annotated[ str, Field( description="Placement identifier from the publisher's placement registry in adagents.json. Identifies where on the property this ad opportunity exists. One placement per request." ), ] property_id: Annotated[ property_id_1.PropertyId | None, Field( description="Publisher's human-readable property slug (e.g., 'cnn_homepage'). Optional when property_rid is present. Useful for logging and debugging." ), ] = None property_rid: Annotated[ UUID, Field( description='Property catalog UUID (UUID v7). Globally unique, stable identifier assigned by the property catalog. The primary key for TMP matching and property list targeting.' ), ] property_type: Annotated[ property_type_1.PropertyType, Field(description='Type of the publisher property') ] protocol_version: Annotated[ str | None, Field( description='TMP protocol version. Allows receivers to handle semantic differences across versions.' ), ] = '1.0' request_id: Annotated[ str, Field( description='Unique request identifier. MUST NOT correlate with any identity match request_id.' ), ] type: Annotated[ Literal['context_match_request'], Field(description='Message type discriminator for deserialization.'), ]Base model for AdCP types with spec-compliant serialization.
Defaults to
extra='ignore'so that unknown fields from newer spec versions are silently dropped rather than causing validation errors. Generated types whose schemas setadditionalProperties: trueoverride this withextra='allow'in their ownmodel_config. Consumers who want strict validation can override withextra='forbid'.Create a new model by parsing and validating input data from keyword arguments.
Raises [
ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.selfis explicitly positional-only to allowselfas a field name.Ancestors
- AdCPBaseModel
- pydantic.main.BaseModel
Class variables
var artifact : Artifact | Nonevar artifact_refs : list[ArtifactRef] | Nonevar context_signals : ContextSignals | Nonevar field_schema : pydantic.networks.AnyUrl | Nonevar geo : Geo | Nonevar model_configvar package_ids : list[str] | Nonevar placement_id : strvar property_id : PropertyId | Nonevar property_rid : uuid.UUIDvar property_type : PropertyTypevar protocol_version : str | Nonevar request_id : strvar type : Literal['context_match_request']
Inherited members
class ContextMatchResponse (**data: Any)-
Expand source code
class ContextMatchResponse(AdCPBaseModel): model_config = ConfigDict( extra='allow', ) cache_ttl: Annotated[ int | None, Field( description='Optional override for the default 5-minute cache TTL, in seconds. When present, the router MUST use this value instead of its default. Set to 0 to disable caching (e.g., when targeting configuration has just changed).', ge=0, le=86400, ), ] = None offers: Annotated[ list[offer.Offer], Field( description='Offers from the buyer, one per activated package. An empty array means no packages matched. For simple activation, each offer has just package_id. For richer responses, offers include brand, price, summary, and creative manifest.' ), ] request_id: Annotated[ str, Field(description='Echoed request identifier from the context match request') ] signals: Annotated[ Signals | None, Field( description='Response-level targeting signals for ad server pass-through. In the GAM case, these carry the key-value pairs that trigger line items. Not per-offer — applies to the response as a whole.' ), ] = None type: Annotated[ Literal['context_match_response'], Field(description='Message type discriminator for deserialization.'), ]Base model for AdCP types with spec-compliant serialization.
Defaults to
extra='ignore'so that unknown fields from newer spec versions are silently dropped rather than causing validation errors. Generated types whose schemas setadditionalProperties: trueoverride this withextra='allow'in their ownmodel_config. Consumers who want strict validation can override withextra='forbid'.Create a new model by parsing and validating input data from keyword arguments.
Raises [
ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.selfis explicitly positional-only to allowselfas a field name.Ancestors
- AdCPBaseModel
- pydantic.main.BaseModel
Class variables
var cache_ttl : int | Nonevar model_configvar offers : list[Offer]var request_id : strvar signals : Signals | Nonevar type : Literal['context_match_response']
Inherited members
class ContextObject (**data: Any)-
Expand source code
class ContextObject(AdCPBaseModel): model_config = ConfigDict( extra='allow', )Base model for AdCP types with spec-compliant serialization.
Defaults to
extra='ignore'so that unknown fields from newer spec versions are silently dropped rather than causing validation errors. Generated types whose schemas setadditionalProperties: trueoverride this withextra='allow'in their ownmodel_config. Consumers who want strict validation can override withextra='forbid'.Create a new model by parsing and validating input data from keyword arguments.
Raises [
ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.selfis explicitly positional-only to allowselfas a field name.Ancestors
- AdCPBaseModel
- pydantic.main.BaseModel
Class variables
var model_config
Inherited members
class CpaPricingOption (**data: Any)-
Expand source code
class CpaPricingOption(AdCPBaseModel): model_config = ConfigDict( extra='allow', ) currency: Annotated[ str, Field( description='ISO 4217 currency code', examples=['USD', 'EUR', 'GBP', 'JPY'], pattern='^[A-Z]{3}$', ), ] custom_event_name: Annotated[ str | None, Field( description="Name of the custom event when event_type is 'custom'. Required when event_type is 'custom', ignored otherwise." ), ] = None eligible_adjustments: Annotated[ list[adjustment_kind.PriceAdjustmentKind] | None, Field( description='Adjustment kinds applicable to this pricing option. Tells buyer agents which adjustments are available before negotiation. When absent, no adjustments are pre-declared — the buyer should check price_breakdown if present.' ), ] = None event_source_id: Annotated[ str | None, Field( description='When present, only events from this specific event source count toward billing. Allows different CPA rates for different sources (e.g., online vs in-store purchases). Must match an event source configured via sync_event_sources.' ), ] = None event_type: Annotated[ event_type_1.EventType, Field( description='The conversion event type that triggers billing (e.g., purchase, lead, app_install)' ), ] fixed_price: Annotated[ float, Field(description='Fixed price per acquisition in the specified currency', gt=0.0) ] min_spend_per_package: Annotated[ float | None, Field( description='Minimum spend requirement per package using this pricing option, in the specified currency', ge=0.0, ), ] = None price_breakdown: Annotated[ price_breakdown_1.PriceBreakdown | None, Field( description='Breakdown of how fixed_price was derived from the list (rate card) price. Only meaningful when fixed_price is present.' ), ] = None pricing_model: Annotated[ Literal['cpa'], Field(description='Cost per acquisition (conversion event)') ] pricing_option_id: Annotated[ str, Field(description='Unique identifier for this pricing option within the product') ]Base model for AdCP types with spec-compliant serialization.
Defaults to
extra='ignore'so that unknown fields from newer spec versions are silently dropped rather than causing validation errors. Generated types whose schemas setadditionalProperties: trueoverride this withextra='allow'in their ownmodel_config. Consumers who want strict validation can override withextra='forbid'.Create a new model by parsing and validating input data from keyword arguments.
Raises [
ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.selfis explicitly positional-only to allowselfas a field name.Ancestors
- AdCPBaseModel
- pydantic.main.BaseModel
Class variables
var currency : strvar custom_event_name : str | Nonevar eligible_adjustments : list[PriceAdjustmentKind] | Nonevar event_source_id : str | Nonevar event_type : EventTypevar fixed_price : floatvar min_spend_per_package : float | Nonevar model_configvar price_breakdown : PriceBreakdown | Nonevar pricing_model : Literal['cpa']var pricing_option_id : str
Inherited members
class CpcPricingOption (**data: Any)-
Expand source code
class CpcPricingOption(AdCPBaseModel): model_config = ConfigDict( extra='allow', ) currency: Annotated[ str, Field( description='ISO 4217 currency code', examples=['USD', 'EUR', 'GBP', 'JPY'], pattern='^[A-Z]{3}$', ), ] eligible_adjustments: Annotated[ list[adjustment_kind.PriceAdjustmentKind] | None, Field( description='Adjustment kinds applicable to this pricing option. Tells buyer agents which adjustments are available before negotiation. When absent, no adjustments are pre-declared — the buyer should check price_breakdown if present.' ), ] = None fixed_price: Annotated[ float | None, Field( description='Fixed price per click. If present, this is fixed pricing. If absent, auction-based.', ge=0.0, ), ] = None floor_price: Annotated[ float | None, Field( description='Minimum acceptable bid for auction pricing (mutually exclusive with fixed_price). Bids below this value will be rejected.', ge=0.0, ), ] = None max_bid: Annotated[ bool | None, Field( description="When true, bid_price is interpreted as the buyer's maximum willingness to pay (ceiling) rather than an exact price. Sellers may optimize actual clearing prices between floor_price and bid_price based on delivery pacing. When false or absent, bid_price (if provided) is the exact bid/price to honor." ), ] = False min_spend_per_package: Annotated[ float | None, Field( description='Minimum spend requirement per package using this pricing option, in the specified currency', ge=0.0, ), ] = None price_breakdown: Annotated[ price_breakdown_1.PriceBreakdown | None, Field( description='Breakdown of how fixed_price was derived from the list (rate card) price. Only meaningful when fixed_price is present.' ), ] = None price_guidance: Annotated[ price_guidance_1.PriceGuidance | None, Field(description='Optional pricing guidance for auction-based bidding'), ] = None pricing_model: Annotated[Literal['cpc'], Field(description='Cost per click')] pricing_option_id: Annotated[ str, Field(description='Unique identifier for this pricing option within the product') ]Base model for AdCP types with spec-compliant serialization.
Defaults to
extra='ignore'so that unknown fields from newer spec versions are silently dropped rather than causing validation errors. Generated types whose schemas setadditionalProperties: trueoverride this withextra='allow'in their ownmodel_config. Consumers who want strict validation can override withextra='forbid'.Create a new model by parsing and validating input data from keyword arguments.
Raises [
ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.selfis explicitly positional-only to allowselfas a field name.Ancestors
- AdCPBaseModel
- pydantic.main.BaseModel
Class variables
var currency : strvar eligible_adjustments : list[PriceAdjustmentKind] | Nonevar fixed_price : float | Nonevar floor_price : float | Nonevar max_bid : bool | Nonevar min_spend_per_package : float | Nonevar model_configvar price_breakdown : PriceBreakdown | Nonevar price_guidance : PriceGuidance | Nonevar pricing_model : Literal['cpc']var pricing_option_id : str
Inherited members
class CpcvPricingOption (**data: Any)-
Expand source code
class CpcvPricingOption(AdCPBaseModel): model_config = ConfigDict( extra='allow', ) currency: Annotated[ str, Field( description='ISO 4217 currency code', examples=['USD', 'EUR', 'GBP', 'JPY'], pattern='^[A-Z]{3}$', ), ] eligible_adjustments: Annotated[ list[adjustment_kind.PriceAdjustmentKind] | None, Field( description='Adjustment kinds applicable to this pricing option. Tells buyer agents which adjustments are available before negotiation. When absent, no adjustments are pre-declared — the buyer should check price_breakdown if present.' ), ] = None fixed_price: Annotated[ float | None, Field( description='Fixed price per completed view. If present, this is fixed pricing. If absent, auction-based.', ge=0.0, ), ] = None floor_price: Annotated[ float | None, Field( description='Minimum acceptable bid for auction pricing (mutually exclusive with fixed_price). Bids below this value will be rejected.', ge=0.0, ), ] = None max_bid: Annotated[ bool | None, Field( description="When true, bid_price is interpreted as the buyer's maximum willingness to pay (ceiling) rather than an exact price. Sellers may optimize actual clearing prices between floor_price and bid_price based on delivery pacing. When false or absent, bid_price (if provided) is the exact bid/price to honor." ), ] = False min_spend_per_package: Annotated[ float | None, Field( description='Minimum spend requirement per package using this pricing option, in the specified currency', ge=0.0, ), ] = None price_breakdown: Annotated[ price_breakdown_1.PriceBreakdown | None, Field( description='Breakdown of how fixed_price was derived from the list (rate card) price. Only meaningful when fixed_price is present.' ), ] = None price_guidance: Annotated[ price_guidance_1.PriceGuidance | None, Field(description='Optional pricing guidance for auction-based bidding'), ] = None pricing_model: Annotated[ Literal['cpcv'], Field(description='Cost per completed view (100% completion)') ] pricing_option_id: Annotated[ str, Field(description='Unique identifier for this pricing option within the product') ]Base model for AdCP types with spec-compliant serialization.
Defaults to
extra='ignore'so that unknown fields from newer spec versions are silently dropped rather than causing validation errors. Generated types whose schemas setadditionalProperties: trueoverride this withextra='allow'in their ownmodel_config. Consumers who want strict validation can override withextra='forbid'.Create a new model by parsing and validating input data from keyword arguments.
Raises [
ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.selfis explicitly positional-only to allowselfas a field name.Ancestors
- AdCPBaseModel
- pydantic.main.BaseModel
Class variables
var currency : strvar eligible_adjustments : list[PriceAdjustmentKind] | Nonevar fixed_price : float | Nonevar floor_price : float | Nonevar max_bid : bool | Nonevar min_spend_per_package : float | Nonevar model_configvar price_breakdown : PriceBreakdown | Nonevar price_guidance : PriceGuidance | Nonevar pricing_model : Literal['cpcv']var pricing_option_id : str
Inherited members
class CpmPricingOption (**data: Any)-
Expand source code
class CpmPricingOption(AdCPBaseModel): model_config = ConfigDict( extra='allow', ) currency: Annotated[ str, Field( description='ISO 4217 currency code', examples=['USD', 'EUR', 'GBP', 'JPY'], pattern='^[A-Z]{3}$', ), ] eligible_adjustments: Annotated[ list[adjustment_kind.PriceAdjustmentKind] | None, Field( description='Adjustment kinds applicable to this pricing option. Tells buyer agents which adjustments are available before negotiation. When absent, no adjustments are pre-declared — the buyer should check price_breakdown if present.' ), ] = None fixed_price: Annotated[ float | None, Field( description='Fixed price per unit. If present, this is fixed pricing. If absent, auction-based.', ge=0.0, ), ] = None floor_price: Annotated[ float | None, Field( description='Minimum acceptable bid for auction pricing (mutually exclusive with fixed_price). Bids below this value will be rejected.', ge=0.0, ), ] = None max_bid: Annotated[ bool | None, Field( description="When true, bid_price is interpreted as the buyer's maximum willingness to pay (ceiling) rather than an exact price. Sellers may optimize actual clearing prices between floor_price and bid_price based on delivery pacing. When false or absent, bid_price (if provided) is the exact bid/price to honor." ), ] = False min_spend_per_package: Annotated[ float | None, Field( description='Minimum spend requirement per package using this pricing option, in the specified currency', ge=0.0, ), ] = None price_breakdown: Annotated[ price_breakdown_1.PriceBreakdown | None, Field( description='Breakdown of how fixed_price was derived from the list (rate card) price. Only meaningful when fixed_price is present.' ), ] = None price_guidance: Annotated[ price_guidance_1.PriceGuidance | None, Field(description='Optional pricing guidance for auction-based bidding'), ] = None pricing_model: Annotated[Literal['cpm'], Field(description='Cost per 1,000 impressions')] pricing_option_id: Annotated[ str, Field(description='Unique identifier for this pricing option within the product') ]Base model for AdCP types with spec-compliant serialization.
Defaults to
extra='ignore'so that unknown fields from newer spec versions are silently dropped rather than causing validation errors. Generated types whose schemas setadditionalProperties: trueoverride this withextra='allow'in their ownmodel_config. Consumers who want strict validation can override withextra='forbid'.Create a new model by parsing and validating input data from keyword arguments.
Raises [
ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.selfis explicitly positional-only to allowselfas a field name.Ancestors
- AdCPBaseModel
- pydantic.main.BaseModel
Class variables
var currency : strvar eligible_adjustments : list[PriceAdjustmentKind] | Nonevar fixed_price : float | Nonevar floor_price : float | Nonevar max_bid : bool | Nonevar min_spend_per_package : float | Nonevar model_configvar price_breakdown : PriceBreakdown | Nonevar price_guidance : PriceGuidance | Nonevar pricing_model : Literal['cpm']var pricing_option_id : str
class CpmAuctionPricingOption (**data: Any)-
Expand source code
class CpmPricingOption(AdCPBaseModel): model_config = ConfigDict( extra='allow', ) currency: Annotated[ str, Field( description='ISO 4217 currency code', examples=['USD', 'EUR', 'GBP', 'JPY'], pattern='^[A-Z]{3}$', ), ] eligible_adjustments: Annotated[ list[adjustment_kind.PriceAdjustmentKind] | None, Field( description='Adjustment kinds applicable to this pricing option. Tells buyer agents which adjustments are available before negotiation. When absent, no adjustments are pre-declared — the buyer should check price_breakdown if present.' ), ] = None fixed_price: Annotated[ float | None, Field( description='Fixed price per unit. If present, this is fixed pricing. If absent, auction-based.', ge=0.0, ), ] = None floor_price: Annotated[ float | None, Field( description='Minimum acceptable bid for auction pricing (mutually exclusive with fixed_price). Bids below this value will be rejected.', ge=0.0, ), ] = None max_bid: Annotated[ bool | None, Field( description="When true, bid_price is interpreted as the buyer's maximum willingness to pay (ceiling) rather than an exact price. Sellers may optimize actual clearing prices between floor_price and bid_price based on delivery pacing. When false or absent, bid_price (if provided) is the exact bid/price to honor." ), ] = False min_spend_per_package: Annotated[ float | None, Field( description='Minimum spend requirement per package using this pricing option, in the specified currency', ge=0.0, ), ] = None price_breakdown: Annotated[ price_breakdown_1.PriceBreakdown | None, Field( description='Breakdown of how fixed_price was derived from the list (rate card) price. Only meaningful when fixed_price is present.' ), ] = None price_guidance: Annotated[ price_guidance_1.PriceGuidance | None, Field(description='Optional pricing guidance for auction-based bidding'), ] = None pricing_model: Annotated[Literal['cpm'], Field(description='Cost per 1,000 impressions')] pricing_option_id: Annotated[ str, Field(description='Unique identifier for this pricing option within the product') ]Base model for AdCP types with spec-compliant serialization.
Defaults to
extra='ignore'so that unknown fields from newer spec versions are silently dropped rather than causing validation errors. Generated types whose schemas setadditionalProperties: trueoverride this withextra='allow'in their ownmodel_config. Consumers who want strict validation can override withextra='forbid'.Create a new model by parsing and validating input data from keyword arguments.
Raises [
ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.selfis explicitly positional-only to allowselfas a field name.Ancestors
- AdCPBaseModel
- pydantic.main.BaseModel
Class variables
var currency : strvar eligible_adjustments : list[PriceAdjustmentKind] | Nonevar fixed_price : float | Nonevar floor_price : float | Nonevar max_bid : bool | Nonevar min_spend_per_package : float | Nonevar model_configvar price_breakdown : PriceBreakdown | Nonevar price_guidance : PriceGuidance | Nonevar pricing_model : Literal['cpm']var pricing_option_id : str
class CpmFixedRatePricingOption (**data: Any)-
Expand source code
class CpmPricingOption(AdCPBaseModel): model_config = ConfigDict( extra='allow', ) currency: Annotated[ str, Field( description='ISO 4217 currency code', examples=['USD', 'EUR', 'GBP', 'JPY'], pattern='^[A-Z]{3}$', ), ] eligible_adjustments: Annotated[ list[adjustment_kind.PriceAdjustmentKind] | None, Field( description='Adjustment kinds applicable to this pricing option. Tells buyer agents which adjustments are available before negotiation. When absent, no adjustments are pre-declared — the buyer should check price_breakdown if present.' ), ] = None fixed_price: Annotated[ float | None, Field( description='Fixed price per unit. If present, this is fixed pricing. If absent, auction-based.', ge=0.0, ), ] = None floor_price: Annotated[ float | None, Field( description='Minimum acceptable bid for auction pricing (mutually exclusive with fixed_price). Bids below this value will be rejected.', ge=0.0, ), ] = None max_bid: Annotated[ bool | None, Field( description="When true, bid_price is interpreted as the buyer's maximum willingness to pay (ceiling) rather than an exact price. Sellers may optimize actual clearing prices between floor_price and bid_price based on delivery pacing. When false or absent, bid_price (if provided) is the exact bid/price to honor." ), ] = False min_spend_per_package: Annotated[ float | None, Field( description='Minimum spend requirement per package using this pricing option, in the specified currency', ge=0.0, ), ] = None price_breakdown: Annotated[ price_breakdown_1.PriceBreakdown | None, Field( description='Breakdown of how fixed_price was derived from the list (rate card) price. Only meaningful when fixed_price is present.' ), ] = None price_guidance: Annotated[ price_guidance_1.PriceGuidance | None, Field(description='Optional pricing guidance for auction-based bidding'), ] = None pricing_model: Annotated[Literal['cpm'], Field(description='Cost per 1,000 impressions')] pricing_option_id: Annotated[ str, Field(description='Unique identifier for this pricing option within the product') ]Base model for AdCP types with spec-compliant serialization.
Defaults to
extra='ignore'so that unknown fields from newer spec versions are silently dropped rather than causing validation errors. Generated types whose schemas setadditionalProperties: trueoverride this withextra='allow'in their ownmodel_config. Consumers who want strict validation can override withextra='forbid'.Create a new model by parsing and validating input data from keyword arguments.
Raises [
ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.selfis explicitly positional-only to allowselfas a field name.Ancestors
- AdCPBaseModel
- pydantic.main.BaseModel
Class variables
var currency : strvar eligible_adjustments : list[PriceAdjustmentKind] | Nonevar fixed_price : float | Nonevar floor_price : float | Nonevar max_bid : bool | Nonevar min_spend_per_package : float | Nonevar model_configvar price_breakdown : PriceBreakdown | Nonevar price_guidance : PriceGuidance | Nonevar pricing_model : Literal['cpm']var pricing_option_id : str
Inherited members
class CppPricingOption (**data: Any)-
Expand source code
class CppPricingOption(AdCPBaseModel): model_config = ConfigDict( extra='allow', ) currency: Annotated[ str, Field( description='ISO 4217 currency code', examples=['USD', 'EUR', 'GBP', 'JPY'], pattern='^[A-Z]{3}$', ), ] eligible_adjustments: Annotated[ list[adjustment_kind.PriceAdjustmentKind] | None, Field( description='Adjustment kinds applicable to this pricing option. Tells buyer agents which adjustments are available before negotiation. When absent, no adjustments are pre-declared — the buyer should check price_breakdown if present.' ), ] = None fixed_price: Annotated[ float | None, Field( description='Fixed price per rating point. If present, this is fixed pricing. If absent, auction-based.', ge=0.0, ), ] = None floor_price: Annotated[ float | None, Field( description='Minimum acceptable bid for auction pricing (mutually exclusive with fixed_price). Bids below this value will be rejected.', ge=0.0, ), ] = None min_spend_per_package: Annotated[ float | None, Field( description='Minimum spend requirement per package using this pricing option, in the specified currency', ge=0.0, ), ] = None parameters: Annotated[ Parameters, Field(description='CPP-specific parameters for demographic targeting') ] price_breakdown: Annotated[ price_breakdown_1.PriceBreakdown | None, Field( description='Breakdown of how fixed_price was derived from the list (rate card) price. Only meaningful when fixed_price is present.' ), ] = None price_guidance: Annotated[ price_guidance_1.PriceGuidance | None, Field(description='Optional pricing guidance for auction-based bidding'), ] = None pricing_model: Annotated[Literal['cpp'], Field(description='Cost per Gross Rating Point')] pricing_option_id: Annotated[ str, Field(description='Unique identifier for this pricing option within the product') ]Base model for AdCP types with spec-compliant serialization.
Defaults to
extra='ignore'so that unknown fields from newer spec versions are silently dropped rather than causing validation errors. Generated types whose schemas setadditionalProperties: trueoverride this withextra='allow'in their ownmodel_config. Consumers who want strict validation can override withextra='forbid'.Create a new model by parsing and validating input data from keyword arguments.
Raises [
ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.selfis explicitly positional-only to allowselfas a field name.Ancestors
- AdCPBaseModel
- pydantic.main.BaseModel
Class variables
var currency : strvar eligible_adjustments : list[PriceAdjustmentKind] | Nonevar fixed_price : float | Nonevar floor_price : float | Nonevar min_spend_per_package : float | Nonevar model_configvar parameters : Parametersvar price_breakdown : PriceBreakdown | Nonevar price_guidance : PriceGuidance | Nonevar pricing_model : Literal['cpp']var pricing_option_id : str
Inherited members
class CpvPricingOption (**data: Any)-
Expand source code
class CpvPricingOption(AdCPBaseModel): model_config = ConfigDict( extra='allow', ) currency: Annotated[ str, Field( description='ISO 4217 currency code', examples=['USD', 'EUR', 'GBP', 'JPY'], pattern='^[A-Z]{3}$', ), ] eligible_adjustments: Annotated[ list[adjustment_kind.PriceAdjustmentKind] | None, Field( description='Adjustment kinds applicable to this pricing option. Tells buyer agents which adjustments are available before negotiation. When absent, no adjustments are pre-declared — the buyer should check price_breakdown if present.' ), ] = None fixed_price: Annotated[ float | None, Field( description='Fixed price per view. If present, this is fixed pricing. If absent, auction-based.', ge=0.0, ), ] = None floor_price: Annotated[ float | None, Field( description='Minimum acceptable bid for auction pricing (mutually exclusive with fixed_price). Bids below this value will be rejected.', ge=0.0, ), ] = None max_bid: Annotated[ bool | None, Field( description="When true, bid_price is interpreted as the buyer's maximum willingness to pay (ceiling) rather than an exact price. Sellers may optimize actual clearing prices between floor_price and bid_price based on delivery pacing. When false or absent, bid_price (if provided) is the exact bid/price to honor." ), ] = False min_spend_per_package: Annotated[ float | None, Field( description='Minimum spend requirement per package using this pricing option, in the specified currency', ge=0.0, ), ] = None parameters: Annotated[ Parameters, Field(description='CPV-specific parameters defining the view threshold') ] price_breakdown: Annotated[ price_breakdown_1.PriceBreakdown | None, Field( description='Breakdown of how fixed_price was derived from the list (rate card) price. Only meaningful when fixed_price is present.' ), ] = None price_guidance: Annotated[ price_guidance_1.PriceGuidance | None, Field(description='Optional pricing guidance for auction-based bidding'), ] = None pricing_model: Annotated[Literal['cpv'], Field(description='Cost per view at threshold')] pricing_option_id: Annotated[ str, Field(description='Unique identifier for this pricing option within the product') ]Base model for AdCP types with spec-compliant serialization.
Defaults to
extra='ignore'so that unknown fields from newer spec versions are silently dropped rather than causing validation errors. Generated types whose schemas setadditionalProperties: trueoverride this withextra='allow'in their ownmodel_config. Consumers who want strict validation can override withextra='forbid'.Create a new model by parsing and validating input data from keyword arguments.
Raises [
ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.selfis explicitly positional-only to allowselfas a field name.Ancestors
- AdCPBaseModel
- pydantic.main.BaseModel
Class variables
var currency : strvar eligible_adjustments : list[PriceAdjustmentKind] | Nonevar fixed_price : float | Nonevar floor_price : float | Nonevar max_bid : bool | Nonevar min_spend_per_package : float | Nonevar model_configvar parameters : Parametersvar price_breakdown : PriceBreakdown | Nonevar price_guidance : PriceGuidance | Nonevar pricing_model : Literal['cpv']var pricing_option_id : str
Inherited members
class CreateContentStandardsSuccessResponse (**data: Any)-
Expand source code
class CreateContentStandardsResponse1(AdCPBaseModel): context: context_1.ContextObject | None = None ext: ext_1.ExtensionObject | None = None standards_id: Annotated[ str, Field(description='Unique identifier for the created standards configuration') ]Base model for AdCP types with spec-compliant serialization.
Defaults to
extra='ignore'so that unknown fields from newer spec versions are silently dropped rather than causing validation errors. Generated types whose schemas setadditionalProperties: trueoverride this withextra='allow'in their ownmodel_config. Consumers who want strict validation can override withextra='forbid'.Create a new model by parsing and validating input data from keyword arguments.
Raises [
ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.selfis explicitly positional-only to allowselfas a field name.Ancestors
- AdCPBaseModel
- pydantic.main.BaseModel
Class variables
var context : ContextObject | Nonevar ext : ExtensionObject | Nonevar model_configvar standards_id : str
Inherited members
class CreateContentStandardsErrorResponse (**data: Any)-
Expand source code
class CreateContentStandardsResponse2(AdCPBaseModel): conflicting_standards_id: Annotated[ str | None, Field( description='If the error is a scope conflict, the ID of the existing standards that conflict' ), ] = None context: context_1.ContextObject | None = None errors: list[error.Error] ext: ext_1.ExtensionObject | None = NoneBase model for AdCP types with spec-compliant serialization.
Defaults to
extra='ignore'so that unknown fields from newer spec versions are silently dropped rather than causing validation errors. Generated types whose schemas setadditionalProperties: trueoverride this withextra='allow'in their ownmodel_config. Consumers who want strict validation can override withextra='forbid'.Create a new model by parsing and validating input data from keyword arguments.
Raises [
ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.selfis explicitly positional-only to allowselfas a field name.Ancestors
- AdCPBaseModel
- pydantic.main.BaseModel
Class variables
var conflicting_standards_id : str | Nonevar context : ContextObject | Nonevar errors : list[Error]var ext : ExtensionObject | Nonevar model_config
Inherited members
class CreateMediaBuyRequest (**data: Any)-
Expand source code
class CreateMediaBuyRequest(AdCPBaseModel): model_config = ConfigDict( extra='allow', ) account: Annotated[ account_ref.AccountReference, Field( description='Account to bill for this media buy. Pass a natural key (brand, operator, optional sandbox) or a seller-assigned account_id from list_accounts.' ), ] advertiser_industry: Annotated[ advertiser_industry_1.AdvertiserIndustry | None, Field( description="Industry classification for this specific campaign. A brand may operate across multiple industries (brand.json industries field), but each media buy targets one. For example, a consumer health company running a wellness campaign sends 'healthcare.wellness', not 'cpg'. Sellers map this to platform-native codes (e.g., Spotify ADV categories, LinkedIn industry IDs). When omitted, sellers may infer from the brand manifest's industries field." ), ] = None artifact_webhook: Annotated[ ArtifactWebhook | None, Field( description='Optional webhook configuration for content artifact delivery. Used by governance agents to validate content adjacency. Seller pushes artifacts to this endpoint; orchestrator forwards to governance agent for validation.' ), ] = None brand: Annotated[ brand_ref.BrandReference, Field( description='Brand reference for this media buy. Resolved to full brand identity at execution time from brand.json or the registry.' ), ] context: context_1.ContextObject | None = None end_time: Annotated[ AwareDatetime, Field(description='Campaign end date/time in ISO 8601 format') ] ext: ext_1.ExtensionObject | None = None idempotency_key: Annotated[ str | None, Field( description='Client-generated unique key for this request. If a request with the same idempotency_key and account has already been processed, the seller returns the existing media buy rather than creating a duplicate. MUST be unique per (seller, request) pair to prevent cross-seller correlation. Use a fresh UUID v4 for each request.', max_length=255, min_length=16, ), ] = None invoice_recipient: Annotated[ business_entity.BusinessEntity | None, Field( description="Override the account's default billing entity for this specific buy. When provided, the seller invoices this entity instead. The seller MUST validate the invoice recipient is authorized for this account. When governance_agents are configured, the seller MUST include invoice_recipient in the check_governance request." ), ] = None io_acceptance: Annotated[ IoAcceptance | None, Field( description="Acceptance of an insertion order from a committed proposal. Required when the proposal's insertion_order has requires_signature: true. References the io_id from the proposal's insertion_order." ), ] = None packages: Annotated[ list[package_request.PackageRequest] | None, Field( description="Array of package configurations. Required when not using proposal_id. When executing a proposal, this can be omitted and packages will be derived from the proposal's allocations.", min_length=1, ), ] = None plan_id: Annotated[ str | None, Field( description='Campaign governance plan identifier. Required when the account has governance_agents. The seller includes this in the committed check_governance request so the governance agent can validate against the correct plan.' ), ] = None po_number: Annotated[str | None, Field(description='Purchase order number for tracking')] = None proposal_id: Annotated[ str | None, Field( description="ID of a proposal from get_products to execute. When provided with total_budget, the publisher converts the proposal's allocation percentages into packages automatically. Alternative to providing packages array." ), ] = None push_notification_config: Annotated[ push_notification_config_1.PushNotificationConfig | None, Field( description='Optional webhook configuration for async task status notifications. Publisher will send webhooks when status changes (working, input-required, completed, failed). The client generates an operation_id and embeds it in the URL before sending — the publisher echoes it back in webhook payloads for correlation.' ), ] = None reporting_webhook: Annotated[ reporting_webhook_1.ReportingWebhook | None, Field(description='Optional webhook configuration for automated reporting delivery'), ] = None start_time: start_timing.StartTiming total_budget: Annotated[ TotalBudget | None, Field( description="Total budget for the media buy when executing a proposal. The publisher applies the proposal's allocation percentages to this amount to derive package budgets." ), ] = NoneBase model for AdCP types with spec-compliant serialization.
Defaults to
extra='ignore'so that unknown fields from newer spec versions are silently dropped rather than causing validation errors. Generated types whose schemas setadditionalProperties: trueoverride this withextra='allow'in their ownmodel_config. Consumers who want strict validation can override withextra='forbid'.Create a new model by parsing and validating input data from keyword arguments.
Raises [
ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.selfis explicitly positional-only to allowselfas a field name.Ancestors
- AdCPBaseModel
- pydantic.main.BaseModel
Class variables
var account : AccountReferencevar advertiser_industry : AdvertiserIndustry | Nonevar artifact_webhook : ArtifactWebhook | Nonevar brand : BrandReferencevar context : ContextObject | Nonevar end_time : pydantic.types.AwareDatetimevar ext : ExtensionObject | Nonevar idempotency_key : str | Nonevar invoice_recipient : BusinessEntity | Nonevar io_acceptance : IoAcceptance | Nonevar model_configvar packages : list[PackageRequest] | Nonevar plan_id : str | Nonevar po_number : str | Nonevar proposal_id : str | Nonevar push_notification_config : PushNotificationConfig | Nonevar reporting_webhook : ReportingWebhook | Nonevar start_time : StartTimingvar total_budget : TotalBudget | None
Inherited members
class CreateMediaBuySuccessResponse (**data: Any)-
Expand source code
class CreateMediaBuyResponse1(AdCPBaseModel): model_config = ConfigDict( extra='allow', ) account: Annotated[ account_1.Account | None, Field( description='Account billed for this media buy. Includes advertiser, billing proxy (if any), and rate card applied.' ), ] = None confirmed_at: Annotated[ AwareDatetime | None, Field( description='ISO 8601 timestamp when this media buy was confirmed by the seller. A successful create_media_buy response constitutes order confirmation.' ), ] = None context: context_1.ContextObject | None = None creative_deadline: Annotated[ AwareDatetime | None, Field(description='ISO 8601 timestamp for creative upload deadline') ] = None ext: ext_1.ExtensionObject | None = None invoice_recipient: Annotated[ business_entity.BusinessEntity | None, Field( description='Per-buy invoice recipient, echoed from the request when provided. Confirms the seller accepted the billing override. Bank details are omitted (write-only).' ), ] = None media_buy_id: Annotated[ str, Field(description="Seller's unique identifier for the created media buy") ] packages: Annotated[ list[package.Package], Field(description='Array of created packages with complete state information'), ] planned_delivery: Annotated[ planned_delivery_1.PlannedDelivery | None, Field( description="The seller's interpreted delivery parameters. Describes what the seller will actually run -- geo, channels, flight dates, frequency caps, and budget. Present when the account has governance_agents or when the seller chooses to provide delivery transparency." ), ] = None revision: Annotated[ int | None, Field( description='Initial revision number for this media buy. Use in subsequent update_media_buy requests for optimistic concurrency.', ge=1, ), ] = None sandbox: Annotated[ bool | None, Field(description='When true, this response contains simulated data from sandbox mode.'), ] = None status: Annotated[ media_buy_status.MediaBuyStatus | None, Field( description="Initial media buy status. Either 'active' (immediate activation) or 'pending_activation' (awaiting platform setup)." ), ] = None valid_actions: Annotated[ list[ValidAction] | None, Field( description='Actions the buyer can perform on this media buy after creation. Saves a round-trip to get_media_buys.' ), ] = NoneBase model for AdCP types with spec-compliant serialization.
Defaults to
extra='ignore'so that unknown fields from newer spec versions are silently dropped rather than causing validation errors. Generated types whose schemas setadditionalProperties: trueoverride this withextra='allow'in their ownmodel_config. Consumers who want strict validation can override withextra='forbid'.Create a new model by parsing and validating input data from keyword arguments.
Raises [
ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.selfis explicitly positional-only to allowselfas a field name.Ancestors
- AdCPBaseModel
- pydantic.main.BaseModel
Class variables
var account : Account | Nonevar confirmed_at : pydantic.types.AwareDatetime | Nonevar context : ContextObject | Nonevar creative_deadline : pydantic.types.AwareDatetime | Nonevar ext : ExtensionObject | Nonevar invoice_recipient : BusinessEntity | Nonevar media_buy_id : strvar model_configvar packages : list[Package]var planned_delivery : PlannedDelivery | Nonevar revision : int | Nonevar sandbox : bool | Nonevar status : MediaBuyStatus | Nonevar valid_actions : list[ValidAction] | None
Inherited members
class CreateMediaBuyErrorResponse (**data: Any)-
Expand source code
class CreateMediaBuyResponse2(AdCPBaseModel): model_config = ConfigDict( extra='allow', ) context: context_1.ContextObject | None = None errors: Annotated[ list[error.Error], Field(description='Array of errors explaining why the operation failed', min_length=1), ] ext: ext_1.ExtensionObject | None = NoneBase model for AdCP types with spec-compliant serialization.
Defaults to
extra='ignore'so that unknown fields from newer spec versions are silently dropped rather than causing validation errors. Generated types whose schemas setadditionalProperties: trueoverride this withextra='allow'in their ownmodel_config. Consumers who want strict validation can override withextra='forbid'.Create a new model by parsing and validating input data from keyword arguments.
Raises [
ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.selfis explicitly positional-only to allowselfas a field name.Ancestors
- AdCPBaseModel
- pydantic.main.BaseModel
Class variables
var context : ContextObject | Nonevar errors : list[Error]var ext : ExtensionObject | Nonevar model_config
Inherited members
class Creative (**data: Any)-
Expand source code
class Creative(AdCPBaseModel): model_config = ConfigDict( extra='allow', ) creative_id: Annotated[str, Field(description='Creative identifier')] format_id: Annotated[ format_id_1.FormatId | None, Field(description='Format of this creative') ] = None media_buy_id: Annotated[ str | None, Field( description="Publisher's media buy identifier for this creative. Present when the request spanned multiple media buys, so the buyer can correlate each creative to its media buy." ), ] = None totals: Annotated[ delivery_metrics.DeliveryMetrics | None, Field(description='Aggregate delivery metrics across all variants of this creative'), ] = None variant_count: Annotated[ int | None, Field( description='Total number of variants for this creative. When max_variants was specified in the request, this may exceed the number of items in the variants array.', ge=0, ), ] = None variants: Annotated[ list[creative_variant.CreativeVariant], Field( description='Variant-level delivery breakdown. Each variant includes the rendered manifest and delivery metrics. For standard creatives, contains a single variant. For asset group optimization, one per combination. For generative creative, one per generated execution. Empty when a creative has no variants yet.' ), ]Base model for AdCP types with spec-compliant serialization.
Defaults to
extra='ignore'so that unknown fields from newer spec versions are silently dropped rather than causing validation errors. Generated types whose schemas setadditionalProperties: trueoverride this withextra='allow'in their ownmodel_config. Consumers who want strict validation can override withextra='forbid'.Create a new model by parsing and validating input data from keyword arguments.
Raises [
ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.selfis explicitly positional-only to allowselfas a field name.Ancestors
- AdCPBaseModel
- pydantic.main.BaseModel
Class variables
var creative_id : strvar format_id : FormatId | Nonevar media_buy_id : str | Nonevar model_configvar totals : DeliveryMetrics | Nonevar variant_count : int | Nonevar variants : list[CreativeVariant]
class SyncCreativeResult (**data: Any)-
Expand source code
class Creative(AdCPBaseModel): model_config = ConfigDict( extra='allow', ) account: Annotated[ account_1.Account | None, Field(description='Account that owns this creative') ] = None action: Annotated[ creative_action.CreativeAction, Field(description='Action taken for this creative') ] assigned_to: Annotated[ list[str] | None, Field( description='Package IDs this creative was successfully assigned to (only present when assignments were requested)' ), ] = None assignment_errors: Annotated[ dict[Annotated[str, StringConstraints(pattern=r'^[a-zA-Z0-9_-]+$')], str] | None, Field( description='Assignment errors by package ID (only present when assignment failures occurred)' ), ] = None changes: Annotated[ list[str] | None, Field(description="Field names that were modified (only present when action='updated')"), ] = None creative_id: Annotated[str, Field(description='Creative ID from the request')] errors: Annotated[ list[str] | None, Field(description="Validation or processing errors (only present when action='failed')"), ] = None expires_at: Annotated[ AwareDatetime | None, Field( description='ISO 8601 timestamp when preview link expires (only present when preview_url exists)' ), ] = None platform_id: Annotated[ str | None, Field(description='Platform-specific ID assigned to the creative') ] = None preview_url: Annotated[ AnyUrl | None, Field( description='Preview URL for generative creatives (only present for generative formats)' ), ] = None warnings: Annotated[ list[str] | None, Field(description='Non-fatal warnings about this creative') ] = NoneBase model for AdCP types with spec-compliant serialization.
Defaults to
extra='ignore'so that unknown fields from newer spec versions are silently dropped rather than causing validation errors. Generated types whose schemas setadditionalProperties: trueoverride this withextra='allow'in their ownmodel_config. Consumers who want strict validation can override withextra='forbid'.Create a new model by parsing and validating input data from keyword arguments.
Raises [
ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.selfis explicitly positional-only to allowselfas a field name.Ancestors
- AdCPBaseModel
- pydantic.main.BaseModel
Class variables
var account : Account | Nonevar action : CreativeActionvar assigned_to : list[str] | Nonevar assignment_errors : dict[str, str] | Nonevar changes : list[str] | Nonevar creative_id : strvar errors : list[str] | Nonevar expires_at : pydantic.types.AwareDatetime | Nonevar model_configvar platform_id : str | Nonevar preview_url : pydantic.networks.AnyUrl | Nonevar warnings : list[str] | None
Inherited members
class CreativeApproval (**data: Any)-
Expand source code
class CreativeApproval(AdCPBaseModel): model_config = ConfigDict( extra='allow', ) approval_status: creative_approval_status.CreativeApprovalStatus creative_id: Annotated[str, Field(description='Creative identifier')] rejection_reason: Annotated[ str | None, Field( description="Human-readable explanation of why the creative was rejected. Present only when approval_status is 'rejected'." ), ] = NoneBase model for AdCP types with spec-compliant serialization.
Defaults to
extra='ignore'so that unknown fields from newer spec versions are silently dropped rather than causing validation errors. Generated types whose schemas setadditionalProperties: trueoverride this withextra='allow'in their ownmodel_config. Consumers who want strict validation can override withextra='forbid'.Create a new model by parsing and validating input data from keyword arguments.
Raises [
ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.selfis explicitly positional-only to allowselfas a field name.Ancestors
- AdCPBaseModel
- pydantic.main.BaseModel
Class variables
var approval_status : CreativeApprovalStatusvar creative_id : strvar model_configvar rejection_reason : str | None
Inherited members
class CreativeApprovalStatus (*args, **kwds)-
Expand source code
class CreativeApprovalStatus(Enum): pending_review = 'pending_review' approved = 'approved' rejected = 'rejected'Create a collection of name/value pairs.
Example enumeration:
>>> class Color(Enum): ... RED = 1 ... BLUE = 2 ... GREEN = 3Access them by:
- attribute access::
>>> Color.RED <Color.RED: 1>- value lookup:
>>> Color(1) <Color.RED: 1>- name lookup:
>>> Color['RED'] <Color.RED: 1>Enumerations can be iterated over, and know how many members they have:
>>> len(Color) 3>>> list(Color) [<Color.RED: 1>, <Color.BLUE: 2>, <Color.GREEN: 3>]Methods can be added to enumerations, and members can have their own attributes – see the documentation for details.
Ancestors
- enum.Enum
Class variables
var approvedvar pending_reviewvar rejected
class CreativeFilters (**data: Any)-
Expand source code
class CreativeFilters(AdCPBaseModel): model_config = ConfigDict( extra='allow', ) accounts: Annotated[ list[account_ref.AccountReference] | None, Field( description='Filter creatives by owning accounts. Useful for agencies managing multiple client accounts.', min_length=1, ), ] = None assigned_to_packages: Annotated[ list[str] | None, Field( description='Filter creatives assigned to any of these packages. Sales-agent-specific — standalone creative agents SHOULD ignore this filter.', min_length=1, ), ] = None concept_ids: Annotated[ list[str] | None, Field( description='Filter by creative concept IDs. Concepts group related creatives across sizes and formats (e.g., Flashtalking concepts, Celtra campaign folders, CM360 creative groups).', min_length=1, ), ] = None created_after: Annotated[ AwareDatetime | None, Field(description='Filter creatives created after this date (ISO 8601)'), ] = None created_before: Annotated[ AwareDatetime | None, Field(description='Filter creatives created before this date (ISO 8601)'), ] = None creative_ids: Annotated[ list[str] | None, Field(description='Filter by specific creative IDs', max_length=100, min_length=1), ] = None format_ids: Annotated[ list[format_id.FormatId] | None, Field( description='Filter by structured format IDs. Returns creatives that match any of these formats.', min_length=1, ), ] = None has_served: Annotated[ bool | None, Field( description='When true, return only creatives that have served at least one impression. When false, return only creatives that have never served.' ), ] = None has_variables: Annotated[ bool | None, Field( description='When true, return only creatives with dynamic variables (DCO). When false, return only static creatives.' ), ] = None media_buy_ids: Annotated[ list[str] | None, Field( description='Filter creatives assigned to any of these media buys. Sales-agent-specific — standalone creative agents SHOULD ignore this filter.', min_length=1, ), ] = None name_contains: Annotated[ str | None, Field(description='Filter by creative names containing this text (case-insensitive)'), ] = None statuses: Annotated[ list[creative_status.CreativeStatus] | None, Field(description='Filter by creative approval statuses', min_length=1), ] = None tags: Annotated[ list[str] | None, Field(description='Filter by creative tags (all tags must match)', min_length=1), ] = None tags_any: Annotated[ list[str] | None, Field(description='Filter by creative tags (any tag must match)', min_length=1), ] = None unassigned: Annotated[ bool | None, Field( description='Filter for unassigned creatives when true, assigned creatives when false. Sales-agent-specific — standalone creative agents SHOULD ignore this filter.' ), ] = None updated_after: Annotated[ AwareDatetime | None, Field(description='Filter creatives last updated after this date (ISO 8601)'), ] = None updated_before: Annotated[ AwareDatetime | None, Field(description='Filter creatives last updated before this date (ISO 8601)'), ] = NoneBase model for AdCP types with spec-compliant serialization.
Defaults to
extra='ignore'so that unknown fields from newer spec versions are silently dropped rather than causing validation errors. Generated types whose schemas setadditionalProperties: trueoverride this withextra='allow'in their ownmodel_config. Consumers who want strict validation can override withextra='forbid'.Create a new model by parsing and validating input data from keyword arguments.
Raises [
ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.selfis explicitly positional-only to allowselfas a field name.Ancestors
- AdCPBaseModel
- pydantic.main.BaseModel
Class variables
var accounts : list[AccountReference] | Nonevar assigned_to_packages : list[str] | Nonevar concept_ids : list[str] | Nonevar created_after : pydantic.types.AwareDatetime | Nonevar created_before : pydantic.types.AwareDatetime | Nonevar creative_ids : list[str] | Nonevar format_ids : list[FormatId] | Nonevar has_served : bool | Nonevar has_variables : bool | Nonevar media_buy_ids : list[str] | Nonevar model_configvar name_contains : str | Nonevar statuses : list[CreativeStatus] | Nonevar unassigned : bool | Nonevar updated_after : pydantic.types.AwareDatetime | Nonevar updated_before : pydantic.types.AwareDatetime | None
Inherited members
class CreativeManifest (**data: Any)-
Expand source code
class CreativeManifest(AdCPBaseModel): model_config = ConfigDict( extra='allow', ) assets: Annotated[ dict[ Annotated[str, StringConstraints(pattern=r'^[a-z0-9_]+$')], image_asset.ImageAsset | video_asset.VideoAsset | audio_asset.AudioAsset | vast_asset.VastAsset | text_asset.TextAsset | url_asset.UrlAsset | html_asset.HtmlAsset | javascript_asset.JavascriptAsset | webhook_asset.WebhookAsset | css_asset.CssAsset | daast_asset.DaastAsset | markdown_asset.MarkdownAsset | brief_asset.BriefAsset | catalog_asset.CatalogAsset, ], Field( description="Map of asset IDs to actual asset content. Each key MUST match an asset_id from the format's assets array (e.g., 'banner_image', 'clickthrough_url', 'video_file', 'vast_tag'). The asset_id is the technical identifier used to match assets to format requirements.\n\nIMPORTANT: Full validation requires format context. The format defines what type each asset_id should be. Standalone schema validation only checks structural conformance — each asset must match at least one valid asset type schema." ), ] ext: ext_1.ExtensionObject | None = None format_id: Annotated[ format_id_1.FormatId, Field( description="Format identifier this manifest is for. Can be a template format (id only) or a deterministic format (id + dimensions/duration). For dimension-specific creatives, include width/height/unit in the format_id to create a unique identifier (e.g., {id: 'display_static', width: 300, height: 250, unit: 'px'})." ), ] provenance: Annotated[ provenance_1.Provenance | None, Field( description='Provenance metadata for this creative manifest. Serves as the default provenance for all assets in this manifest. An asset with its own provenance replaces this object entirely (no field-level merging).' ), ] = None rights: Annotated[ list[rights_constraint.RightsConstraint] | None, Field( description='Rights constraints attached to this creative. Each entry represents constraints from a single rights holder. A creative may combine multiple rights constraints (e.g., talent likeness + music license). For v1, rights constraints are informational metadata — the buyer/orchestrator manages creative lifecycle against these terms.' ), ] = NoneBase model for AdCP types with spec-compliant serialization.
Defaults to
extra='ignore'so that unknown fields from newer spec versions are silently dropped rather than causing validation errors. Generated types whose schemas setadditionalProperties: trueoverride this withextra='allow'in their ownmodel_config. Consumers who want strict validation can override withextra='forbid'.Create a new model by parsing and validating input data from keyword arguments.
Raises [
ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.selfis explicitly positional-only to allowselfas a field name.Ancestors
- AdCPBaseModel
- pydantic.main.BaseModel
Class variables
var assets : dict[str, ImageAsset | VideoAsset | AudioAsset | VastAsset | TextAsset | UrlAsset | HtmlAsset | JavascriptAsset | WebhookAsset | CssAsset | DaastAsset | MarkdownAsset | BriefAsset | CatalogAsset]var ext : ExtensionObject | Nonevar format_id : FormatIdvar model_configvar provenance : Provenance | Nonevar rights : list[RightsConstraint] | None
Inherited members
class CreativeStatus (*args, **kwds)-
Expand source code
class CreativeStatus(Enum): processing = 'processing' pending_review = 'pending_review' approved = 'approved' rejected = 'rejected' archived = 'archived'Create a collection of name/value pairs.
Example enumeration:
>>> class Color(Enum): ... RED = 1 ... BLUE = 2 ... GREEN = 3Access them by:
- attribute access::
>>> Color.RED <Color.RED: 1>- value lookup:
>>> Color(1) <Color.RED: 1>- name lookup:
>>> Color['RED'] <Color.RED: 1>Enumerations can be iterated over, and know how many members they have:
>>> len(Color) 3>>> list(Color) [<Color.RED: 1>, <Color.BLUE: 2>, <Color.GREEN: 3>]Methods can be added to enumerations, and members can have their own attributes – see the documentation for details.
Ancestors
- enum.Enum
Class variables
var approvedvar archivedvar pending_reviewvar processingvar rejected
class CreativeVariant (**data: Any)-
Expand source code
class CreativeVariant(DeliveryMetrics): generation_context: Annotated[ GenerationContext | None, Field( description='Input signals that triggered generation of this variant (Tier 3). Describes why the platform created this specific variant. Platforms should provide summarized or anonymized signals rather than raw user input. For web contexts, may include page topic or URL. For conversational contexts, an anonymized content signal. For search, query category or intent. When the content context is managed through AdCP content standards, reference the artifact directly via the artifact field.' ), ] = None manifest: Annotated[ creative_manifest.CreativeManifest | None, Field( description='The rendered creative manifest for this variant — the actual output that was served, not the input assets. Contains format_id and the resolved assets (specific headline, image, video, etc. the platform selected or generated). For Tier 2, shows which asset combination was picked. For Tier 3, contains the generated assets which may differ entirely from the input brand identity. Pass to preview_creative to re-render.' ), ] = None variant_id: Annotated[str, Field(description='Platform-assigned identifier for this variant')]Base model for AdCP types with spec-compliant serialization.
Defaults to
extra='ignore'so that unknown fields from newer spec versions are silently dropped rather than causing validation errors. Generated types whose schemas setadditionalProperties: trueoverride this withextra='allow'in their ownmodel_config. Consumers who want strict validation can override withextra='forbid'.Create a new model by parsing and validating input data from keyword arguments.
Raises [
ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.selfis explicitly positional-only to allowselfas a field name.Ancestors
- DeliveryMetrics
- AdCPBaseModel
- pydantic.main.BaseModel
Class variables
var generation_context : GenerationContext | Nonevar manifest : CreativeManifest | Nonevar model_configvar variant_id : str
Inherited members
class CursorStore (*args, **kwargs)-
Expand source code
@runtime_checkable class CursorStore(Protocol): """Protocol for persisting the feed cursor.""" async def load(self) -> str | None: """Load the saved cursor, or None if no cursor exists.""" ... async def save(self, cursor: str) -> None: """Save the current cursor.""" ...Protocol for persisting the feed cursor.
Ancestors
- typing.Protocol
- typing.Generic
Methods
async def load(self) ‑> str | None-
Expand source code
async def load(self) -> str | None: """Load the saved cursor, or None if no cursor exists.""" ...Load the saved cursor, or None if no cursor exists.
async def save(self, cursor: str) ‑> None-
Expand source code
async def save(self, cursor: str) -> None: """Save the current cursor.""" ...Save the current cursor.
class UrlDaastAsset (**data: Any)-
Expand source code
class DaastAsset1(AdCPBaseModel): model_config = ConfigDict( extra='allow', ) companion_ads: Annotated[ bool | None, Field(description='Whether companion display ads are included') ] = None daast_version: Annotated[ daast_version_1.DaastVersion | None, Field(description='DAAST specification version') ] = None delivery_type: Annotated[ Literal['url'], Field(description='Discriminator indicating DAAST is delivered via URL endpoint'), ] duration_ms: Annotated[ int | None, Field(description='Expected audio duration in milliseconds (if known)', ge=0) ] = None provenance: Annotated[ provenance_1.Provenance | None, Field( description='Provenance metadata for this asset, overrides manifest-level provenance' ), ] = None tracking_events: Annotated[ list[daast_tracking_event.DaastTrackingEvent] | None, Field(description='Tracking events supported by this DAAST tag'), ] = None transcript_url: Annotated[ AnyUrl | None, Field(description='URL to text transcript of the audio content') ] = None url: Annotated[AnyUrl, Field(description='URL endpoint that returns DAAST XML')]Base model for AdCP types with spec-compliant serialization.
Defaults to
extra='ignore'so that unknown fields from newer spec versions are silently dropped rather than causing validation errors. Generated types whose schemas setadditionalProperties: trueoverride this withextra='allow'in their ownmodel_config. Consumers who want strict validation can override withextra='forbid'.Create a new model by parsing and validating input data from keyword arguments.
Raises [
ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.selfis explicitly positional-only to allowselfas a field name.Ancestors
- AdCPBaseModel
- pydantic.main.BaseModel
Class variables
var companion_ads : bool | Nonevar daast_version : DaastVersion | Nonevar delivery_type : Literal['url']var duration_ms : int | Nonevar model_configvar provenance : Provenance | Nonevar tracking_events : list[DaastTrackingEvent] | Nonevar transcript_url : pydantic.networks.AnyUrl | Nonevar url : pydantic.networks.AnyUrl
Inherited members
class InlineDaastAsset (**data: Any)-
Expand source code
class DaastAsset2(AdCPBaseModel): model_config = ConfigDict( extra='allow', ) companion_ads: Annotated[ bool | None, Field(description='Whether companion display ads are included') ] = None content: Annotated[str, Field(description='Inline DAAST XML content')] daast_version: Annotated[ daast_version_1.DaastVersion | None, Field(description='DAAST specification version') ] = None delivery_type: Annotated[ Literal['inline'], Field(description='Discriminator indicating DAAST is delivered as inline XML content'), ] duration_ms: Annotated[ int | None, Field(description='Expected audio duration in milliseconds (if known)', ge=0) ] = None provenance: Annotated[ provenance_1.Provenance | None, Field( description='Provenance metadata for this asset, overrides manifest-level provenance' ), ] = None tracking_events: Annotated[ list[daast_tracking_event.DaastTrackingEvent] | None, Field(description='Tracking events supported by this DAAST tag'), ] = None transcript_url: Annotated[ AnyUrl | None, Field(description='URL to text transcript of the audio content') ] = NoneBase model for AdCP types with spec-compliant serialization.
Defaults to
extra='ignore'so that unknown fields from newer spec versions are silently dropped rather than causing validation errors. Generated types whose schemas setadditionalProperties: trueoverride this withextra='allow'in their ownmodel_config. Consumers who want strict validation can override withextra='forbid'.Create a new model by parsing and validating input data from keyword arguments.
Raises [
ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.selfis explicitly positional-only to allowselfas a field name.Ancestors
- AdCPBaseModel
- pydantic.main.BaseModel
Class variables
var companion_ads : bool | Nonevar content : strvar daast_version : DaastVersion | Nonevar delivery_type : Literal['inline']var duration_ms : int | Nonevar model_configvar provenance : Provenance | Nonevar tracking_events : list[DaastTrackingEvent] | Nonevar transcript_url : pydantic.networks.AnyUrl | None
Inherited members
class DateRange (**data: Any)-
Expand source code
class DateRange(AdCPBaseModel): model_config = ConfigDict( extra='allow', ) end: Annotated[date_aliased, Field(description='End date (inclusive), ISO 8601')] start: Annotated[date_aliased, Field(description='Start date (inclusive), ISO 8601')]Base model for AdCP types with spec-compliant serialization.
Defaults to
extra='ignore'so that unknown fields from newer spec versions are silently dropped rather than causing validation errors. Generated types whose schemas setadditionalProperties: trueoverride this withextra='allow'in their ownmodel_config. Consumers who want strict validation can override withextra='forbid'.Create a new model by parsing and validating input data from keyword arguments.
Raises [
ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.selfis explicitly positional-only to allowselfas a field name.Ancestors
- AdCPBaseModel
- pydantic.main.BaseModel
Class variables
var end : datetime.datevar model_configvar start : datetime.date
Inherited members
class DatetimeRange (**data: Any)-
Expand source code
class DatetimeRange(AdCPBaseModel): model_config = ConfigDict( extra='allow', ) end: Annotated[AwareDatetime, Field(description='End timestamp (inclusive), ISO 8601')] start: Annotated[AwareDatetime, Field(description='Start timestamp (inclusive), ISO 8601')]Base model for AdCP types with spec-compliant serialization.
Defaults to
extra='ignore'so that unknown fields from newer spec versions are silently dropped rather than causing validation errors. Generated types whose schemas setadditionalProperties: trueoverride this withextra='allow'in their ownmodel_config. Consumers who want strict validation can override withextra='forbid'.Create a new model by parsing and validating input data from keyword arguments.
Raises [
ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.selfis explicitly positional-only to allowselfas a field name.Ancestors
- AdCPBaseModel
- pydantic.main.BaseModel
Class variables
var end : pydantic.types.AwareDatetimevar model_configvar start : pydantic.types.AwareDatetime
Inherited members
class DeliveryStatus (*args, **kwds)-
Expand source code
class DeliveryStatus(Enum): delivering = 'delivering' not_delivering = 'not_delivering' completed = 'completed' budget_exhausted = 'budget_exhausted' flight_ended = 'flight_ended' goal_met = 'goal_met'Create a collection of name/value pairs.
Example enumeration:
>>> class Color(Enum): ... RED = 1 ... BLUE = 2 ... GREEN = 3Access them by:
- attribute access::
>>> Color.RED <Color.RED: 1>- value lookup:
>>> Color(1) <Color.RED: 1>- name lookup:
>>> Color['RED'] <Color.RED: 1>Enumerations can be iterated over, and know how many members they have:
>>> len(Color) 3>>> list(Color) [<Color.RED: 1>, <Color.BLUE: 2>, <Color.GREEN: 3>]Methods can be added to enumerations, and members can have their own attributes – see the documentation for details.
Ancestors
- enum.Enum
Class variables
var budget_exhaustedvar completedvar deliveringvar flight_endedvar goal_metvar not_delivering
class PlatformDeployment (**data: Any)-
Expand source code
class Deployment1(AdCPBaseModel): model_config = ConfigDict( extra='allow', ) account: Annotated[str | None, Field(description='Account identifier if applicable')] = None activation_key: Annotated[ activation_key_1.ActivationKey | None, Field( description='The key to use for targeting. Only present if is_live=true AND requester has access to this deployment.' ), ] = None deployed_at: Annotated[ AwareDatetime | None, Field(description='Timestamp when activation completed (if is_live=true)'), ] = None estimated_activation_duration_minutes: Annotated[ float | None, Field( description='Estimated time to activate if not live, or to complete activation if in progress', ge=0.0, ), ] = None is_live: Annotated[ bool, Field(description='Whether signal is currently active on this deployment') ] platform: Annotated[str, Field(description='Platform identifier for DSPs')] type: Annotated[ Literal['platform'], Field(description='Discriminator indicating this is a platform-based deployment'), ]Base model for AdCP types with spec-compliant serialization.
Defaults to
extra='ignore'so that unknown fields from newer spec versions are silently dropped rather than causing validation errors. Generated types whose schemas setadditionalProperties: trueoverride this withextra='allow'in their ownmodel_config. Consumers who want strict validation can override withextra='forbid'.Create a new model by parsing and validating input data from keyword arguments.
Raises [
ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.selfis explicitly positional-only to allowselfas a field name.Ancestors
- AdCPBaseModel
- pydantic.main.BaseModel
Class variables
var account : str | Nonevar activation_key : ActivationKey | Nonevar deployed_at : pydantic.types.AwareDatetime | Nonevar estimated_activation_duration_minutes : float | Nonevar is_live : boolvar model_configvar platform : strvar type : Literal['platform']
Inherited members
class AgentDeployment (**data: Any)-
Expand source code
class Deployment2(AdCPBaseModel): model_config = ConfigDict( extra='allow', ) account: Annotated[str | None, Field(description='Account identifier if applicable')] = None activation_key: Annotated[ activation_key_1.ActivationKey | None, Field( description='The key to use for targeting. Only present if is_live=true AND requester has access to this deployment.' ), ] = None agent_url: Annotated[AnyUrl, Field(description='URL identifying the deployment agent')] deployed_at: Annotated[ AwareDatetime | None, Field(description='Timestamp when activation completed (if is_live=true)'), ] = None estimated_activation_duration_minutes: Annotated[ float | None, Field( description='Estimated time to activate if not live, or to complete activation if in progress', ge=0.0, ), ] = None is_live: Annotated[ bool, Field(description='Whether signal is currently active on this deployment') ] type: Annotated[ Literal['agent'], Field(description='Discriminator indicating this is an agent URL-based deployment'), ]Base model for AdCP types with spec-compliant serialization.
Defaults to
extra='ignore'so that unknown fields from newer spec versions are silently dropped rather than causing validation errors. Generated types whose schemas setadditionalProperties: trueoverride this withextra='allow'in their ownmodel_config. Consumers who want strict validation can override withextra='forbid'.Create a new model by parsing and validating input data from keyword arguments.
Raises [
ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.selfis explicitly positional-only to allowselfas a field name.Ancestors
- AdCPBaseModel
- pydantic.main.BaseModel
Class variables
var account : str | Nonevar activation_key : ActivationKey | Nonevar agent_url : pydantic.networks.AnyUrlvar deployed_at : pydantic.types.AwareDatetime | Nonevar estimated_activation_duration_minutes : float | Nonevar is_live : boolvar model_configvar type : Literal['agent']
Inherited members
class PlatformDestination (**data: Any)-
Expand source code
class Destination1(AdCPBaseModel): model_config = ConfigDict( extra='allow', ) account: Annotated[ str | None, Field(description='Optional account identifier on the platform') ] = None platform: Annotated[ str, Field(description="Platform identifier for DSPs (e.g., 'the-trade-desk', 'amazon-dsp')"), ] type: Annotated[ Literal['platform'], Field(description='Discriminator indicating this is a platform-based deployment'), ]Base model for AdCP types with spec-compliant serialization.
Defaults to
extra='ignore'so that unknown fields from newer spec versions are silently dropped rather than causing validation errors. Generated types whose schemas setadditionalProperties: trueoverride this withextra='allow'in their ownmodel_config. Consumers who want strict validation can override withextra='forbid'.Create a new model by parsing and validating input data from keyword arguments.
Raises [
ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.selfis explicitly positional-only to allowselfas a field name.Ancestors
- AdCPBaseModel
- pydantic.main.BaseModel
Class variables
var account : str | Nonevar model_configvar platform : strvar type : Literal['platform']
Inherited members
class AgentDestination (**data: Any)-
Expand source code
class Destination2(AdCPBaseModel): model_config = ConfigDict( extra='allow', ) account: Annotated[ str | None, Field(description='Optional account identifier on the agent') ] = None agent_url: Annotated[ AnyUrl, Field(description='URL identifying the deployment agent (for sales agents, etc.)') ] type: Annotated[ Literal['agent'], Field(description='Discriminator indicating this is an agent URL-based deployment'), ]Base model for AdCP types with spec-compliant serialization.
Defaults to
extra='ignore'so that unknown fields from newer spec versions are silently dropped rather than causing validation errors. Generated types whose schemas setadditionalProperties: trueoverride this withextra='allow'in their ownmodel_config. Consumers who want strict validation can override withextra='forbid'.Create a new model by parsing and validating input data from keyword arguments.
Raises [
ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.selfis explicitly positional-only to allowselfas a field name.Ancestors
- AdCPBaseModel
- pydantic.main.BaseModel
Class variables
var account : str | Nonevar agent_url : pydantic.networks.AnyUrlvar model_configvar type : Literal['agent']
Inherited members
class DevicePlatform (*args, **kwds)-
Expand source code
class DevicePlatform(Enum): ios = 'ios' android = 'android' windows = 'windows' macos = 'macos' linux = 'linux' chromeos = 'chromeos' tvos = 'tvos' tizen = 'tizen' webos = 'webos' fire_os = 'fire_os' roku_os = 'roku_os' unknown = 'unknown'Create a collection of name/value pairs.
Example enumeration:
>>> class Color(Enum): ... RED = 1 ... BLUE = 2 ... GREEN = 3Access them by:
- attribute access::
>>> Color.RED <Color.RED: 1>- value lookup:
>>> Color(1) <Color.RED: 1>- name lookup:
>>> Color['RED'] <Color.RED: 1>Enumerations can be iterated over, and know how many members they have:
>>> len(Color) 3>>> list(Color) [<Color.RED: 1>, <Color.BLUE: 2>, <Color.GREEN: 3>]Methods can be added to enumerations, and members can have their own attributes – see the documentation for details.
Ancestors
- enum.Enum
Class variables
var androidvar chromeosvar fire_osvar iosvar linuxvar macosvar roku_osvar tizenvar tvosvar unknownvar webosvar windows
class DeviceType (*args, **kwds)-
Expand source code
class DeviceType(Enum): desktop = 'desktop' mobile = 'mobile' tablet = 'tablet' ctv = 'ctv' dooh = 'dooh' unknown = 'unknown'Create a collection of name/value pairs.
Example enumeration:
>>> class Color(Enum): ... RED = 1 ... BLUE = 2 ... GREEN = 3Access them by:
- attribute access::
>>> Color.RED <Color.RED: 1>- value lookup:
>>> Color(1) <Color.RED: 1>- name lookup:
>>> Color['RED'] <Color.RED: 1>Enumerations can be iterated over, and know how many members they have:
>>> len(Color) 3>>> list(Color) [<Color.RED: 1>, <Color.BLUE: 2>, <Color.GREEN: 3>]Methods can be added to enumerations, and members can have their own attributes – see the documentation for details.
Ancestors
- enum.Enum
Class variables
var ctvvar desktopvar doohvar mobilevar tabletvar unknown
class DomainLookupResult (**data: Any)-
Expand source code
class DomainLookupResult(RegistryBaseModel): domain: Annotated[str, Field(examples=["examplepub.com"])] authorized_agents: list[DomainAuthorizedAgent] sales_agents_claiming: list[SalesAgentClaim]Base model for registry API types.
Uses
extra='allow'so that new fields from the registry API are preserved rather than dropped. This differs from AdCPBaseModel which defaults toextra='ignore'for protocol types.Create a new model by parsing and validating input data from keyword arguments.
Raises [
ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.selfis explicitly positional-only to allowselfas a field name.Ancestors
- RegistryBaseModel
- pydantic.main.BaseModel
Class variables
var domain : strvar model_configvar sales_agents_claiming : list[SalesAgentClaim]
class Duration (**data: Any)-
Expand source code
class Duration(AdCPBaseModel): model_config = ConfigDict( extra='forbid', ) interval: Annotated[ int, Field(description="Number of time units. Must be 1 when unit is 'campaign'.", ge=1) ] unit: Annotated[ Unit, Field( description="Time unit. 'seconds' for sub-minute precision. 'campaign' spans the full campaign flight." ), ]Base model for AdCP types with spec-compliant serialization.
Defaults to
extra='ignore'so that unknown fields from newer spec versions are silently dropped rather than causing validation errors. Generated types whose schemas setadditionalProperties: trueoverride this withextra='allow'in their ownmodel_config. Consumers who want strict validation can override withextra='forbid'.Create a new model by parsing and validating input data from keyword arguments.
Raises [
ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.selfis explicitly positional-only to allowselfas a field name.Ancestors
- AdCPBaseModel
- pydantic.main.BaseModel
Class variables
var interval : intvar model_configvar unit : Unit
Inherited members
class Error (**data: Any)-
Expand source code
class Error(AdCPBaseModel): model_config = ConfigDict( extra='allow', ) code: Annotated[ str, Field( description='Error code for programmatic handling. Standard codes are defined in error-code.json and enable autonomous agent recovery. Sellers MAY use codes not in the standard vocabulary for platform-specific errors; agents MUST handle unknown codes gracefully by falling back to the recovery classification.', max_length=64, min_length=1, ), ] details: Annotated[ dict[str, Any] | None, Field(description='Additional task-specific error details') ] = None field: Annotated[ str | None, Field(description="Field path associated with the error (e.g., 'packages[0].targeting')"), ] = None message: Annotated[str, Field(description='Human-readable error message')] recovery: Annotated[ Recovery | None, Field( description='Agent recovery classification. transient: retry after delay (rate limit, service unavailable, timeout). correctable: fix the request and resend (invalid field, budget too low, creative rejected). terminal: requires human action (account suspended, payment required, account not found).' ), ] = None retry_after: Annotated[ float | None, Field( description='Seconds to wait before retrying the operation. Sellers MUST return values between 1 and 3600. Clients MUST clamp values outside this range.', ge=1.0, le=3600.0, ), ] = None suggestion: Annotated[str | None, Field(description='Suggested fix for the error')] = NoneBase model for AdCP types with spec-compliant serialization.
Defaults to
extra='ignore'so that unknown fields from newer spec versions are silently dropped rather than causing validation errors. Generated types whose schemas setadditionalProperties: trueoverride this withextra='allow'in their ownmodel_config. Consumers who want strict validation can override withextra='forbid'.Create a new model by parsing and validating input data from keyword arguments.
Raises [
ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.selfis explicitly positional-only to allowselfas a field name.Ancestors
- AdCPBaseModel
- pydantic.main.BaseModel
Class variables
var code : strvar details : dict[str, typing.Any] | Nonevar field : str | Nonevar message : strvar model_configvar recovery : Recovery | Nonevar retry_after : float | Nonevar suggestion : str | None
Inherited members
class ErrorCode (*args, **kwds)-
Expand source code
class ErrorCode(Enum): INVALID_REQUEST = 'INVALID_REQUEST' AUTH_REQUIRED = 'AUTH_REQUIRED' RATE_LIMITED = 'RATE_LIMITED' SERVICE_UNAVAILABLE = 'SERVICE_UNAVAILABLE' POLICY_VIOLATION = 'POLICY_VIOLATION' PRODUCT_NOT_FOUND = 'PRODUCT_NOT_FOUND' PRODUCT_UNAVAILABLE = 'PRODUCT_UNAVAILABLE' PROPOSAL_EXPIRED = 'PROPOSAL_EXPIRED' BUDGET_TOO_LOW = 'BUDGET_TOO_LOW' CREATIVE_REJECTED = 'CREATIVE_REJECTED' UNSUPPORTED_FEATURE = 'UNSUPPORTED_FEATURE' AUDIENCE_TOO_SMALL = 'AUDIENCE_TOO_SMALL' ACCOUNT_NOT_FOUND = 'ACCOUNT_NOT_FOUND' ACCOUNT_SETUP_REQUIRED = 'ACCOUNT_SETUP_REQUIRED' ACCOUNT_AMBIGUOUS = 'ACCOUNT_AMBIGUOUS' ACCOUNT_PAYMENT_REQUIRED = 'ACCOUNT_PAYMENT_REQUIRED' ACCOUNT_SUSPENDED = 'ACCOUNT_SUSPENDED' COMPLIANCE_UNSATISFIED = 'COMPLIANCE_UNSATISFIED' BUDGET_EXHAUSTED = 'BUDGET_EXHAUSTED' BUDGET_EXCEEDED = 'BUDGET_EXCEEDED' CONFLICT = 'CONFLICT' CREATIVE_DEADLINE_EXCEEDED = 'CREATIVE_DEADLINE_EXCEEDED' INVALID_STATE = 'INVALID_STATE' MEDIA_BUY_NOT_FOUND = 'MEDIA_BUY_NOT_FOUND' NOT_CANCELLABLE = 'NOT_CANCELLABLE' PACKAGE_NOT_FOUND = 'PACKAGE_NOT_FOUND' SESSION_NOT_FOUND = 'SESSION_NOT_FOUND' SESSION_TERMINATED = 'SESSION_TERMINATED' VALIDATION_ERROR = 'VALIDATION_ERROR' PRODUCT_EXPIRED = 'PRODUCT_EXPIRED' PROPOSAL_NOT_COMMITTED = 'PROPOSAL_NOT_COMMITTED' IO_REQUIRED = 'IO_REQUIRED'Create a collection of name/value pairs.
Example enumeration:
>>> class Color(Enum): ... RED = 1 ... BLUE = 2 ... GREEN = 3Access them by:
- attribute access::
>>> Color.RED <Color.RED: 1>- value lookup:
>>> Color(1) <Color.RED: 1>- name lookup:
>>> Color['RED'] <Color.RED: 1>Enumerations can be iterated over, and know how many members they have:
>>> len(Color) 3>>> list(Color) [<Color.RED: 1>, <Color.BLUE: 2>, <Color.GREEN: 3>]Methods can be added to enumerations, and members can have their own attributes – see the documentation for details.
Ancestors
- enum.Enum
Class variables
var ACCOUNT_AMBIGUOUSvar ACCOUNT_NOT_FOUNDvar ACCOUNT_PAYMENT_REQUIREDvar ACCOUNT_SETUP_REQUIREDvar ACCOUNT_SUSPENDEDvar AUDIENCE_TOO_SMALLvar AUTH_REQUIREDvar BUDGET_EXCEEDEDvar BUDGET_EXHAUSTEDvar BUDGET_TOO_LOWvar COMPLIANCE_UNSATISFIEDvar CONFLICTvar CREATIVE_DEADLINE_EXCEEDEDvar CREATIVE_REJECTEDvar INVALID_REQUESTvar INVALID_STATEvar IO_REQUIREDvar MEDIA_BUY_NOT_FOUNDvar NOT_CANCELLABLEvar PACKAGE_NOT_FOUNDvar POLICY_VIOLATIONvar PRODUCT_EXPIREDvar PRODUCT_NOT_FOUNDvar PRODUCT_UNAVAILABLEvar PROPOSAL_EXPIREDvar PROPOSAL_NOT_COMMITTEDvar RATE_LIMITEDvar SERVICE_UNAVAILABLEvar SESSION_NOT_FOUNDvar SESSION_TERMINATEDvar UNSUPPORTED_FEATUREvar VALIDATION_ERROR
class EventType (*args, **kwds)-
Expand source code
class EventType(Enum): page_view = 'page_view' view_content = 'view_content' select_content = 'select_content' select_item = 'select_item' search = 'search' share = 'share' add_to_cart = 'add_to_cart' remove_from_cart = 'remove_from_cart' viewed_cart = 'viewed_cart' add_to_wishlist = 'add_to_wishlist' initiate_checkout = 'initiate_checkout' add_payment_info = 'add_payment_info' purchase = 'purchase' refund = 'refund' lead = 'lead' qualify_lead = 'qualify_lead' close_convert_lead = 'close_convert_lead' disqualify_lead = 'disqualify_lead' complete_registration = 'complete_registration' subscribe = 'subscribe' start_trial = 'start_trial' app_install = 'app_install' app_launch = 'app_launch' contact = 'contact' schedule = 'schedule' donate = 'donate' submit_application = 'submit_application' custom = 'custom'Create a collection of name/value pairs.
Example enumeration:
>>> class Color(Enum): ... RED = 1 ... BLUE = 2 ... GREEN = 3Access them by:
- attribute access::
>>> Color.RED <Color.RED: 1>- value lookup:
>>> Color(1) <Color.RED: 1>- name lookup:
>>> Color['RED'] <Color.RED: 1>Enumerations can be iterated over, and know how many members they have:
>>> len(Color) 3>>> list(Color) [<Color.RED: 1>, <Color.BLUE: 2>, <Color.GREEN: 3>]Methods can be added to enumerations, and members can have their own attributes – see the documentation for details.
Ancestors
- enum.Enum
Class variables
var add_payment_infovar add_to_cartvar add_to_wishlistvar app_installvar app_launchvar close_convert_leadvar complete_registrationvar contactvar customvar disqualify_leadvar donatevar initiate_checkoutvar leadvar page_viewvar purchasevar qualify_leadvar refundvar remove_from_cartvar schedulevar searchvar select_contentvar select_itemvar start_trialvar submit_applicationvar subscribevar view_contentvar viewed_cart
class ExtensionObject (**data: Any)-
Expand source code
class ExtensionObject(AdCPBaseModel): model_config = ConfigDict( extra='allow', )Base model for AdCP types with spec-compliant serialization.
Defaults to
extra='ignore'so that unknown fields from newer spec versions are silently dropped rather than causing validation errors. Generated types whose schemas setadditionalProperties: trueoverride this withextra='allow'in their ownmodel_config. Consumers who want strict validation can override withextra='forbid'.Create a new model by parsing and validating input data from keyword arguments.
Raises [
ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.selfis explicitly positional-only to allowselfas a field name.Ancestors
- AdCPBaseModel
- pydantic.main.BaseModel
Class variables
var model_config
Inherited members
class FeatureResolver (capabilities: GetAdcpCapabilitiesResponse)-
Expand source code
class FeatureResolver: """Resolves feature support from a GetAdcpCapabilitiesResponse. Supports multiple feature namespaces: - Protocol support: ``"media_buy"`` checks ``supported_protocols`` - Extension support: ``"ext:scope3"`` checks ``extensions_supported`` - Targeting: ``"targeting.geo_countries"`` checks ``media_buy.execution.targeting`` - Media buy features: ``"audience_targeting"`` checks ``media_buy.features`` - Signals features: ``"catalog_signals"`` checks ``signals.features`` """ def __init__(self, capabilities: GetAdcpCapabilitiesResponse) -> None: self._caps = capabilities # Pre-compute the set of valid protocol names so supports() doesn't # need a runtime import on every call. from adcp.types.generated_poc.protocol.get_adcp_capabilities_response import ( SupportedProtocol, ) self._valid_protocols = {p.value for p in SupportedProtocol} self._declared_protocols = {p.value for p in capabilities.supported_protocols} @property def capabilities(self) -> GetAdcpCapabilitiesResponse: return self._caps def supports(self, feature: str) -> bool: """Check if a feature is supported.""" caps = self._caps # Extension check: "ext:scope3" if feature.startswith("ext:"): ext_name = feature[4:] if caps.extensions_supported is None: return False return any(item.root == ext_name for item in caps.extensions_supported) # Targeting check: "targeting.geo_countries" if feature.startswith("targeting."): attr_name = feature[len("targeting."):] if caps.media_buy is None or caps.media_buy.execution is None: return False targeting = caps.media_buy.execution.targeting if targeting is None: return False if attr_name not in type(targeting).model_fields: return False val = getattr(targeting, attr_name, None) # For bool fields, check truthiness. For object fields (like geo_metros), # presence means supported. return val is not None and val is not False # Protocol check: if the string is a known protocol name, resolve it # against supported_protocols and stop — don't fall through to features. if feature in self._declared_protocols: return True if feature in self._valid_protocols: return False # Media buy features check if caps.media_buy is not None and caps.media_buy.features is not None: if feature in type(caps.media_buy.features).model_fields: val = getattr(caps.media_buy.features, feature, None) if val is True: return True # Signals features check if caps.signals is not None and caps.signals.features is not None: if feature in type(caps.signals.features).model_fields: val = getattr(caps.signals.features, feature, None) if val is True: return True return False def require( self, *features: str, agent_id: str | None = None, agent_uri: str | None = None, ) -> None: """Assert that all listed features are supported. Args: *features: Feature identifiers to require. agent_id: Optional agent ID for error context. agent_uri: Optional agent URI for error context. Raises: ADCPFeatureUnsupportedError: If any features are not supported. """ unsupported = [f for f in features if not self.supports(f)] if not unsupported: return declared = self.get_declared_features() raise ADCPFeatureUnsupportedError( unsupported_features=unsupported, declared_features=declared, agent_id=agent_id, agent_uri=agent_uri, ) def get_declared_features(self) -> list[str]: """Collect all features the response declares as supported.""" caps = self._caps declared: list[str] = [] # Supported protocols for p in caps.supported_protocols: declared.append(p.value) # Media buy features if caps.media_buy is not None and caps.media_buy.features is not None: for field_name in type(caps.media_buy.features).model_fields: if getattr(caps.media_buy.features, field_name, None) is True: declared.append(field_name) # Signals features if caps.signals is not None and caps.signals.features is not None: for field_name in type(caps.signals.features).model_fields: if getattr(caps.signals.features, field_name, None) is True: declared.append(field_name) # Targeting features if caps.media_buy is not None and caps.media_buy.execution is not None: targeting = caps.media_buy.execution.targeting if targeting is not None: for field_name in type(targeting).model_fields: val = getattr(targeting, field_name, None) if val is not None and val is not False: declared.append(f"targeting.{field_name}") # Extensions if caps.extensions_supported is not None: for item in caps.extensions_supported: declared.append(f"ext:{item.root}") return declaredResolves feature support from a GetAdcpCapabilitiesResponse.
Supports multiple feature namespaces:
- Protocol support:
"media_buy"checkssupported_protocols - Extension support:
"ext:scope3"checksextensions_supported - Targeting:
"targeting.geo_countries"checksmedia_buy.execution.targeting - Media buy features:
"audience_targeting"checksmedia_buy.features - Signals features:
"catalog_signals"checkssignals.features
Instance variables
prop capabilities : GetAdcpCapabilitiesResponse-
Expand source code
@property def capabilities(self) -> GetAdcpCapabilitiesResponse: return self._caps
Methods
def get_declared_features(self) ‑> list[str]-
Expand source code
def get_declared_features(self) -> list[str]: """Collect all features the response declares as supported.""" caps = self._caps declared: list[str] = [] # Supported protocols for p in caps.supported_protocols: declared.append(p.value) # Media buy features if caps.media_buy is not None and caps.media_buy.features is not None: for field_name in type(caps.media_buy.features).model_fields: if getattr(caps.media_buy.features, field_name, None) is True: declared.append(field_name) # Signals features if caps.signals is not None and caps.signals.features is not None: for field_name in type(caps.signals.features).model_fields: if getattr(caps.signals.features, field_name, None) is True: declared.append(field_name) # Targeting features if caps.media_buy is not None and caps.media_buy.execution is not None: targeting = caps.media_buy.execution.targeting if targeting is not None: for field_name in type(targeting).model_fields: val = getattr(targeting, field_name, None) if val is not None and val is not False: declared.append(f"targeting.{field_name}") # Extensions if caps.extensions_supported is not None: for item in caps.extensions_supported: declared.append(f"ext:{item.root}") return declaredCollect all features the response declares as supported.
def require(self, *features: str, agent_id: str | None = None, agent_uri: str | None = None) ‑> None-
Expand source code
def require( self, *features: str, agent_id: str | None = None, agent_uri: str | None = None, ) -> None: """Assert that all listed features are supported. Args: *features: Feature identifiers to require. agent_id: Optional agent ID for error context. agent_uri: Optional agent URI for error context. Raises: ADCPFeatureUnsupportedError: If any features are not supported. """ unsupported = [f for f in features if not self.supports(f)] if not unsupported: return declared = self.get_declared_features() raise ADCPFeatureUnsupportedError( unsupported_features=unsupported, declared_features=declared, agent_id=agent_id, agent_uri=agent_uri, )Assert that all listed features are supported.
Args
*features- Feature identifiers to require.
agent_id- Optional agent ID for error context.
agent_uri- Optional agent URI for error context.
Raises
ADCPFeatureUnsupportedError- If any features are not supported.
def supports(self, feature: str) ‑> bool-
Expand source code
def supports(self, feature: str) -> bool: """Check if a feature is supported.""" caps = self._caps # Extension check: "ext:scope3" if feature.startswith("ext:"): ext_name = feature[4:] if caps.extensions_supported is None: return False return any(item.root == ext_name for item in caps.extensions_supported) # Targeting check: "targeting.geo_countries" if feature.startswith("targeting."): attr_name = feature[len("targeting."):] if caps.media_buy is None or caps.media_buy.execution is None: return False targeting = caps.media_buy.execution.targeting if targeting is None: return False if attr_name not in type(targeting).model_fields: return False val = getattr(targeting, attr_name, None) # For bool fields, check truthiness. For object fields (like geo_metros), # presence means supported. return val is not None and val is not False # Protocol check: if the string is a known protocol name, resolve it # against supported_protocols and stop — don't fall through to features. if feature in self._declared_protocols: return True if feature in self._valid_protocols: return False # Media buy features check if caps.media_buy is not None and caps.media_buy.features is not None: if feature in type(caps.media_buy.features).model_fields: val = getattr(caps.media_buy.features, feature, None) if val is True: return True # Signals features check if caps.signals is not None and caps.signals.features is not None: if feature in type(caps.signals.features).model_fields: val = getattr(caps.signals.features, feature, None) if val is True: return True return FalseCheck if a feature is supported.
- Protocol support:
class FederatedAgentWithDetails (**data: Any)-
Expand source code
class FederatedAgentWithDetails(RegistryBaseModel): url: str name: str type: AgentType protocol: AgentProtocol | None = None description: str | None = None mcp_endpoint: str | None = None contact: AgentDetailedContact | None = None added_date: str | None = None source: AgentSource | None = None member: AgentMember | None = None discovered_from: AgentDiscoveredFrom | None = None health: AgentHealth | None = None stats: AgentStats | None = None capabilities: AgentCapabilities | None = None compliance: AgentCompliance | None = None publisher_domains: list[str] | None = None property_summary: PropertySummary | None = NoneBase model for registry API types.
Uses
extra='allow'so that new fields from the registry API are preserved rather than dropped. This differs from AdCPBaseModel which defaults toextra='ignore'for protocol types.Create a new model by parsing and validating input data from keyword arguments.
Raises [
ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.selfis explicitly positional-only to allowselfas a field name.Ancestors
- RegistryBaseModel
- pydantic.main.BaseModel
Class variables
var added_date : str | Nonevar capabilities : AgentCapabilities | Nonevar compliance : AgentCompliance | Nonevar contact : AgentDetailedContact | Nonevar description : str | Nonevar discovered_from : AgentDiscoveredFrom | Nonevar health : AgentHealth | Nonevar mcp_endpoint : str | Nonevar member : AgentMember | Nonevar model_configvar name : strvar property_summary : PropertySummary | Nonevar protocol : AgentProtocol | Nonevar publisher_domains : list[str] | Nonevar source : AgentSource | Nonevar stats : AgentStats | Nonevar type : AgentTypevar url : str
class FederatedPublisher (**data: Any)-
Expand source code
class FederatedPublisher(RegistryBaseModel): domain: str source: AgentSource | None = None member: AgentMember | None = None agent_count: int | None = None last_validated: str | None = None discovered_from: PublisherDiscoveredFrom | None = None has_valid_adagents: bool | None = None discovered_at: str | None = NoneBase model for registry API types.
Uses
extra='allow'so that new fields from the registry API are preserved rather than dropped. This differs from AdCPBaseModel which defaults toextra='ignore'for protocol types.Create a new model by parsing and validating input data from keyword arguments.
Raises [
ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.selfis explicitly positional-only to allowselfas a field name.Ancestors
- RegistryBaseModel
- pydantic.main.BaseModel
Class variables
var agent_count : int | Nonevar discovered_at : str | Nonevar discovered_from : PublisherDiscoveredFrom | Nonevar domain : strvar has_valid_adagents : bool | Nonevar last_validated : str | Nonevar member : AgentMember | Nonevar model_configvar source : AgentSource | None
class FeedEvent (**data: Any)-
Expand source code
class FeedEvent(RegistryBaseModel): """Single event from the registry change feed.""" event_id: str event_type: str entity_type: str entity_id: str payload: dict[str, Any] = Field(default_factory=dict) actor: str created_at: strSingle event from the registry change feed.
Create a new model by parsing and validating input data from keyword arguments.
Raises [
ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.selfis explicitly positional-only to allowselfas a field name.Ancestors
- RegistryBaseModel
- pydantic.main.BaseModel
Class variables
var actor : strvar created_at : strvar entity_id : strvar entity_type : strvar event_id : strvar event_type : strvar model_configvar payload : dict[str, typing.Any]
class FeedFormat (*args, **kwds)-
Expand source code
class FeedFormat(Enum): google_merchant_center = 'google_merchant_center' facebook_catalog = 'facebook_catalog' shopify = 'shopify' linkedin_jobs = 'linkedin_jobs' custom = 'custom'Create a collection of name/value pairs.
Example enumeration:
>>> class Color(Enum): ... RED = 1 ... BLUE = 2 ... GREEN = 3Access them by:
- attribute access::
>>> Color.RED <Color.RED: 1>- value lookup:
>>> Color(1) <Color.RED: 1>- name lookup:
>>> Color['RED'] <Color.RED: 1>Enumerations can be iterated over, and know how many members they have:
>>> len(Color) 3>>> list(Color) [<Color.RED: 1>, <Color.BLUE: 2>, <Color.GREEN: 3>]Methods can be added to enumerations, and members can have their own attributes – see the documentation for details.
Ancestors
- enum.Enum
Class variables
var customvar facebook_catalogvar google_merchant_centervar linkedin_jobsvar shopify
class FeedPage (**data: Any)-
Expand source code
class FeedPage(RegistryBaseModel): """Page of events from the registry change feed.""" events: list[FeedEvent] = Field(default_factory=list) cursor: str | None = None has_more: boolPage of events from the registry change feed.
Create a new model by parsing and validating input data from keyword arguments.
Raises [
ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.selfis explicitly positional-only to allowselfas a field name.Ancestors
- RegistryBaseModel
- pydantic.main.BaseModel
Class variables
var cursor : str | Nonevar events : list[FeedEvent]var has_more : boolvar model_config
class FileCursorStore (path: str | Path = '.adcp-sync-cursor.json')-
Expand source code
class FileCursorStore: """Default cursor store using a local JSON file. Args: path: Path to the cursor file. Defaults to .adcp-sync-cursor.json """ def __init__(self, path: str | Path = ".adcp-sync-cursor.json") -> None: self._path = Path(path) async def load(self) -> str | None: try: data = json.loads(self._path.read_text()) return data.get("cursor") # type: ignore[no-any-return] except (FileNotFoundError, json.JSONDecodeError, KeyError): return None async def save(self, cursor: str) -> None: temp = self._path.with_suffix(".tmp") temp.write_text(json.dumps({"cursor": cursor})) temp.replace(self._path) # Atomic renameDefault cursor store using a local JSON file.
Args
path- Path to the cursor file. Defaults to .adcp-sync-cursor.json
Methods
async def load(self) ‑> str | None-
Expand source code
async def load(self) -> str | None: try: data = json.loads(self._path.read_text()) return data.get("cursor") # type: ignore[no-any-return] except (FileNotFoundError, json.JSONDecodeError, KeyError): return None async def save(self, cursor: str) ‑> None-
Expand source code
async def save(self, cursor: str) -> None: temp = self._path.with_suffix(".tmp") temp.write_text(json.dumps({"cursor": cursor})) temp.replace(self._path) # Atomic rename
class FlatRatePricingOption (**data: Any)-
Expand source code
class FlatRatePricingOption(AdCPBaseModel): model_config = ConfigDict( extra='allow', ) currency: Annotated[ str, Field( description='ISO 4217 currency code', examples=['USD', 'EUR', 'GBP', 'JPY'], pattern='^[A-Z]{3}$', ), ] eligible_adjustments: Annotated[ list[adjustment_kind.PriceAdjustmentKind] | None, Field( description='Adjustment kinds applicable to this pricing option. Tells buyer agents which adjustments are available before negotiation. When absent, no adjustments are pre-declared — the buyer should check price_breakdown if present.' ), ] = None fixed_price: Annotated[ float | None, Field( description='Flat rate cost. If present, this is fixed pricing. If absent, auction-based.', ge=0.0, ), ] = None floor_price: Annotated[ float | None, Field( description='Minimum acceptable bid for auction pricing (mutually exclusive with fixed_price). Bids below this value will be rejected.', ge=0.0, ), ] = None min_spend_per_package: Annotated[ float | None, Field( description='Minimum spend requirement per package using this pricing option, in the specified currency', ge=0.0, ), ] = None parameters: Annotated[ Parameters | None, Field( description='DOOH inventory allocation parameters. Sponsorship and takeover flat_rate options omit this field entirely — only include for digital out-of-home inventory.', title='DoohParameters', ), ] = None price_breakdown: Annotated[ price_breakdown_1.PriceBreakdown | None, Field( description='Breakdown of how fixed_price was derived from the list (rate card) price. Only meaningful when fixed_price is present.' ), ] = None price_guidance: Annotated[ price_guidance_1.PriceGuidance | None, Field(description='Optional pricing guidance for auction-based bidding'), ] = None pricing_model: Annotated[ Literal['flat_rate'], Field(description='Fixed cost regardless of delivery volume') ] pricing_option_id: Annotated[ str, Field(description='Unique identifier for this pricing option within the product') ]Base model for AdCP types with spec-compliant serialization.
Defaults to
extra='ignore'so that unknown fields from newer spec versions are silently dropped rather than causing validation errors. Generated types whose schemas setadditionalProperties: trueoverride this withextra='allow'in their ownmodel_config. Consumers who want strict validation can override withextra='forbid'.Create a new model by parsing and validating input data from keyword arguments.
Raises [
ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.selfis explicitly positional-only to allowselfas a field name.Ancestors
- AdCPBaseModel
- pydantic.main.BaseModel
Class variables
var currency : strvar eligible_adjustments : list[PriceAdjustmentKind] | Nonevar fixed_price : float | Nonevar floor_price : float | Nonevar min_spend_per_package : float | Nonevar model_configvar parameters : Parameters | Nonevar price_breakdown : PriceBreakdown | Nonevar price_guidance : PriceGuidance | Nonevar pricing_model : Literal['flat_rate']var pricing_option_id : str
Inherited members
class Format (**data: Any)-
Expand source code
class Format(AdCPBaseModel): model_config = ConfigDict( extra='allow', ) accepts_parameters: Annotated[ list[format_id_parameter.FormatIdParameter] | None, Field( description='List of parameters this format accepts in format_id. Template formats define which parameters (dimensions, duration, etc.) can be specified when instantiating the format. Empty or omitted means this is a concrete format with fixed parameters.' ), ] = None accessibility: Annotated[ Accessibility | None, Field( description='Accessibility posture of this format. Declares the WCAG conformance level that creatives produced by this format will meet.' ), ] = None assets: Annotated[ list[ Assets | Assets5 | Assets6 | Assets7 | Assets8 | Assets9 | Assets10 | Assets11 | Assets12 | Assets13 | Assets14 | Assets15 | Assets16 | Assets17 | Assets18 ] | None, Field( description="Array of all assets supported for this format. Each asset is identified by its asset_id, which must be used as the key in creative manifests. Use the 'required' boolean on each asset to indicate whether it's mandatory." ), ] = None delivery: Annotated[ dict[str, Any] | None, Field(description='Delivery method specifications (e.g., hosted, VAST, third-party tags)'), ] = None description: Annotated[ str | None, Field( description='Plain text explanation of what this format does and what assets it requires' ), ] = None disclosure_capabilities: Annotated[ list[DisclosureCapability] | None, Field( description='Structured disclosure capabilities per position with persistence modes. Declares which persistence behaviors each disclosure position supports, enabling persistence-aware matching against provenance render guidance and brief requirements. When present, supersedes supported_disclosure_positions for persistence-aware queries. The flat supported_disclosure_positions field is retained for backward compatibility. Each position MUST appear at most once; validators and agents SHOULD reject duplicates.', min_length=1, ), ] = None example_url: Annotated[ AnyUrl | None, Field( description='Optional URL to showcase page with examples and interactive demos of this format' ), ] = None format_card: Annotated[ FormatCard | None, Field( description='Optional standard visual card (300x400px) for displaying this format in user interfaces. Can be rendered via preview_creative or pre-generated.' ), ] = None format_card_detailed: Annotated[ FormatCardDetailed | None, Field( description='Optional detailed card with carousel and full specifications. Provides rich format documentation similar to ad spec pages.' ), ] = None format_id: Annotated[ format_id_1.FormatId, Field(description='Structured format identifier with agent URL and format name'), ] input_format_ids: Annotated[ list[format_id_1.FormatId] | None, Field( description='Array of format IDs this format accepts as input creative manifests. When present, indicates this format can take existing creatives in these formats as input. Omit for formats that work from raw assets (images, text, etc.) rather than existing creatives.' ), ] = None name: Annotated[str, Field(description='Human-readable format name')] output_format_ids: Annotated[ list[format_id_1.FormatId] | None, Field( description='Array of format IDs that this format can produce as output. When present, indicates this format can build creatives in these output formats (e.g., a multi-publisher template format might produce standard display formats across many publishers). Omit for formats that produce a single fixed output (the format itself).' ), ] = None renders: Annotated[ list[Renders | Renders1] | None, Field( description='Specification of rendered pieces for this format. Most formats produce a single render. Companion ad formats (video + banner), adaptive formats, and multi-placement formats produce multiple renders. Each render specifies its role and dimensions.', min_length=1, ), ] = None reported_metrics: Annotated[ list[available_metric.AvailableMetric] | None, Field( description='Metrics this format can produce in delivery reporting. Buyers receive the intersection of format reported_metrics and product available_metrics. If omitted, the format defers entirely to product-level metric declarations.', min_length=1, ), ] = None supported_disclosure_positions: Annotated[ list[disclosure_position.DisclosurePosition] | None, Field( description='Disclosure positions this format can render. Buyers use this to determine whether a format can satisfy their compliance requirements before submitting a creative. When omitted, the format makes no disclosure rendering guarantees — creative agents SHOULD treat this as incompatible with briefs that require specific disclosure positions. Values correspond to positions on creative-brief.json required_disclosures.', min_length=1, ), ] = None supported_macros: Annotated[ list[universal_macro.UniversalMacro | str] | None, Field( description='List of universal macros supported by this format (e.g., MEDIA_BUY_ID, CACHEBUSTER, DEVICE_ID). Used for validation and developer tooling. See docs/creative/universal-macros.mdx for full documentation.' ), ] = NoneBase model for AdCP types with spec-compliant serialization.
Defaults to
extra='ignore'so that unknown fields from newer spec versions are silently dropped rather than causing validation errors. Generated types whose schemas setadditionalProperties: trueoverride this withextra='allow'in their ownmodel_config. Consumers who want strict validation can override withextra='forbid'.Create a new model by parsing and validating input data from keyword arguments.
Raises [
ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.selfis explicitly positional-only to allowselfas a field name.Ancestors
- AdCPBaseModel
- pydantic.main.BaseModel
Class variables
var accepts_parameters : list[FormatIdParameter] | Nonevar accessibility : Accessibility | Nonevar assets : list[Assets | Assets5 | Assets6 | Assets7 | Assets8 | Assets9 | Assets10 | Assets11 | Assets12 | Assets13 | Assets14 | Assets15 | Assets16 | Assets17 | Assets18] | Nonevar delivery : dict[str, typing.Any] | Nonevar description : str | Nonevar disclosure_capabilities : list[DisclosureCapability] | Nonevar example_url : pydantic.networks.AnyUrl | Nonevar format_card : FormatCard | Nonevar format_card_detailed : FormatCardDetailed | Nonevar format_id : FormatIdvar input_format_ids : list[FormatId] | Nonevar model_configvar name : strvar output_format_ids : list[FormatId] | Nonevar renders : list[Renders | Renders1] | Nonevar reported_metrics : list[AvailableMetric] | Nonevar supported_disclosure_positions : list[DisclosurePosition] | Nonevar supported_macros : list[UniversalMacro | str] | None
Inherited members
class FormatId (**data: Any)-
Expand source code
class FormatId(AdCPBaseModel): model_config = ConfigDict( extra='allow', ) agent_url: Annotated[ AnyUrl, Field( description="URL of the agent that defines this format (e.g., 'https://creatives.adcontextprotocol.org' for standard formats, or 'https://publisher.com/.well-known/adcp/sales' for custom formats)" ), ] duration_ms: Annotated[ float | None, Field( description='Duration in milliseconds for time-based formats (video, audio). When specified, creates a parameterized format ID. Omit to reference a template format without parameters.', ge=1.0, ), ] = None height: Annotated[ int | None, Field( description='Height in pixels for visual formats. When specified, width must also be specified. Both fields together create a parameterized format ID for dimension-specific variants.', ge=1, ), ] = None id: Annotated[ str, Field( description="Format identifier within the agent's namespace (e.g., 'display_static', 'video_hosted', 'audio_standard'). When used alone, references a template format. When combined with dimension/duration fields, creates a parameterized format ID for a specific variant.", pattern='^[a-zA-Z0-9_-]+$', ), ] width: Annotated[ int | None, Field( description='Width in pixels for visual formats. When specified, height must also be specified. Both fields together create a parameterized format ID for dimension-specific variants.', ge=1, ), ] = NoneBase model for AdCP types with spec-compliant serialization.
Defaults to
extra='ignore'so that unknown fields from newer spec versions are silently dropped rather than causing validation errors. Generated types whose schemas setadditionalProperties: trueoverride this withextra='allow'in their ownmodel_config. Consumers who want strict validation can override withextra='forbid'.Create a new model by parsing and validating input data from keyword arguments.
Raises [
ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.selfis explicitly positional-only to allowselfas a field name.Ancestors
- AdCPBaseModel
- pydantic.main.BaseModel
Class variables
var agent_url : pydantic.networks.AnyUrlvar duration_ms : float | Nonevar height : int | Nonevar id : strvar model_configvar width : int | None
Inherited members
class GetAccountFinancialsRequest (**data: Any)-
Expand source code
class GetAccountFinancialsRequest(AdCPBaseModel): model_config = ConfigDict( extra='allow', ) account: Annotated[ account_ref.AccountReference, Field(description='Account to query financials for. Must be an operator-billed account.'), ] context: context_1.ContextObject | None = None ext: ext_1.ExtensionObject | None = None period: Annotated[ date_range.DateRange | None, Field( description='Date range for the spend summary. Defaults to the current billing cycle if omitted.' ), ] = NoneBase model for AdCP types with spec-compliant serialization.
Defaults to
extra='ignore'so that unknown fields from newer spec versions are silently dropped rather than causing validation errors. Generated types whose schemas setadditionalProperties: trueoverride this withextra='allow'in their ownmodel_config. Consumers who want strict validation can override withextra='forbid'.Create a new model by parsing and validating input data from keyword arguments.
Raises [
ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.selfis explicitly positional-only to allowselfas a field name.Ancestors
- AdCPBaseModel
- pydantic.main.BaseModel
Class variables
var account : AccountReferencevar context : ContextObject | Nonevar ext : ExtensionObject | Nonevar model_configvar period : DateRange | None
Inherited members
class GetAccountFinancialsSuccessResponse (**data: Any)-
Expand source code
class GetAccountFinancialsResponse1(AdCPBaseModel): model_config = ConfigDict( extra='allow', ) account: Annotated[ account_ref.AccountReference, Field(description='Account reference, echoed from the request'), ] balance: Annotated[ Balance | None, Field(description='Prepay balance. Present for prepay accounts.') ] = None context: context_1.ContextObject | None = None credit: Annotated[ Credit | None, Field( description='Credit status. Present for credit-based accounts (payment_terms like net_30).' ), ] = None currency: Annotated[ str, Field( description='ISO 4217 currency code for all monetary amounts in this response', pattern='^[A-Z]{3}$', ), ] ext: ext_1.ExtensionObject | None = None invoices: Annotated[ list[Invoice] | None, Field(description='Recent invoices. Sellers may limit the number returned.'), ] = None payment_status: Annotated[ PaymentStatus | None, Field( description='Overall payment status. current: all obligations met. past_due: one or more invoices overdue. suspended: account suspended due to payment issues.' ), ] = None payment_terms: Annotated[ PaymentTerms | None, Field(description='Payment terms in effect for this account') ] = None period: Annotated[ date_range.DateRange, Field( description='The actual period covered by spend data. May differ from the requested period if the seller adjusts to billing cycle boundaries.' ), ] spend: Annotated[Spend | None, Field(description='Spend summary for the period')] = None timezone: Annotated[ str, Field( description="IANA timezone of the seller's billing day boundaries (e.g., 'America/New_York'). All dates in this response — period, invoice periods, due dates — are calendar dates in this timezone. Buyers in a different timezone should expect spend boundaries to differ from their own calendar day." ), ]Base model for AdCP types with spec-compliant serialization.
Defaults to
extra='ignore'so that unknown fields from newer spec versions are silently dropped rather than causing validation errors. Generated types whose schemas setadditionalProperties: trueoverride this withextra='allow'in their ownmodel_config. Consumers who want strict validation can override withextra='forbid'.Create a new model by parsing and validating input data from keyword arguments.
Raises [
ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.selfis explicitly positional-only to allowselfas a field name.Ancestors
- AdCPBaseModel
- pydantic.main.BaseModel
Class variables
var account : AccountReferencevar balance : Balance | Nonevar context : ContextObject | Nonevar credit : Credit | Nonevar currency : strvar ext : ExtensionObject | Nonevar invoices : list[Invoice] | Nonevar model_configvar payment_status : PaymentStatus | Nonevar payment_terms : PaymentTerms | Nonevar period : DateRangevar spend : Spend | Nonevar timezone : str
Inherited members
class GetAccountFinancialsErrorResponse (**data: Any)-
Expand source code
class GetAccountFinancialsResponse2(AdCPBaseModel): model_config = ConfigDict( extra='allow', ) context: context_1.ContextObject | None = None errors: Annotated[list[error.Error], Field(description='Operation-level errors', min_length=1)] ext: ext_1.ExtensionObject | None = NoneBase model for AdCP types with spec-compliant serialization.
Defaults to
extra='ignore'so that unknown fields from newer spec versions are silently dropped rather than causing validation errors. Generated types whose schemas setadditionalProperties: trueoverride this withextra='allow'in their ownmodel_config. Consumers who want strict validation can override withextra='forbid'.Create a new model by parsing and validating input data from keyword arguments.
Raises [
ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.selfis explicitly positional-only to allowselfas a field name.Ancestors
- AdCPBaseModel
- pydantic.main.BaseModel
Class variables
var context : ContextObject | Nonevar errors : list[Error]var ext : ExtensionObject | Nonevar model_config
Inherited members
class GetBrandIdentityRequest (**data: Any)-
Expand source code
class GetBrandIdentityRequest(AdCPBaseModel): model_config = ConfigDict( extra='allow', ) brand_id: Annotated[str, Field(description='Brand identifier from brand.json brands array')] context: context_1.ContextObject | None = None ext: ext_1.ExtensionObject | None = None fields: Annotated[ list[FieldModel] | None, Field( description='Optional identity sections to include in the response. When omitted, all sections the caller is authorized to see are returned. Core fields (brand_id, house, names) are always returned and do not need to be requested.', min_length=1, ), ] = None use_case: Annotated[ str | None, Field( description="Intended use case, so the agent can tailor the response. A 'voice_synthesis' use case returns voice configs; a 'likeness' use case returns high-res photos and appearance guidelines." ), ] = NoneBase model for AdCP types with spec-compliant serialization.
Defaults to
extra='ignore'so that unknown fields from newer spec versions are silently dropped rather than causing validation errors. Generated types whose schemas setadditionalProperties: trueoverride this withextra='allow'in their ownmodel_config. Consumers who want strict validation can override withextra='forbid'.Create a new model by parsing and validating input data from keyword arguments.
Raises [
ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.selfis explicitly positional-only to allowselfas a field name.Ancestors
- AdCPBaseModel
- pydantic.main.BaseModel
Class variables
var brand_id : strvar context : ContextObject | Nonevar ext : ExtensionObject | Nonevar fields : list[FieldModel] | Nonevar model_configvar use_case : str | None
Inherited members
class GetBrandIdentitySuccessResponse (**data: Any)-
Expand source code
class GetBrandIdentityResponse1(AdCPBaseModel): model_config = ConfigDict( extra='allow', ) assets: Annotated[ list[Asset] | None, Field( description='Available brand assets (images, audio, video). Authorized callers only. Shape matches brand.json asset definition.' ), ] = None available_fields: Annotated[ list[AvailableField] | None, Field( description='Fields available but not returned in this response due to authorization level. Tells the caller what they would gain by linking their account via sync_accounts. Values match the request fields enum.' ), ] = None brand_id: Annotated[str, Field(description='Brand identifier')] colors: Annotated[ Colors | None, Field( description='Brand color palette. Each role accepts a single hex color or an array of hex colors. Shape matches brand.json colors definition.' ), ] = None context: context_1.ContextObject | None = None description: Annotated[str | None, Field(description='Brand description')] = None ext: ext_1.ExtensionObject | None = None fonts: Annotated[ Fonts | None, Field(description='Brand typography. Shape matches brand.json fonts definition.'), ] = None house: Annotated[ House, Field( description='The house (corporate entity) this brand belongs to. Always returned regardless of authorization level.' ), ] industries: Annotated[ list[str] | None, Field(description='Brand industries.', min_length=1) ] = None keller_type: Annotated[ KellerType | None, Field( description='Brand architecture type: master (primary brand of house), sub_brand (carries parent name), endorsed (independent identity backed by parent), independent (operates separately)' ), ] = None logos: Annotated[ list[Logo] | None, Field( description='Brand logos. Public callers get standard logos; authorized callers also receive high-res variants. Shape matches brand.json logo definition.' ), ] = None names: Annotated[ list[dict[str, str]], Field( description="Localized brand names with BCP 47 locale code keys (e.g., 'en_US', 'fr_CA'). Bare language codes ('en') are accepted as wildcards for backwards compatibility." ), ] rights: Annotated[ Rights | None, Field(description='Rights availability summary. For detailed pricing, use get_rights.'), ] = None tagline: Annotated[ str | Tagline | None, Field( description='Brand tagline or slogan. Accepts a plain string or a localized array matching the names pattern.' ), ] = None tone: Annotated[Tone | None, Field(description='Brand voice and messaging guidelines')] = None visual_guidelines: Annotated[ dict[str, Any] | None, Field( description='Structured visual rules for generative creative systems (photography, graphic_style, colorways, type_scale, motion). Matches brand.json visual_guidelines definition. Authorized callers only.' ), ] = None voice_synthesis: Annotated[ VoiceSynthesis | None, Field(description='Voice synthesis configuration for AI-generated audio'), ] = NoneBase model for AdCP types with spec-compliant serialization.
Defaults to
extra='ignore'so that unknown fields from newer spec versions are silently dropped rather than causing validation errors. Generated types whose schemas setadditionalProperties: trueoverride this withextra='allow'in their ownmodel_config. Consumers who want strict validation can override withextra='forbid'.Create a new model by parsing and validating input data from keyword arguments.
Raises [
ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.selfis explicitly positional-only to allowselfas a field name.Ancestors
- AdCPBaseModel
- pydantic.main.BaseModel
Class variables
var assets : list[Asset] | Nonevar available_fields : list[AvailableField] | Nonevar brand_id : strvar colors : Colors | Nonevar context : ContextObject | Nonevar description : str | Nonevar ext : ExtensionObject | Nonevar fonts : Fonts | Nonevar house : Housevar industries : list[str] | Nonevar keller_type : KellerType | Nonevar logos : list[Logo] | Nonevar model_configvar names : list[dict[str, str]]var rights : Rights | Nonevar tagline : str | Tagline | Nonevar tone : Tone | Nonevar visual_guidelines : dict[str, typing.Any] | Nonevar voice_synthesis : VoiceSynthesis | None
Inherited members
class GetBrandIdentityErrorResponse (**data: Any)-
Expand source code
class GetBrandIdentityResponse2(AdCPBaseModel): model_config = ConfigDict( extra='allow', ) context: context_1.ContextObject | None = None errors: Annotated[list[error.Error], Field(min_length=1)] ext: ext_1.ExtensionObject | None = NoneBase model for AdCP types with spec-compliant serialization.
Defaults to
extra='ignore'so that unknown fields from newer spec versions are silently dropped rather than causing validation errors. Generated types whose schemas setadditionalProperties: trueoverride this withextra='allow'in their ownmodel_config. Consumers who want strict validation can override withextra='forbid'.Create a new model by parsing and validating input data from keyword arguments.
Raises [
ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.selfis explicitly positional-only to allowselfas a field name.Ancestors
- AdCPBaseModel
- pydantic.main.BaseModel
Class variables
var context : ContextObject | Nonevar errors : list[Error]var ext : ExtensionObject | Nonevar model_config
Inherited members
class GetContentStandardsSuccessResponse (**data: Any)-
Expand source code
class GetContentStandardsResponse1(ContentStandards): context: context_1.ContextObject | None = NoneBase model for AdCP types with spec-compliant serialization.
Defaults to
extra='ignore'so that unknown fields from newer spec versions are silently dropped rather than causing validation errors. Generated types whose schemas setadditionalProperties: trueoverride this withextra='allow'in their ownmodel_config. Consumers who want strict validation can override withextra='forbid'.Create a new model by parsing and validating input data from keyword arguments.
Raises [
ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.selfis explicitly positional-only to allowselfas a field name.Ancestors
- ContentStandards
- AdCPBaseModel
- pydantic.main.BaseModel
Class variables
var context : ContextObject | Nonevar model_config
Inherited members
class GetContentStandardsErrorResponse (**data: Any)-
Expand source code
class GetContentStandardsResponse2(AdCPBaseModel): context: context_1.ContextObject | None = None errors: list[error.Error] ext: ext_1.ExtensionObject | None = NoneBase model for AdCP types with spec-compliant serialization.
Defaults to
extra='ignore'so that unknown fields from newer spec versions are silently dropped rather than causing validation errors. Generated types whose schemas setadditionalProperties: trueoverride this withextra='allow'in their ownmodel_config. Consumers who want strict validation can override withextra='forbid'.Create a new model by parsing and validating input data from keyword arguments.
Raises [
ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.selfis explicitly positional-only to allowselfas a field name.Ancestors
- AdCPBaseModel
- pydantic.main.BaseModel
Class variables
var context : ContextObject | Nonevar errors : list[Error]var ext : ExtensionObject | Nonevar model_config
Inherited members
class GetCreativeDeliveryRequest (**data: Any)-
Expand source code
class GetCreativeDeliveryRequest(AdCPBaseModel): model_config = ConfigDict( extra='allow', ) account: Annotated[ account_ref.AccountReference | None, Field( description='Account for routing and scoping. Limits results to creatives within this account.' ), ] = None context: context_1.ContextObject | None = None creative_ids: Annotated[ list[str] | None, Field( description='Filter to specific creatives by ID. If omitted, returns delivery for all creatives matching the other filters.', min_length=1, ), ] = None end_date: Annotated[ str | None, Field( description="End date for delivery period (YYYY-MM-DD). Interpreted in the platform's reporting timezone.", pattern='^\\d{4}-\\d{2}-\\d{2}$', ), ] = None ext: ext_1.ExtensionObject | None = None max_variants: Annotated[ int | None, Field( description='Maximum number of variants to return per creative. When omitted, the agent returns all variants. Use this to limit response size for generative creatives that may produce large numbers of variants.', ge=1, ), ] = None media_buy_ids: Annotated[ list[str] | None, Field( description='Filter to specific media buys by publisher ID. If omitted, returns creative delivery across all matching media buys.', min_length=1, ), ] = None pagination: Annotated[ pagination_request.PaginationRequest | None, Field( description='Pagination parameters for the creatives array in the response. Uses cursor-based pagination consistent with other list operations.' ), ] = None start_date: Annotated[ str | None, Field( description="Start date for delivery period (YYYY-MM-DD). Interpreted in the platform's reporting timezone.", pattern='^\\d{4}-\\d{2}-\\d{2}$', ), ] = NoneBase model for AdCP types with spec-compliant serialization.
Defaults to
extra='ignore'so that unknown fields from newer spec versions are silently dropped rather than causing validation errors. Generated types whose schemas setadditionalProperties: trueoverride this withextra='allow'in their ownmodel_config. Consumers who want strict validation can override withextra='forbid'.Create a new model by parsing and validating input data from keyword arguments.
Raises [
ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.selfis explicitly positional-only to allowselfas a field name.Ancestors
- AdCPBaseModel
- pydantic.main.BaseModel
Class variables
var account : AccountReference | Nonevar context : ContextObject | Nonevar creative_ids : list[str] | Nonevar end_date : str | Nonevar ext : ExtensionObject | Nonevar max_variants : int | Nonevar media_buy_ids : list[str] | Nonevar model_configvar pagination : PaginationRequest | Nonevar start_date : str | None
class GetCreativeDeliveryByBuyerRefRequest (**data: Any)-
Expand source code
class GetCreativeDeliveryRequest(AdCPBaseModel): model_config = ConfigDict( extra='allow', ) account: Annotated[ account_ref.AccountReference | None, Field( description='Account for routing and scoping. Limits results to creatives within this account.' ), ] = None context: context_1.ContextObject | None = None creative_ids: Annotated[ list[str] | None, Field( description='Filter to specific creatives by ID. If omitted, returns delivery for all creatives matching the other filters.', min_length=1, ), ] = None end_date: Annotated[ str | None, Field( description="End date for delivery period (YYYY-MM-DD). Interpreted in the platform's reporting timezone.", pattern='^\\d{4}-\\d{2}-\\d{2}$', ), ] = None ext: ext_1.ExtensionObject | None = None max_variants: Annotated[ int | None, Field( description='Maximum number of variants to return per creative. When omitted, the agent returns all variants. Use this to limit response size for generative creatives that may produce large numbers of variants.', ge=1, ), ] = None media_buy_ids: Annotated[ list[str] | None, Field( description='Filter to specific media buys by publisher ID. If omitted, returns creative delivery across all matching media buys.', min_length=1, ), ] = None pagination: Annotated[ pagination_request.PaginationRequest | None, Field( description='Pagination parameters for the creatives array in the response. Uses cursor-based pagination consistent with other list operations.' ), ] = None start_date: Annotated[ str | None, Field( description="Start date for delivery period (YYYY-MM-DD). Interpreted in the platform's reporting timezone.", pattern='^\\d{4}-\\d{2}-\\d{2}$', ), ] = NoneBase model for AdCP types with spec-compliant serialization.
Defaults to
extra='ignore'so that unknown fields from newer spec versions are silently dropped rather than causing validation errors. Generated types whose schemas setadditionalProperties: trueoverride this withextra='allow'in their ownmodel_config. Consumers who want strict validation can override withextra='forbid'.Create a new model by parsing and validating input data from keyword arguments.
Raises [
ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.selfis explicitly positional-only to allowselfas a field name.Ancestors
- AdCPBaseModel
- pydantic.main.BaseModel
Class variables
var account : AccountReference | Nonevar context : ContextObject | Nonevar creative_ids : list[str] | Nonevar end_date : str | Nonevar ext : ExtensionObject | Nonevar max_variants : int | Nonevar media_buy_ids : list[str] | Nonevar model_configvar pagination : PaginationRequest | Nonevar start_date : str | None
class GetCreativeDeliveryByCreativeRequest (**data: Any)-
Expand source code
class GetCreativeDeliveryRequest(AdCPBaseModel): model_config = ConfigDict( extra='allow', ) account: Annotated[ account_ref.AccountReference | None, Field( description='Account for routing and scoping. Limits results to creatives within this account.' ), ] = None context: context_1.ContextObject | None = None creative_ids: Annotated[ list[str] | None, Field( description='Filter to specific creatives by ID. If omitted, returns delivery for all creatives matching the other filters.', min_length=1, ), ] = None end_date: Annotated[ str | None, Field( description="End date for delivery period (YYYY-MM-DD). Interpreted in the platform's reporting timezone.", pattern='^\\d{4}-\\d{2}-\\d{2}$', ), ] = None ext: ext_1.ExtensionObject | None = None max_variants: Annotated[ int | None, Field( description='Maximum number of variants to return per creative. When omitted, the agent returns all variants. Use this to limit response size for generative creatives that may produce large numbers of variants.', ge=1, ), ] = None media_buy_ids: Annotated[ list[str] | None, Field( description='Filter to specific media buys by publisher ID. If omitted, returns creative delivery across all matching media buys.', min_length=1, ), ] = None pagination: Annotated[ pagination_request.PaginationRequest | None, Field( description='Pagination parameters for the creatives array in the response. Uses cursor-based pagination consistent with other list operations.' ), ] = None start_date: Annotated[ str | None, Field( description="Start date for delivery period (YYYY-MM-DD). Interpreted in the platform's reporting timezone.", pattern='^\\d{4}-\\d{2}-\\d{2}$', ), ] = NoneBase model for AdCP types with spec-compliant serialization.
Defaults to
extra='ignore'so that unknown fields from newer spec versions are silently dropped rather than causing validation errors. Generated types whose schemas setadditionalProperties: trueoverride this withextra='allow'in their ownmodel_config. Consumers who want strict validation can override withextra='forbid'.Create a new model by parsing and validating input data from keyword arguments.
Raises [
ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.selfis explicitly positional-only to allowselfas a field name.Ancestors
- AdCPBaseModel
- pydantic.main.BaseModel
Class variables
var account : AccountReference | Nonevar context : ContextObject | Nonevar creative_ids : list[str] | Nonevar end_date : str | Nonevar ext : ExtensionObject | Nonevar max_variants : int | Nonevar media_buy_ids : list[str] | Nonevar model_configvar pagination : PaginationRequest | Nonevar start_date : str | None
class GetCreativeDeliveryByMediaBuyRequest (**data: Any)-
Expand source code
class GetCreativeDeliveryRequest(AdCPBaseModel): model_config = ConfigDict( extra='allow', ) account: Annotated[ account_ref.AccountReference | None, Field( description='Account for routing and scoping. Limits results to creatives within this account.' ), ] = None context: context_1.ContextObject | None = None creative_ids: Annotated[ list[str] | None, Field( description='Filter to specific creatives by ID. If omitted, returns delivery for all creatives matching the other filters.', min_length=1, ), ] = None end_date: Annotated[ str | None, Field( description="End date for delivery period (YYYY-MM-DD). Interpreted in the platform's reporting timezone.", pattern='^\\d{4}-\\d{2}-\\d{2}$', ), ] = None ext: ext_1.ExtensionObject | None = None max_variants: Annotated[ int | None, Field( description='Maximum number of variants to return per creative. When omitted, the agent returns all variants. Use this to limit response size for generative creatives that may produce large numbers of variants.', ge=1, ), ] = None media_buy_ids: Annotated[ list[str] | None, Field( description='Filter to specific media buys by publisher ID. If omitted, returns creative delivery across all matching media buys.', min_length=1, ), ] = None pagination: Annotated[ pagination_request.PaginationRequest | None, Field( description='Pagination parameters for the creatives array in the response. Uses cursor-based pagination consistent with other list operations.' ), ] = None start_date: Annotated[ str | None, Field( description="Start date for delivery period (YYYY-MM-DD). Interpreted in the platform's reporting timezone.", pattern='^\\d{4}-\\d{2}-\\d{2}$', ), ] = NoneBase model for AdCP types with spec-compliant serialization.
Defaults to
extra='ignore'so that unknown fields from newer spec versions are silently dropped rather than causing validation errors. Generated types whose schemas setadditionalProperties: trueoverride this withextra='allow'in their ownmodel_config. Consumers who want strict validation can override withextra='forbid'.Create a new model by parsing and validating input data from keyword arguments.
Raises [
ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.selfis explicitly positional-only to allowselfas a field name.Ancestors
- AdCPBaseModel
- pydantic.main.BaseModel
Class variables
var account : AccountReference | Nonevar context : ContextObject | Nonevar creative_ids : list[str] | Nonevar end_date : str | Nonevar ext : ExtensionObject | Nonevar max_variants : int | Nonevar media_buy_ids : list[str] | Nonevar model_configvar pagination : PaginationRequest | Nonevar start_date : str | None
Inherited members
class GetCreativeDeliveryResponse (**data: Any)-
Expand source code
class GetCreativeDeliveryResponse(AdCPBaseModel): model_config = ConfigDict( extra='allow', ) account_id: Annotated[ str | None, Field( description='Account identifier. Present when the response spans or is scoped to a specific account.' ), ] = None context: context_1.ContextObject | None = None creatives: Annotated[ list[Creative], Field(description='Creative delivery data with variant breakdowns') ] currency: Annotated[ str, Field( description="ISO 4217 currency code for monetary values in this response (e.g., 'USD', 'EUR')", pattern='^[A-Z]{3}$', ), ] errors: Annotated[ list[error.Error] | None, Field(description='Task-specific errors and warnings') ] = None ext: ext_1.ExtensionObject | None = None media_buy_id: Annotated[ str | None, Field( description="Publisher's media buy identifier. Present when the request was scoped to a single media buy." ), ] = None pagination: Annotated[ Pagination | None, Field( description='Pagination information. Present when the request included pagination parameters.' ), ] = None reporting_period: Annotated[ReportingPeriod, Field(description='Date range for the report.')]Base model for AdCP types with spec-compliant serialization.
Defaults to
extra='ignore'so that unknown fields from newer spec versions are silently dropped rather than causing validation errors. Generated types whose schemas setadditionalProperties: trueoverride this withextra='allow'in their ownmodel_config. Consumers who want strict validation can override withextra='forbid'.Create a new model by parsing and validating input data from keyword arguments.
Raises [
ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.selfis explicitly positional-only to allowselfas a field name.Ancestors
- AdCPBaseModel
- pydantic.main.BaseModel
Class variables
var account_id : str | Nonevar context : ContextObject | Nonevar creatives : list[Creative]var currency : strvar errors : list[Error] | Nonevar ext : ExtensionObject | Nonevar media_buy_id : str | Nonevar model_configvar pagination : Pagination | Nonevar reporting_period : ReportingPeriod
Inherited members
class GetCreativeFeaturesRequest (**data: Any)-
Expand source code
class GetCreativeFeaturesRequest(AdCPBaseModel): model_config = ConfigDict( extra='allow', ) account: Annotated[ account_ref.AccountReference | None, Field( description='Account for billing this evaluation. Required when the governance agent charges per evaluation.' ), ] = None context: context_1.ContextObject | None = None creative_manifest: Annotated[ creative_manifest_1.CreativeManifest, Field(description='The creative manifest to evaluate. Contains format_id and assets.'), ] ext: ext_1.ExtensionObject | None = None feature_ids: Annotated[ list[str] | None, Field( description='Optional filter to specific features. If omitted, returns all available features.', min_length=1, ), ] = NoneBase model for AdCP types with spec-compliant serialization.
Defaults to
extra='ignore'so that unknown fields from newer spec versions are silently dropped rather than causing validation errors. Generated types whose schemas setadditionalProperties: trueoverride this withextra='allow'in their ownmodel_config. Consumers who want strict validation can override withextra='forbid'.Create a new model by parsing and validating input data from keyword arguments.
Raises [
ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.selfis explicitly positional-only to allowselfas a field name.Ancestors
- AdCPBaseModel
- pydantic.main.BaseModel
Class variables
var account : AccountReference | Nonevar context : ContextObject | Nonevar creative_manifest : CreativeManifestvar ext : ExtensionObject | Nonevar feature_ids : list[str] | Nonevar model_config
Inherited members
class GetCreativeFeaturesSuccessResponse (**data: Any)-
Expand source code
class GetCreativeFeaturesResponse1(AdCPBaseModel): context: context_1.ContextObject | None = None detail_url: Annotated[ AnyUrl | None, Field( description="URL to the vendor's full assessment report. The vendor controls what information is disclosed and access control." ), ] = None ext: ext_1.ExtensionObject | None = None results: Annotated[ list[creative_feature_result.CreativeFeatureResult], Field(description='Feature values for the evaluated creative'), ]Base model for AdCP types with spec-compliant serialization.
Defaults to
extra='ignore'so that unknown fields from newer spec versions are silently dropped rather than causing validation errors. Generated types whose schemas setadditionalProperties: trueoverride this withextra='allow'in their ownmodel_config. Consumers who want strict validation can override withextra='forbid'.Create a new model by parsing and validating input data from keyword arguments.
Raises [
ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.selfis explicitly positional-only to allowselfas a field name.Ancestors
- AdCPBaseModel
- pydantic.main.BaseModel
Class variables
var context : ContextObject | Nonevar detail_url : pydantic.networks.AnyUrl | Nonevar ext : ExtensionObject | Nonevar model_configvar results : list[CreativeFeatureResult]
Inherited members
class GetCreativeFeaturesErrorResponse (**data: Any)-
Expand source code
class GetCreativeFeaturesResponse2(AdCPBaseModel): context: context_1.ContextObject | None = None errors: list[error.Error] ext: ext_1.ExtensionObject | None = NoneBase model for AdCP types with spec-compliant serialization.
Defaults to
extra='ignore'so that unknown fields from newer spec versions are silently dropped rather than causing validation errors. Generated types whose schemas setadditionalProperties: trueoverride this withextra='allow'in their ownmodel_config. Consumers who want strict validation can override withextra='forbid'.Create a new model by parsing and validating input data from keyword arguments.
Raises [
ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.selfis explicitly positional-only to allowselfas a field name.Ancestors
- AdCPBaseModel
- pydantic.main.BaseModel
Class variables
var context : ContextObject | Nonevar errors : list[Error]var ext : ExtensionObject | Nonevar model_config
Inherited members
class GetMediaBuyArtifactsSuccessResponse (**data: Any)-
Expand source code
class GetMediaBuyArtifactsResponse1(AdCPBaseModel): artifacts: Annotated[ list[Artifact], Field(description='Delivery records with full artifact content') ] collection_info: Annotated[ CollectionInfo | None, Field( description='Information about artifact collection for this media buy. Sampling is configured at buy creation time — this reports what was actually collected.' ), ] = None context: context_1.ContextObject | None = None ext: ext_1.ExtensionObject | None = None media_buy_id: Annotated[str, Field(description='Media buy these artifacts belong to')] pagination: pagination_response.PaginationResponse | None = NoneBase model for AdCP types with spec-compliant serialization.
Defaults to
extra='ignore'so that unknown fields from newer spec versions are silently dropped rather than causing validation errors. Generated types whose schemas setadditionalProperties: trueoverride this withextra='allow'in their ownmodel_config. Consumers who want strict validation can override withextra='forbid'.Create a new model by parsing and validating input data from keyword arguments.
Raises [
ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.selfis explicitly positional-only to allowselfas a field name.Ancestors
- AdCPBaseModel
- pydantic.main.BaseModel
Class variables
var artifacts : list[Artifact]var collection_info : CollectionInfo | Nonevar context : ContextObject | Nonevar ext : ExtensionObject | Nonevar media_buy_id : strvar model_configvar pagination : PaginationResponse | None
Inherited members
class GetMediaBuyArtifactsErrorResponse (**data: Any)-
Expand source code
class GetMediaBuyArtifactsResponse2(AdCPBaseModel): context: context_1.ContextObject | None = None errors: list[error.Error] ext: ext_1.ExtensionObject | None = NoneBase model for AdCP types with spec-compliant serialization.
Defaults to
extra='ignore'so that unknown fields from newer spec versions are silently dropped rather than causing validation errors. Generated types whose schemas setadditionalProperties: trueoverride this withextra='allow'in their ownmodel_config. Consumers who want strict validation can override withextra='forbid'.Create a new model by parsing and validating input data from keyword arguments.
Raises [
ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.selfis explicitly positional-only to allowselfas a field name.Ancestors
- AdCPBaseModel
- pydantic.main.BaseModel
Class variables
var context : ContextObject | Nonevar errors : list[Error]var ext : ExtensionObject | Nonevar model_config
Inherited members
class GetMediaBuyDeliveryRequest (**data: Any)-
Expand source code
class GetMediaBuyDeliveryRequest(AdCPBaseModel): model_config = ConfigDict( extra='allow', ) account: Annotated[ account_ref.AccountReference | None, Field( description='Filter delivery data to a specific account. When omitted, returns data across all accessible accounts.' ), ] = None attribution_window: Annotated[ AttributionWindow | None, Field( description='Attribution window to apply for conversion metrics. When provided, the seller returns conversion data using the requested lookback windows instead of their platform default. The seller echoes the applied window in the response. Sellers that do not support configurable windows ignore this field and return their default. Check get_adcp_capabilities conversion_tracking.attribution_windows for available options.' ), ] = None context: context_1.ContextObject | None = None end_date: Annotated[ str | None, Field( description="End date for reporting period (YYYY-MM-DD). When omitted along with start_date, returns campaign lifetime data. Only accepted when the product's reporting_capabilities.date_range_support is 'date_range'.", pattern='^\\d{4}-\\d{2}-\\d{2}$', ), ] = None ext: ext_1.ExtensionObject | None = None include_package_daily_breakdown: Annotated[ bool | None, Field( description='When true, include daily_breakdown arrays within each package in by_package. Useful for per-package pacing analysis and line-item monitoring. Omit or set false to reduce response size — package daily data can be large for multi-package buys over long flights.' ), ] = False media_buy_ids: Annotated[ list[str] | None, Field(description='Array of media buy IDs to get delivery data for', min_length=1), ] = None reporting_dimensions: Annotated[ ReportingDimensions | None, Field( description='Request dimensional breakdowns in delivery reporting. Each key enables a specific breakdown dimension within by_package — include as an empty object (e.g., "device_type": {}) to activate with defaults. Omit entirely for no breakdowns (backward compatible). Unsupported dimensions are silently omitted from the response. Note: keyword, catalog_item, and creative breakdowns are returned automatically when the seller supports them and are not controlled by this object.' ), ] = None start_date: Annotated[ str | None, Field( description="Start date for reporting period (YYYY-MM-DD). When omitted along with end_date, returns campaign lifetime data. Only accepted when the product's reporting_capabilities.date_range_support is 'date_range'.", pattern='^\\d{4}-\\d{2}-\\d{2}$', ), ] = None status_filter: Annotated[ media_buy_status.MediaBuyStatus | StatusFilter | None, Field(description='Filter by status. Can be a single status or array of statuses'), ] = NoneBase model for AdCP types with spec-compliant serialization.
Defaults to
extra='ignore'so that unknown fields from newer spec versions are silently dropped rather than causing validation errors. Generated types whose schemas setadditionalProperties: trueoverride this withextra='allow'in their ownmodel_config. Consumers who want strict validation can override withextra='forbid'.Create a new model by parsing and validating input data from keyword arguments.
Raises [
ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.selfis explicitly positional-only to allowselfas a field name.Ancestors
- AdCPBaseModel
- pydantic.main.BaseModel
Class variables
var account : AccountReference | Nonevar attribution_window : AttributionWindow | Nonevar context : ContextObject | Nonevar end_date : str | Nonevar ext : ExtensionObject | Nonevar include_package_daily_breakdown : bool | Nonevar media_buy_ids : list[str] | Nonevar model_configvar reporting_dimensions : ReportingDimensions | Nonevar start_date : str | Nonevar status_filter : MediaBuyStatus | StatusFilter | None
Inherited members
class GetMediaBuyDeliveryResponse (**data: Any)-
Expand source code
class GetMediaBuyDeliveryResponse(AdCPBaseModel): model_config = ConfigDict( extra='allow', ) aggregated_totals: Annotated[ AggregatedTotals | None, Field( description='Combined metrics across all returned media buys. Only included in API responses (get_media_buy_delivery), not in webhook notifications.' ), ] = None attribution_window: Annotated[ attribution_window_1.AttributionWindow | None, Field( description='Attribution methodology and lookback windows used for conversion metrics in this response. All media buys from a single seller share the same attribution methodology. Enables cross-platform comparison (e.g., Amazon 14-day click vs. Criteo 30-day click).' ), ] = None context: context_1.ContextObject | None = None currency: Annotated[str, Field(description='ISO 4217 currency code', pattern='^[A-Z]{3}$')] errors: Annotated[ list[error.Error] | None, Field( description='Task-specific errors and warnings (e.g., missing delivery data, reporting platform issues)' ), ] = None ext: ext_1.ExtensionObject | None = None media_buy_deliveries: Annotated[ list[MediaBuyDelivery], Field( description='Array of delivery data for media buys. When used in webhook notifications, may contain multiple media buys aggregated by publisher. When used in get_media_buy_delivery API responses, typically contains requested media buys.' ), ] next_expected_at: Annotated[ AwareDatetime | None, Field( description="ISO 8601 timestamp for next expected notification (only present in webhook deliveries when notification_type is not 'final')" ), ] = None notification_type: Annotated[ NotificationType | None, Field( description='Type of webhook notification (only present in webhook deliveries): scheduled = regular periodic update, final = campaign completed, delayed = data not yet available, adjusted = resending period with updated data' ), ] = None partial_data: Annotated[ bool | None, Field( description='Indicates if any media buys in this webhook have missing/delayed data (only present in webhook deliveries)' ), ] = None reporting_period: Annotated[ ReportingPeriod, Field(description='Date range for the report. All periods use UTC timezone.'), ] sandbox: Annotated[ bool | None, Field(description='When true, this response contains simulated data from sandbox mode.'), ] = None sequence_number: Annotated[ int | None, Field( description='Sequential notification number (only present in webhook deliveries, starts at 1)', ge=1, ), ] = None unavailable_count: Annotated[ int | None, Field( description='Number of media buys with reporting_delayed or failed status (only present in webhook deliveries when partial_data is true)', ge=0, ), ] = NoneBase model for AdCP types with spec-compliant serialization.
Defaults to
extra='ignore'so that unknown fields from newer spec versions are silently dropped rather than causing validation errors. Generated types whose schemas setadditionalProperties: trueoverride this withextra='allow'in their ownmodel_config. Consumers who want strict validation can override withextra='forbid'.Create a new model by parsing and validating input data from keyword arguments.
Raises [
ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.selfis explicitly positional-only to allowselfas a field name.Ancestors
- AdCPBaseModel
- pydantic.main.BaseModel
Class variables
var aggregated_totals : AggregatedTotals | Nonevar attribution_window : AttributionWindow | Nonevar context : ContextObject | Nonevar currency : strvar errors : list[Error] | Nonevar ext : ExtensionObject | Nonevar media_buy_deliveries : list[MediaBuyDelivery]var model_configvar next_expected_at : pydantic.types.AwareDatetime | Nonevar notification_type : NotificationType | Nonevar partial_data : bool | Nonevar reporting_period : ReportingPeriodvar sandbox : bool | Nonevar sequence_number : int | None
Inherited members
class GetMediaBuysRequest (**data: Any)-
Expand source code
class GetMediaBuysRequest(AdCPBaseModel): model_config = ConfigDict( extra='allow', ) account: Annotated[ account_ref.AccountReference | None, Field( description='Account to retrieve media buys for. When omitted, returns data across all accessible accounts.' ), ] = None context: context_1.ContextObject | None = None ext: ext_1.ExtensionObject | None = None include_history: Annotated[ int | None, Field( description='When present, include the last N revision history entries for each media buy (returns min(N, available entries)). Each entry contains revision number, timestamp, actor, and a summary of what changed. Omit or set to 0 to exclude history (default). Recommended: 5-10 for monitoring, 50+ for audit.', ge=0, le=1000, ), ] = 0 include_snapshot: Annotated[ bool | None, Field( description='When true, include a near-real-time delivery snapshot for each package. Snapshots reflect the latest available entity-level stats from the platform (e.g., updated every ~15 minutes on GAM, ~1 hour on batch-only platforms). The staleness_seconds field on each snapshot indicates data freshness. If a snapshot cannot be returned, package.snapshot_unavailable_reason explains why. Defaults to false.' ), ] = False media_buy_ids: Annotated[ list[str] | None, Field( description='Array of media buy IDs to retrieve. When omitted, returns a paginated set of accessible media buys matching status_filter.', min_length=1, ), ] = None pagination: Annotated[ pagination_request.PaginationRequest | None, Field( description='Cursor-based pagination controls. Strongly recommended when querying broad scopes (for example, all active media buys in an account).' ), ] = None status_filter: Annotated[ media_buy_status.MediaBuyStatus | StatusFilter | None, Field( description='Filter by status. Can be a single status or array of statuses. Defaults to ["active"] when media_buy_ids is omitted. When media_buy_ids is provided, no implicit status filter is applied.' ), ] = NoneBase model for AdCP types with spec-compliant serialization.
Defaults to
extra='ignore'so that unknown fields from newer spec versions are silently dropped rather than causing validation errors. Generated types whose schemas setadditionalProperties: trueoverride this withextra='allow'in their ownmodel_config. Consumers who want strict validation can override withextra='forbid'.Create a new model by parsing and validating input data from keyword arguments.
Raises [
ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.selfis explicitly positional-only to allowselfas a field name.Ancestors
- AdCPBaseModel
- pydantic.main.BaseModel
Class variables
var account : AccountReference | Nonevar context : ContextObject | Nonevar ext : ExtensionObject | Nonevar include_history : int | Nonevar include_snapshot : bool | Nonevar media_buy_ids : list[str] | Nonevar model_configvar pagination : PaginationRequest | Nonevar status_filter : MediaBuyStatus | StatusFilter | None
Inherited members
class GetMediaBuysResponse (**data: Any)-
Expand source code
class GetMediaBuysResponse(AdCPBaseModel): model_config = ConfigDict( extra='allow', ) context: context_1.ContextObject | None = None errors: Annotated[ list[error.Error] | None, Field(description='Task-specific errors (e.g., media buy not found)'), ] = None ext: ext_1.ExtensionObject | None = None media_buys: Annotated[ list[MediaBuy], Field( description='Array of media buys with status, creative approval state, and optional delivery snapshots' ), ] pagination: Annotated[ pagination_response.PaginationResponse | None, Field(description='Pagination metadata for the media_buys array.'), ] = None sandbox: Annotated[ bool | None, Field(description='When true, this response contains simulated data from sandbox mode.'), ] = NoneBase model for AdCP types with spec-compliant serialization.
Defaults to
extra='ignore'so that unknown fields from newer spec versions are silently dropped rather than causing validation errors. Generated types whose schemas setadditionalProperties: trueoverride this withextra='allow'in their ownmodel_config. Consumers who want strict validation can override withextra='forbid'.Create a new model by parsing and validating input data from keyword arguments.
Raises [
ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.selfis explicitly positional-only to allowselfas a field name.Ancestors
- AdCPBaseModel
- pydantic.main.BaseModel
Class variables
var context : ContextObject | Nonevar errors : list[Error] | Nonevar ext : ExtensionObject | Nonevar media_buys : list[MediaBuy]var model_configvar pagination : PaginationResponse | Nonevar sandbox : bool | None
Inherited members
class GetPlanAuditLogsRequest (**data: Any)-
Expand source code
class GetPlanAuditLogsRequest(AdCPBaseModel): model_config = ConfigDict( extra='forbid', ) include_entries: Annotated[ bool | None, Field(description='Include the full audit trail. Default: false.') ] = False plan_ids: Annotated[ list[str] | None, Field( description='Plan IDs to retrieve. For a single plan, pass a one-element array.', min_length=1, ), ] = None portfolio_plan_ids: Annotated[ list[str] | None, Field( description='Portfolio plan IDs. The governance agent expands each to its member_plan_ids and returns combined audit data.', min_length=1, ), ] = NoneBase model for AdCP types with spec-compliant serialization.
Defaults to
extra='ignore'so that unknown fields from newer spec versions are silently dropped rather than causing validation errors. Generated types whose schemas setadditionalProperties: trueoverride this withextra='allow'in their ownmodel_config. Consumers who want strict validation can override withextra='forbid'.Create a new model by parsing and validating input data from keyword arguments.
Raises [
ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.selfis explicitly positional-only to allowselfas a field name.Ancestors
- AdCPBaseModel
- pydantic.main.BaseModel
Class variables
var include_entries : bool | Nonevar model_configvar plan_ids : list[str] | Nonevar portfolio_plan_ids : list[str] | None
Inherited members
class GetPlanAuditLogsResponse (**data: Any)-
Expand source code
class GetPlanAuditLogsResponse(AdCPBaseModel): model_config = ConfigDict( extra='forbid', ) plans: Annotated[list[Plan], Field(description='Audit data for each requested plan.')]Base model for AdCP types with spec-compliant serialization.
Defaults to
extra='ignore'so that unknown fields from newer spec versions are silently dropped rather than causing validation errors. Generated types whose schemas setadditionalProperties: trueoverride this withextra='allow'in their ownmodel_config. Consumers who want strict validation can override withextra='forbid'.Create a new model by parsing and validating input data from keyword arguments.
Raises [
ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.selfis explicitly positional-only to allowselfas a field name.Ancestors
- AdCPBaseModel
- pydantic.main.BaseModel
Class variables
var model_configvar plans : list[Plan]
Inherited members
class GetProductsRequest (**data: Any)-
Expand source code
class GetProductsRequest(AdCPBaseModel): model_config = ConfigDict( extra='allow', ) account: Annotated[ account_ref.AccountReference | None, Field( description="Account for product lookup. Returns products with pricing specific to this account's rate card." ), ] = None brand: Annotated[ brand_ref.BrandReference | None, Field( description='Brand reference for product discovery context. Resolved to full brand identity at execution time.' ), ] = None brief: Annotated[ str | None, Field( description="Natural language description of campaign requirements. Required when buying_mode is 'brief'. Must not be provided when buying_mode is 'wholesale' or 'refine'." ), ] = None buying_mode: Annotated[ BuyingMode, Field( description="Declares buyer intent for this request. 'brief': publisher curates product recommendations from the provided brief. 'wholesale': buyer requests raw inventory to apply their own audiences — brief must not be provided, and proposals are omitted. 'refine': iterate on products and proposals from a previous get_products response using the refine array of change requests. v3 clients MUST include buying_mode. Sellers receiving requests from pre-v3 clients without buying_mode SHOULD default to 'brief'." ), ] catalog: Annotated[ catalog_1.Catalog | None, Field( description='Catalog of items the buyer wants to promote. The seller matches catalog items against its inventory and returns products where matches exist. Supports all catalog types: a job catalog finds job ad products, a product catalog finds sponsored product slots. Reference a synced catalog by catalog_id, or provide inline items.' ), ] = None context: context_1.ContextObject | None = None ext: ext_1.ExtensionObject | None = None fields: Annotated[ list[Field1] | None, Field( description='Specific product fields to include in the response. When omitted, all fields are returned. Use for lightweight discovery calls where only a subset of product data is needed (e.g., just IDs and pricing for comparison). Required fields (product_id, name) are always included regardless of selection.', min_length=1, ), ] = None filters: product_filters.ProductFilters | None = None pagination: pagination_request.PaginationRequest | None = None preferred_delivery_types: Annotated[ list[delivery_type_1.DeliveryType] | None, Field( description='Delivery types the buyer prefers, in priority order. Unlike filters.delivery_type which excludes non-matching products, this signals preference for curation — the publisher may still include other delivery types when they match the brief well.', min_length=1, ), ] = None property_list: Annotated[ property_list_ref.PropertyListReference | None, Field( description='[AdCP 3.0] Reference to an externally managed property list. When provided, the sales agent should filter products to only those available on properties in the list.' ), ] = None refine: Annotated[ list[Refine | Refine1 | Refine2] | None, Field( description="Array of change requests for iterating on products and proposals from a previous get_products response. Each entry declares a scope (request, product, or proposal) and what the buyer is asking for. Only valid when buying_mode is 'refine'. The seller responds to each entry via refinement_applied in the response, matched by position.", min_length=1, ), ] = None required_policies: Annotated[ list[str] | None, Field( description='Registry policy IDs that the buyer requires to be enforced for products in this response. Sellers filter products to only those that comply with or already enforce the requested policies.' ), ] = None time_budget: Annotated[ duration.Duration | None, Field( description='Maximum time the buyer will commit to this request. The seller returns the best results achievable within this budget and does not start processes (human approvals, expensive external queries) that cannot complete in time. When omitted, the seller decides timing.' ), ] = NoneBase model for AdCP types with spec-compliant serialization.
Defaults to
extra='ignore'so that unknown fields from newer spec versions are silently dropped rather than causing validation errors. Generated types whose schemas setadditionalProperties: trueoverride this withextra='allow'in their ownmodel_config. Consumers who want strict validation can override withextra='forbid'.Create a new model by parsing and validating input data from keyword arguments.
Raises [
ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.selfis explicitly positional-only to allowselfas a field name.Ancestors
- AdCPBaseModel
- pydantic.main.BaseModel
Class variables
var account : AccountReference | Nonevar brand : BrandReference | Nonevar brief : str | Nonevar buying_mode : BuyingMode | Nonevar catalog : Catalog | Nonevar context : ContextObject | Nonevar ext : ExtensionObject | Nonevar fields : list[Field1] | Nonevar filters : ProductFilters | Nonevar model_configvar pagination : PaginationRequest | Nonevar preferred_delivery_types : list[DeliveryType] | Nonevar property_list : PropertyListReference | Nonevar refine : list[Refine | Refine1 | Refine2] | Nonevar required_policies : list[str] | Nonevar time_budget : Duration | None
class GetProductsBriefRequest (**data: Any)-
Expand source code
class GetProductsRequest(AdCPBaseModel): model_config = ConfigDict( extra='allow', ) account: Annotated[ account_ref.AccountReference | None, Field( description="Account for product lookup. Returns products with pricing specific to this account's rate card." ), ] = None brand: Annotated[ brand_ref.BrandReference | None, Field( description='Brand reference for product discovery context. Resolved to full brand identity at execution time.' ), ] = None brief: Annotated[ str | None, Field( description="Natural language description of campaign requirements. Required when buying_mode is 'brief'. Must not be provided when buying_mode is 'wholesale' or 'refine'." ), ] = None buying_mode: Annotated[ BuyingMode, Field( description="Declares buyer intent for this request. 'brief': publisher curates product recommendations from the provided brief. 'wholesale': buyer requests raw inventory to apply their own audiences — brief must not be provided, and proposals are omitted. 'refine': iterate on products and proposals from a previous get_products response using the refine array of change requests. v3 clients MUST include buying_mode. Sellers receiving requests from pre-v3 clients without buying_mode SHOULD default to 'brief'." ), ] catalog: Annotated[ catalog_1.Catalog | None, Field( description='Catalog of items the buyer wants to promote. The seller matches catalog items against its inventory and returns products where matches exist. Supports all catalog types: a job catalog finds job ad products, a product catalog finds sponsored product slots. Reference a synced catalog by catalog_id, or provide inline items.' ), ] = None context: context_1.ContextObject | None = None ext: ext_1.ExtensionObject | None = None fields: Annotated[ list[Field1] | None, Field( description='Specific product fields to include in the response. When omitted, all fields are returned. Use for lightweight discovery calls where only a subset of product data is needed (e.g., just IDs and pricing for comparison). Required fields (product_id, name) are always included regardless of selection.', min_length=1, ), ] = None filters: product_filters.ProductFilters | None = None pagination: pagination_request.PaginationRequest | None = None preferred_delivery_types: Annotated[ list[delivery_type_1.DeliveryType] | None, Field( description='Delivery types the buyer prefers, in priority order. Unlike filters.delivery_type which excludes non-matching products, this signals preference for curation — the publisher may still include other delivery types when they match the brief well.', min_length=1, ), ] = None property_list: Annotated[ property_list_ref.PropertyListReference | None, Field( description='[AdCP 3.0] Reference to an externally managed property list. When provided, the sales agent should filter products to only those available on properties in the list.' ), ] = None refine: Annotated[ list[Refine | Refine1 | Refine2] | None, Field( description="Array of change requests for iterating on products and proposals from a previous get_products response. Each entry declares a scope (request, product, or proposal) and what the buyer is asking for. Only valid when buying_mode is 'refine'. The seller responds to each entry via refinement_applied in the response, matched by position.", min_length=1, ), ] = None required_policies: Annotated[ list[str] | None, Field( description='Registry policy IDs that the buyer requires to be enforced for products in this response. Sellers filter products to only those that comply with or already enforce the requested policies.' ), ] = None time_budget: Annotated[ duration.Duration | None, Field( description='Maximum time the buyer will commit to this request. The seller returns the best results achievable within this budget and does not start processes (human approvals, expensive external queries) that cannot complete in time. When omitted, the seller decides timing.' ), ] = NoneBase model for AdCP types with spec-compliant serialization.
Defaults to
extra='ignore'so that unknown fields from newer spec versions are silently dropped rather than causing validation errors. Generated types whose schemas setadditionalProperties: trueoverride this withextra='allow'in their ownmodel_config. Consumers who want strict validation can override withextra='forbid'.Create a new model by parsing and validating input data from keyword arguments.
Raises [
ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.selfis explicitly positional-only to allowselfas a field name.Ancestors
- AdCPBaseModel
- pydantic.main.BaseModel
Class variables
var account : AccountReference | Nonevar brand : BrandReference | Nonevar brief : str | Nonevar buying_mode : BuyingMode | Nonevar catalog : Catalog | Nonevar context : ContextObject | Nonevar ext : ExtensionObject | Nonevar fields : list[Field1] | Nonevar filters : ProductFilters | Nonevar model_configvar pagination : PaginationRequest | Nonevar preferred_delivery_types : list[DeliveryType] | Nonevar property_list : PropertyListReference | Nonevar refine : list[Refine | Refine1 | Refine2] | Nonevar required_policies : list[str] | Nonevar time_budget : Duration | None
class GetProductsRefineRequest (**data: Any)-
Expand source code
class GetProductsRequest(AdCPBaseModel): model_config = ConfigDict( extra='allow', ) account: Annotated[ account_ref.AccountReference | None, Field( description="Account for product lookup. Returns products with pricing specific to this account's rate card." ), ] = None brand: Annotated[ brand_ref.BrandReference | None, Field( description='Brand reference for product discovery context. Resolved to full brand identity at execution time.' ), ] = None brief: Annotated[ str | None, Field( description="Natural language description of campaign requirements. Required when buying_mode is 'brief'. Must not be provided when buying_mode is 'wholesale' or 'refine'." ), ] = None buying_mode: Annotated[ BuyingMode, Field( description="Declares buyer intent for this request. 'brief': publisher curates product recommendations from the provided brief. 'wholesale': buyer requests raw inventory to apply their own audiences — brief must not be provided, and proposals are omitted. 'refine': iterate on products and proposals from a previous get_products response using the refine array of change requests. v3 clients MUST include buying_mode. Sellers receiving requests from pre-v3 clients without buying_mode SHOULD default to 'brief'." ), ] catalog: Annotated[ catalog_1.Catalog | None, Field( description='Catalog of items the buyer wants to promote. The seller matches catalog items against its inventory and returns products where matches exist. Supports all catalog types: a job catalog finds job ad products, a product catalog finds sponsored product slots. Reference a synced catalog by catalog_id, or provide inline items.' ), ] = None context: context_1.ContextObject | None = None ext: ext_1.ExtensionObject | None = None fields: Annotated[ list[Field1] | None, Field( description='Specific product fields to include in the response. When omitted, all fields are returned. Use for lightweight discovery calls where only a subset of product data is needed (e.g., just IDs and pricing for comparison). Required fields (product_id, name) are always included regardless of selection.', min_length=1, ), ] = None filters: product_filters.ProductFilters | None = None pagination: pagination_request.PaginationRequest | None = None preferred_delivery_types: Annotated[ list[delivery_type_1.DeliveryType] | None, Field( description='Delivery types the buyer prefers, in priority order. Unlike filters.delivery_type which excludes non-matching products, this signals preference for curation — the publisher may still include other delivery types when they match the brief well.', min_length=1, ), ] = None property_list: Annotated[ property_list_ref.PropertyListReference | None, Field( description='[AdCP 3.0] Reference to an externally managed property list. When provided, the sales agent should filter products to only those available on properties in the list.' ), ] = None refine: Annotated[ list[Refine | Refine1 | Refine2] | None, Field( description="Array of change requests for iterating on products and proposals from a previous get_products response. Each entry declares a scope (request, product, or proposal) and what the buyer is asking for. Only valid when buying_mode is 'refine'. The seller responds to each entry via refinement_applied in the response, matched by position.", min_length=1, ), ] = None required_policies: Annotated[ list[str] | None, Field( description='Registry policy IDs that the buyer requires to be enforced for products in this response. Sellers filter products to only those that comply with or already enforce the requested policies.' ), ] = None time_budget: Annotated[ duration.Duration | None, Field( description='Maximum time the buyer will commit to this request. The seller returns the best results achievable within this budget and does not start processes (human approvals, expensive external queries) that cannot complete in time. When omitted, the seller decides timing.' ), ] = NoneBase model for AdCP types with spec-compliant serialization.
Defaults to
extra='ignore'so that unknown fields from newer spec versions are silently dropped rather than causing validation errors. Generated types whose schemas setadditionalProperties: trueoverride this withextra='allow'in their ownmodel_config. Consumers who want strict validation can override withextra='forbid'.Create a new model by parsing and validating input data from keyword arguments.
Raises [
ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.selfis explicitly positional-only to allowselfas a field name.Ancestors
- AdCPBaseModel
- pydantic.main.BaseModel
Class variables
var account : AccountReference | Nonevar brand : BrandReference | Nonevar brief : str | Nonevar buying_mode : BuyingMode | Nonevar catalog : Catalog | Nonevar context : ContextObject | Nonevar ext : ExtensionObject | Nonevar fields : list[Field1] | Nonevar filters : ProductFilters | Nonevar model_configvar pagination : PaginationRequest | Nonevar preferred_delivery_types : list[DeliveryType] | Nonevar property_list : PropertyListReference | Nonevar refine : list[Refine | Refine1 | Refine2] | Nonevar required_policies : list[str] | Nonevar time_budget : Duration | None
class GetProductsWholesaleRequest (**data: Any)-
Expand source code
class GetProductsRequest(AdCPBaseModel): model_config = ConfigDict( extra='allow', ) account: Annotated[ account_ref.AccountReference | None, Field( description="Account for product lookup. Returns products with pricing specific to this account's rate card." ), ] = None brand: Annotated[ brand_ref.BrandReference | None, Field( description='Brand reference for product discovery context. Resolved to full brand identity at execution time.' ), ] = None brief: Annotated[ str | None, Field( description="Natural language description of campaign requirements. Required when buying_mode is 'brief'. Must not be provided when buying_mode is 'wholesale' or 'refine'." ), ] = None buying_mode: Annotated[ BuyingMode, Field( description="Declares buyer intent for this request. 'brief': publisher curates product recommendations from the provided brief. 'wholesale': buyer requests raw inventory to apply their own audiences — brief must not be provided, and proposals are omitted. 'refine': iterate on products and proposals from a previous get_products response using the refine array of change requests. v3 clients MUST include buying_mode. Sellers receiving requests from pre-v3 clients without buying_mode SHOULD default to 'brief'." ), ] catalog: Annotated[ catalog_1.Catalog | None, Field( description='Catalog of items the buyer wants to promote. The seller matches catalog items against its inventory and returns products where matches exist. Supports all catalog types: a job catalog finds job ad products, a product catalog finds sponsored product slots. Reference a synced catalog by catalog_id, or provide inline items.' ), ] = None context: context_1.ContextObject | None = None ext: ext_1.ExtensionObject | None = None fields: Annotated[ list[Field1] | None, Field( description='Specific product fields to include in the response. When omitted, all fields are returned. Use for lightweight discovery calls where only a subset of product data is needed (e.g., just IDs and pricing for comparison). Required fields (product_id, name) are always included regardless of selection.', min_length=1, ), ] = None filters: product_filters.ProductFilters | None = None pagination: pagination_request.PaginationRequest | None = None preferred_delivery_types: Annotated[ list[delivery_type_1.DeliveryType] | None, Field( description='Delivery types the buyer prefers, in priority order. Unlike filters.delivery_type which excludes non-matching products, this signals preference for curation — the publisher may still include other delivery types when they match the brief well.', min_length=1, ), ] = None property_list: Annotated[ property_list_ref.PropertyListReference | None, Field( description='[AdCP 3.0] Reference to an externally managed property list. When provided, the sales agent should filter products to only those available on properties in the list.' ), ] = None refine: Annotated[ list[Refine | Refine1 | Refine2] | None, Field( description="Array of change requests for iterating on products and proposals from a previous get_products response. Each entry declares a scope (request, product, or proposal) and what the buyer is asking for. Only valid when buying_mode is 'refine'. The seller responds to each entry via refinement_applied in the response, matched by position.", min_length=1, ), ] = None required_policies: Annotated[ list[str] | None, Field( description='Registry policy IDs that the buyer requires to be enforced for products in this response. Sellers filter products to only those that comply with or already enforce the requested policies.' ), ] = None time_budget: Annotated[ duration.Duration | None, Field( description='Maximum time the buyer will commit to this request. The seller returns the best results achievable within this budget and does not start processes (human approvals, expensive external queries) that cannot complete in time. When omitted, the seller decides timing.' ), ] = NoneBase model for AdCP types with spec-compliant serialization.
Defaults to
extra='ignore'so that unknown fields from newer spec versions are silently dropped rather than causing validation errors. Generated types whose schemas setadditionalProperties: trueoverride this withextra='allow'in their ownmodel_config. Consumers who want strict validation can override withextra='forbid'.Create a new model by parsing and validating input data from keyword arguments.
Raises [
ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.selfis explicitly positional-only to allowselfas a field name.Ancestors
- AdCPBaseModel
- pydantic.main.BaseModel
Class variables
var account : AccountReference | Nonevar brand : BrandReference | Nonevar brief : str | Nonevar buying_mode : BuyingMode | Nonevar catalog : Catalog | Nonevar context : ContextObject | Nonevar ext : ExtensionObject | Nonevar fields : list[Field1] | Nonevar filters : ProductFilters | Nonevar model_configvar pagination : PaginationRequest | Nonevar preferred_delivery_types : list[DeliveryType] | Nonevar property_list : PropertyListReference | Nonevar refine : list[Refine | Refine1 | Refine2] | Nonevar required_policies : list[str] | Nonevar time_budget : Duration | None
Inherited members
class GetProductsResponse (**data: Any)-
Expand source code
class GetProductsResponse(AdCPBaseModel): model_config = ConfigDict( extra='allow', ) catalog_applied: Annotated[ bool | None, Field( description='Whether the seller filtered results based on the provided catalog. True if the seller matched catalog items against its inventory. Absent or false if no catalog was provided or the seller does not support catalog matching.' ), ] = None context: context_1.ContextObject | None = None errors: Annotated[ list[error.Error] | None, Field(description='Task-specific errors and warnings (e.g., product filtering issues)'), ] = None ext: ext_1.ExtensionObject | None = None incomplete: Annotated[ list[IncompleteItem] | None, Field( description="Declares what the seller could not finish within the buyer's time_budget or due to internal limits. Each entry identifies a scope that is missing or partial. Absent when the response is fully complete.", min_length=1, ), ] = None pagination: pagination_response.PaginationResponse | None = None products: Annotated[list[product_1.Product], Field(description='Array of matching products')] property_list_applied: Annotated[ bool | None, Field( description='[AdCP 3.0] Indicates whether property_list filtering was applied. True if the agent filtered products based on the provided property_list. Absent or false if property_list was not provided or not supported by this agent.' ), ] = None proposals: Annotated[ list[proposal_1.Proposal] | None, Field( description='Optional array of proposed media plans with budget allocations across products. Publishers include proposals when they can provide strategic guidance based on the brief. Proposals are actionable - buyers can refine them via follow-up get_products calls within the same session, or execute them directly via create_media_buy.' ), ] = None refinement_applied: Annotated[ list[RefinementAppliedItem] | None, Field( description="Seller's response to each change request in the refine array, matched by position. Each entry acknowledges whether the corresponding ask was applied, partially applied, or unable to be fulfilled. MUST contain the same number of entries in the same order as the request's refine array. Only present when the request used buying_mode: 'refine'." ), ] = None sandbox: Annotated[ bool | None, Field(description='When true, this response contains simulated data from sandbox mode.'), ] = NoneBase model for AdCP types with spec-compliant serialization.
Defaults to
extra='ignore'so that unknown fields from newer spec versions are silently dropped rather than causing validation errors. Generated types whose schemas setadditionalProperties: trueoverride this withextra='allow'in their ownmodel_config. Consumers who want strict validation can override withextra='forbid'.Create a new model by parsing and validating input data from keyword arguments.
Raises [
ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.selfis explicitly positional-only to allowselfas a field name.Ancestors
- AdCPBaseModel
- pydantic.main.BaseModel
Class variables
var catalog_applied : bool | Nonevar context : ContextObject | Nonevar errors : list[Error] | Nonevar ext : ExtensionObject | Nonevar incomplete : list[IncompleteItem] | Nonevar model_configvar pagination : PaginationResponse | Nonevar products : list[Product]var property_list_applied : bool | Nonevar proposals : list[Proposal] | Nonevar refinement_applied : list[RefinementAppliedItem] | Nonevar sandbox : bool | None
Inherited members
class GetRightsRequest (**data: Any)-
Expand source code
class GetRightsRequest(AdCPBaseModel): model_config = ConfigDict( extra='allow', ) brand_id: Annotated[ str | None, Field( description="Search within a specific brand's rights. If omitted, searches across the agent's full roster." ), ] = None buyer_brand: Annotated[ brand_ref.BrandReference | None, Field( description="The buyer's brand. The agent fetches the buyer's brand.json for compatibility filtering (e.g., dietary conflicts, competitor exclusions)." ), ] = None context: context_1.ContextObject | None = None countries: Annotated[ list[Country] | None, Field( description='Countries where rights are needed (ISO 3166-1 alpha-2). Filters to rights available in these markets.' ), ] = None ext: ext_1.ExtensionObject | None = None include_excluded: Annotated[ bool | None, Field( description='Include filtered-out results in the excluded array with reasons. Defaults to false.' ), ] = False pagination: Annotated[ pagination_request.PaginationRequest | None, Field(description='Pagination parameters for large result sets'), ] = None query: Annotated[ str, Field( description='Natural language description of desired rights. The agent interprets intent, budget signals, and compatibility from this text.', max_length=2000, ), ] right_type: Annotated[ right_type_1.RightType | None, Field(description='Filter by type of rights (talent, music, stock_media, etc.)'), ] = None uses: Annotated[ list[right_use.RightUse], Field( description='Rights uses being requested. The agent returns options covering these uses, potentially bundled into composite pricing.', min_length=1, ), ]Base model for AdCP types with spec-compliant serialization.
Defaults to
extra='ignore'so that unknown fields from newer spec versions are silently dropped rather than causing validation errors. Generated types whose schemas setadditionalProperties: trueoverride this withextra='allow'in their ownmodel_config. Consumers who want strict validation can override withextra='forbid'.Create a new model by parsing and validating input data from keyword arguments.
Raises [
ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.selfis explicitly positional-only to allowselfas a field name.Ancestors
- AdCPBaseModel
- pydantic.main.BaseModel
Class variables
var brand_id : str | Nonevar buyer_brand : BrandReference | Nonevar context : ContextObject | Nonevar countries : list[Country] | Nonevar ext : ExtensionObject | Nonevar include_excluded : bool | Nonevar model_configvar pagination : PaginationRequest | Nonevar query : strvar right_type : RightType | Nonevar uses : list[RightUse]
Inherited members
class GetRightsSuccessResponse (**data: Any)-
Expand source code
class GetRightsResponse1(AdCPBaseModel): model_config = ConfigDict( extra='allow', ) context: context_1.ContextObject | None = None excluded: Annotated[ list[ExcludedItem] | None, Field(description='Results that matched but were filtered out, with reasons'), ] = None ext: ext_1.ExtensionObject | None = None rights: Annotated[ list[Right], Field(description='Matching rights with pricing options, ranked by relevance') ]Base model for AdCP types with spec-compliant serialization.
Defaults to
extra='ignore'so that unknown fields from newer spec versions are silently dropped rather than causing validation errors. Generated types whose schemas setadditionalProperties: trueoverride this withextra='allow'in their ownmodel_config. Consumers who want strict validation can override withextra='forbid'.Create a new model by parsing and validating input data from keyword arguments.
Raises [
ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.selfis explicitly positional-only to allowselfas a field name.Ancestors
- AdCPBaseModel
- pydantic.main.BaseModel
Class variables
var context : ContextObject | Nonevar excluded : list[ExcludedItem] | Nonevar ext : ExtensionObject | Nonevar model_configvar rights : list[Right]
Inherited members
class GetRightsErrorResponse (**data: Any)-
Expand source code
class GetRightsResponse2(AdCPBaseModel): model_config = ConfigDict( extra='allow', ) context: context_1.ContextObject | None = None errors: Annotated[list[error.Error], Field(min_length=1)] ext: ext_1.ExtensionObject | None = NoneBase model for AdCP types with spec-compliant serialization.
Defaults to
extra='ignore'so that unknown fields from newer spec versions are silently dropped rather than causing validation errors. Generated types whose schemas setadditionalProperties: trueoverride this withextra='allow'in their ownmodel_config. Consumers who want strict validation can override withextra='forbid'.Create a new model by parsing and validating input data from keyword arguments.
Raises [
ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.selfis explicitly positional-only to allowselfas a field name.Ancestors
- AdCPBaseModel
- pydantic.main.BaseModel
Class variables
var context : ContextObject | Nonevar errors : list[Error]var ext : ExtensionObject | Nonevar model_config
Inherited members
class GetSignalsRequest (**data: Any)-
Expand source code
class GetSignalsRequest(AdCPBaseModel): model_config = ConfigDict( extra='allow', ) account: Annotated[ account_ref.AccountReference | None, Field( description='Account for this request. When provided, the signals agent returns per-account pricing options if configured.' ), ] = None context: context_1.ContextObject | None = None countries: Annotated[ list[Country] | None, Field( description='Countries where signals will be used (ISO 3166-1 alpha-2 codes). When omitted, no geographic filter is applied.', min_length=1, ), ] = None destinations: Annotated[ list[destination.Destination] | None, Field( description='Filter signals to those activatable on specific agents/platforms. When omitted, returns all signals available on the current agent. If the authenticated caller matches one of these destinations, activation keys will be included in the response.', min_length=1, ), ] = None ext: ext_1.ExtensionObject | None = None filters: signal_filters.SignalFilters | None = None max_results: Annotated[ int | None, Field(description='Maximum number of results to return', ge=1) ] = None pagination: pagination_request.PaginationRequest | None = None signal_ids: Annotated[ list[signal_id.SignalId] | None, Field( description="Specific signals to look up by data provider and ID. Returns exact matches from the data provider's catalog. When combined with signal_spec, these signals anchor the starting set and signal_spec guides adjustments.", min_length=1, ), ] = None signal_spec: Annotated[ str | None, Field( description='Natural language description of the desired signals. When used alone, enables semantic discovery. When combined with signal_ids, provides context for the agent but signal_ids matches are returned first.' ), ] = NoneBase model for AdCP types with spec-compliant serialization.
Defaults to
extra='ignore'so that unknown fields from newer spec versions are silently dropped rather than causing validation errors. Generated types whose schemas setadditionalProperties: trueoverride this withextra='allow'in their ownmodel_config. Consumers who want strict validation can override withextra='forbid'.Create a new model by parsing and validating input data from keyword arguments.
Raises [
ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.selfis explicitly positional-only to allowselfas a field name.Ancestors
- AdCPBaseModel
- pydantic.main.BaseModel
Class variables
var account : AccountReference | Nonevar context : ContextObject | Nonevar countries : list[Country] | Nonevar destinations : list[Destination] | Nonevar ext : ExtensionObject | Nonevar filters : SignalFilters | Nonevar max_results : int | Nonevar model_configvar pagination : PaginationRequest | Nonevar signal_ids : list[SignalId] | Nonevar signal_spec : str | None
class GetSignalsDiscoveryRequest (**data: Any)-
Expand source code
class GetSignalsRequest(AdCPBaseModel): model_config = ConfigDict( extra='allow', ) account: Annotated[ account_ref.AccountReference | None, Field( description='Account for this request. When provided, the signals agent returns per-account pricing options if configured.' ), ] = None context: context_1.ContextObject | None = None countries: Annotated[ list[Country] | None, Field( description='Countries where signals will be used (ISO 3166-1 alpha-2 codes). When omitted, no geographic filter is applied.', min_length=1, ), ] = None destinations: Annotated[ list[destination.Destination] | None, Field( description='Filter signals to those activatable on specific agents/platforms. When omitted, returns all signals available on the current agent. If the authenticated caller matches one of these destinations, activation keys will be included in the response.', min_length=1, ), ] = None ext: ext_1.ExtensionObject | None = None filters: signal_filters.SignalFilters | None = None max_results: Annotated[ int | None, Field(description='Maximum number of results to return', ge=1) ] = None pagination: pagination_request.PaginationRequest | None = None signal_ids: Annotated[ list[signal_id.SignalId] | None, Field( description="Specific signals to look up by data provider and ID. Returns exact matches from the data provider's catalog. When combined with signal_spec, these signals anchor the starting set and signal_spec guides adjustments.", min_length=1, ), ] = None signal_spec: Annotated[ str | None, Field( description='Natural language description of the desired signals. When used alone, enables semantic discovery. When combined with signal_ids, provides context for the agent but signal_ids matches are returned first.' ), ] = NoneBase model for AdCP types with spec-compliant serialization.
Defaults to
extra='ignore'so that unknown fields from newer spec versions are silently dropped rather than causing validation errors. Generated types whose schemas setadditionalProperties: trueoverride this withextra='allow'in their ownmodel_config. Consumers who want strict validation can override withextra='forbid'.Create a new model by parsing and validating input data from keyword arguments.
Raises [
ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.selfis explicitly positional-only to allowselfas a field name.Ancestors
- AdCPBaseModel
- pydantic.main.BaseModel
Class variables
var account : AccountReference | Nonevar context : ContextObject | Nonevar countries : list[Country] | Nonevar destinations : list[Destination] | Nonevar ext : ExtensionObject | Nonevar filters : SignalFilters | Nonevar max_results : int | Nonevar model_configvar pagination : PaginationRequest | Nonevar signal_ids : list[SignalId] | Nonevar signal_spec : str | None
class GetSignalsLookupRequest (**data: Any)-
Expand source code
class GetSignalsRequest(AdCPBaseModel): model_config = ConfigDict( extra='allow', ) account: Annotated[ account_ref.AccountReference | None, Field( description='Account for this request. When provided, the signals agent returns per-account pricing options if configured.' ), ] = None context: context_1.ContextObject | None = None countries: Annotated[ list[Country] | None, Field( description='Countries where signals will be used (ISO 3166-1 alpha-2 codes). When omitted, no geographic filter is applied.', min_length=1, ), ] = None destinations: Annotated[ list[destination.Destination] | None, Field( description='Filter signals to those activatable on specific agents/platforms. When omitted, returns all signals available on the current agent. If the authenticated caller matches one of these destinations, activation keys will be included in the response.', min_length=1, ), ] = None ext: ext_1.ExtensionObject | None = None filters: signal_filters.SignalFilters | None = None max_results: Annotated[ int | None, Field(description='Maximum number of results to return', ge=1) ] = None pagination: pagination_request.PaginationRequest | None = None signal_ids: Annotated[ list[signal_id.SignalId] | None, Field( description="Specific signals to look up by data provider and ID. Returns exact matches from the data provider's catalog. When combined with signal_spec, these signals anchor the starting set and signal_spec guides adjustments.", min_length=1, ), ] = None signal_spec: Annotated[ str | None, Field( description='Natural language description of the desired signals. When used alone, enables semantic discovery. When combined with signal_ids, provides context for the agent but signal_ids matches are returned first.' ), ] = NoneBase model for AdCP types with spec-compliant serialization.
Defaults to
extra='ignore'so that unknown fields from newer spec versions are silently dropped rather than causing validation errors. Generated types whose schemas setadditionalProperties: trueoverride this withextra='allow'in their ownmodel_config. Consumers who want strict validation can override withextra='forbid'.Create a new model by parsing and validating input data from keyword arguments.
Raises [
ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.selfis explicitly positional-only to allowselfas a field name.Ancestors
- AdCPBaseModel
- pydantic.main.BaseModel
Class variables
var account : AccountReference | Nonevar context : ContextObject | Nonevar countries : list[Country] | Nonevar destinations : list[Destination] | Nonevar ext : ExtensionObject | Nonevar filters : SignalFilters | Nonevar max_results : int | Nonevar model_configvar pagination : PaginationRequest | Nonevar signal_ids : list[SignalId] | Nonevar signal_spec : str | None
Inherited members
class GetSignalsResponse (**data: Any)-
Expand source code
class GetSignalsResponse(AdCPBaseModel): model_config = ConfigDict( extra='allow', ) context: context_1.ContextObject | None = None errors: Annotated[ list[error.Error] | None, Field( description='Task-specific errors and warnings (e.g., signal discovery or pricing issues)' ), ] = None ext: ext_1.ExtensionObject | None = None pagination: pagination_response.PaginationResponse | None = None sandbox: Annotated[ bool | None, Field(description='When true, this response contains simulated data from sandbox mode.'), ] = None signals: Annotated[list[Signal], Field(description='Array of matching signals')]Base model for AdCP types with spec-compliant serialization.
Defaults to
extra='ignore'so that unknown fields from newer spec versions are silently dropped rather than causing validation errors. Generated types whose schemas setadditionalProperties: trueoverride this withextra='allow'in their ownmodel_config. Consumers who want strict validation can override withextra='forbid'.Create a new model by parsing and validating input data from keyword arguments.
Raises [
ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.selfis explicitly positional-only to allowselfas a field name.Ancestors
- AdCPBaseModel
- pydantic.main.BaseModel
Class variables
var context : ContextObject | Nonevar errors : list[Error] | Nonevar ext : ExtensionObject | Nonevar model_configvar pagination : PaginationResponse | Nonevar sandbox : bool | Nonevar signals : list[Signal]
Inherited members
class Gtin (root: RootModelRootType = PydanticUndefined, **data)-
Expand source code
class Gtin(RootModel[str]): root: Annotated[str, Field(pattern='^[0-9]{8,14}$')]Usage Documentation
A Pydantic
BaseModelfor the root object of the model.Attributes
root- The root object of the model.
__pydantic_root_model__- Whether the model is a RootModel.
__pydantic_private__- Private fields in the model.
__pydantic_extra__- Extra fields in the model.
Create a new model by parsing and validating input data from keyword arguments.
Raises [
ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.selfis explicitly positional-only to allowselfas a field name.Ancestors
- pydantic.root_model.RootModel[str]
- pydantic.root_model.RootModel
- pydantic.main.BaseModel
- typing.Generic
Class variables
var model_configvar root : str
class IdentityMatchRequest (**data: Any)-
Expand source code
class IdentityMatchRequest(AdCPBaseModel): model_config = ConfigDict( extra='forbid', ) field_schema: Annotated[ AnyUrl | None, Field( alias='$schema', description='Optional schema URI for validation. Ignored at runtime.' ), ] = None consent: Annotated[ Consent | None, Field( description='Privacy consent signals. Buyers in regulated jurisdictions MUST NOT process the user token without consent information.' ), ] = None package_ids: Annotated[ list[str], Field( description='ALL active package identifiers for this buyer at this publisher. MUST include every active package, not just those on the current page, to prevent correlation with Context Match requests.', min_length=1, ), ] protocol_version: Annotated[ str | None, Field( description='TMP protocol version. Allows receivers to handle semantic differences across versions.' ), ] = '1.0' request_id: Annotated[ str, Field( description='Unique request identifier. MUST NOT correlate with any context match request_id.' ), ] type: Annotated[ Literal['identity_match_request'], Field(description='Message type discriminator for deserialization.'), ] uid_type: Annotated[ uid_type_1.UidType, Field( description='Type of the user identifier. Tells the buyer which identity graph to resolve against, avoiding trial-and-error matching.' ), ] user_token: Annotated[ str, Field( description='Opaque token from an identity provider (ID5, LiveRamp, UID2) or publisher-generated' ), ]Base model for AdCP types with spec-compliant serialization.
Defaults to
extra='ignore'so that unknown fields from newer spec versions are silently dropped rather than causing validation errors. Generated types whose schemas setadditionalProperties: trueoverride this withextra='allow'in their ownmodel_config. Consumers who want strict validation can override withextra='forbid'.Create a new model by parsing and validating input data from keyword arguments.
Raises [
ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.selfis explicitly positional-only to allowselfas a field name.Ancestors
- AdCPBaseModel
- pydantic.main.BaseModel
Class variables
var consent : Consent | Nonevar field_schema : pydantic.networks.AnyUrl | Nonevar model_configvar package_ids : list[str]var protocol_version : str | Nonevar request_id : strvar type : Literal['identity_match_request']var uid_type : UidTypevar user_token : str
Inherited members
class IdentityMatchResponse (**data: Any)-
Expand source code
class IdentityMatchResponse(AdCPBaseModel): model_config = ConfigDict( extra='allow', ) eligible_package_ids: Annotated[ list[str], Field( description='Package IDs the user is eligible for. Packages not listed are ineligible.' ), ] request_id: Annotated[ str, Field(description='Echoed request identifier from the identity match request') ] ttl_sec: Annotated[ int, Field( description='How long the router should cache this response, in seconds. The router returns cached eligibility without re-querying the buyer during this window. A value of 0 means do not cache.', ge=0, le=86400, ), ] type: Annotated[ Literal['identity_match_response'], Field(description='Message type discriminator for deserialization.'), ]Base model for AdCP types with spec-compliant serialization.
Defaults to
extra='ignore'so that unknown fields from newer spec versions are silently dropped rather than causing validation errors. Generated types whose schemas setadditionalProperties: trueoverride this withextra='allow'in their ownmodel_config. Consumers who want strict validation can override withextra='forbid'.Create a new model by parsing and validating input data from keyword arguments.
Raises [
ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.selfis explicitly positional-only to allowselfas a field name.Ancestors
- AdCPBaseModel
- pydantic.main.BaseModel
Class variables
var eligible_package_ids : list[str]var model_configvar request_id : strvar ttl_sec : intvar type : Literal['identity_match_response']
Inherited members
class ListAccountsRequest (**data: Any)-
Expand source code
class ListAccountsRequest(AdCPBaseModel): model_config = ConfigDict( extra='allow', ) context: context_1.ContextObject | None = None ext: ext_1.ExtensionObject | None = None pagination: pagination_request.PaginationRequest | None = None sandbox: Annotated[ bool | None, Field( description='Filter by sandbox status. true returns only sandbox accounts, false returns only production accounts. Omit to return all accounts. Primarily used with explicit accounts (require_operator_auth: true) where sandbox accounts are pre-existing test accounts on the platform.' ), ] = None status: Annotated[ Status | None, Field(description='Filter accounts by status. Omit to return accounts in all statuses.'), ] = NoneBase model for AdCP types with spec-compliant serialization.
Defaults to
extra='ignore'so that unknown fields from newer spec versions are silently dropped rather than causing validation errors. Generated types whose schemas setadditionalProperties: trueoverride this withextra='allow'in their ownmodel_config. Consumers who want strict validation can override withextra='forbid'.Create a new model by parsing and validating input data from keyword arguments.
Raises [
ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.selfis explicitly positional-only to allowselfas a field name.Ancestors
- AdCPBaseModel
- pydantic.main.BaseModel
Class variables
var context : ContextObject | Nonevar ext : ExtensionObject | Nonevar model_configvar pagination : PaginationRequest | Nonevar sandbox : bool | Nonevar status : Status | None
Inherited members
class ListAccountsResponse (**data: Any)-
Expand source code
class ListAccountsResponse(AdCPBaseModel): model_config = ConfigDict( extra='allow', ) accounts: Annotated[ list[account.Account], Field(description='Array of accounts accessible to the authenticated agent'), ] context: context_1.ContextObject | None = None errors: Annotated[ list[error.Error] | None, Field(description='Task-specific errors and warnings') ] = None ext: ext_1.ExtensionObject | None = None pagination: pagination_response.PaginationResponse | None = NoneBase model for AdCP types with spec-compliant serialization.
Defaults to
extra='ignore'so that unknown fields from newer spec versions are silently dropped rather than causing validation errors. Generated types whose schemas setadditionalProperties: trueoverride this withextra='allow'in their ownmodel_config. Consumers who want strict validation can override withextra='forbid'.Create a new model by parsing and validating input data from keyword arguments.
Raises [
ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.selfis explicitly positional-only to allowselfas a field name.Ancestors
- AdCPBaseModel
- pydantic.main.BaseModel
Class variables
var accounts : list[Account]var context : ContextObject | Nonevar errors : list[Error] | Nonevar ext : ExtensionObject | Nonevar model_configvar pagination : PaginationResponse | None
Inherited members
class ListContentStandardsSuccessResponse (**data: Any)-
Expand source code
class ListContentStandardsResponse1(AdCPBaseModel): context: context_1.ContextObject | None = None ext: ext_1.ExtensionObject | None = None pagination: pagination_response.PaginationResponse | None = None standards: Annotated[ list[content_standards.ContentStandards], Field(description='Array of content standards configurations matching the filter criteria'), ]Base model for AdCP types with spec-compliant serialization.
Defaults to
extra='ignore'so that unknown fields from newer spec versions are silently dropped rather than causing validation errors. Generated types whose schemas setadditionalProperties: trueoverride this withextra='allow'in their ownmodel_config. Consumers who want strict validation can override withextra='forbid'.Create a new model by parsing and validating input data from keyword arguments.
Raises [
ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.selfis explicitly positional-only to allowselfas a field name.Ancestors
- AdCPBaseModel
- pydantic.main.BaseModel
Class variables
var context : ContextObject | Nonevar ext : ExtensionObject | Nonevar model_configvar pagination : PaginationResponse | Nonevar standards : list[ContentStandards]
Inherited members
class ListContentStandardsErrorResponse (**data: Any)-
Expand source code
class ListContentStandardsResponse2(AdCPBaseModel): context: context_1.ContextObject | None = None errors: list[error.Error] ext: ext_1.ExtensionObject | None = NoneBase model for AdCP types with spec-compliant serialization.
Defaults to
extra='ignore'so that unknown fields from newer spec versions are silently dropped rather than causing validation errors. Generated types whose schemas setadditionalProperties: trueoverride this withextra='allow'in their ownmodel_config. Consumers who want strict validation can override withextra='forbid'.Create a new model by parsing and validating input data from keyword arguments.
Raises [
ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.selfis explicitly positional-only to allowselfas a field name.Ancestors
- AdCPBaseModel
- pydantic.main.BaseModel
Class variables
var context : ContextObject | Nonevar errors : list[Error]var ext : ExtensionObject | Nonevar model_config
Inherited members
class ListCreativeFormatsRequest (**data: Any)-
Expand source code
class ListCreativeFormatsRequest(AdCPBaseModel): model_config = ConfigDict( extra='allow', ) asset_types: Annotated[ list[asset_content_type.AssetContentType] | None, Field( description="Filter to formats that include these asset types. For third-party tags, search for 'html' or 'javascript'. E.g., ['image', 'text'] returns formats with images and text, ['javascript'] returns formats accepting JavaScript tags.", min_length=1, ), ] = None context: context_1.ContextObject | None = None disclosure_persistence: Annotated[ list[disclosure_persistence_1.DisclosurePersistence] | None, Field( description='Filter to formats where each requested persistence mode is supported by at least one position in disclosure_capabilities. Different positions may satisfy different modes. Use to find formats compatible with jurisdiction-specific persistence requirements (e.g., continuous for EU AI Act).', min_length=1, ), ] = None disclosure_positions: Annotated[ list[disclosure_position.DisclosurePosition] | None, Field( description="Filter to formats that support all of these disclosure positions. When a format has disclosure_capabilities, match against those positions. Otherwise fall back to supported_disclosure_positions. Use to find formats compatible with a brief's compliance requirements.", min_length=1, ), ] = None ext: ext_1.ExtensionObject | None = None format_ids: Annotated[ list[format_id.FormatId] | None, Field( description='Return only these specific format IDs (e.g., from get_products response)', min_length=1, ), ] = None input_format_ids: Annotated[ list[format_id.FormatId] | None, Field( description="Filter to formats whose input_format_ids includes any of these format IDs. Returns formats that accept these creatives as input — inspect each result's output_format_ids to see what they can produce.", min_length=1, ), ] = None is_responsive: Annotated[ bool | None, Field( description='Filter for responsive formats that adapt to container size. When true, returns formats without fixed dimensions.' ), ] = None max_height: Annotated[ int | None, Field( description='Maximum height in pixels (inclusive). Returns formats where ANY render has height <= this value. For multi-render formats, matches if at least one render fits.' ), ] = None max_width: Annotated[ int | None, Field( description='Maximum width in pixels (inclusive). Returns formats where ANY render has width <= this value. For multi-render formats, matches if at least one render fits.' ), ] = None min_height: Annotated[ int | None, Field( description='Minimum height in pixels (inclusive). Returns formats where ANY render has height >= this value.' ), ] = None min_width: Annotated[ int | None, Field( description='Minimum width in pixels (inclusive). Returns formats where ANY render has width >= this value.' ), ] = None name_search: Annotated[ str | None, Field(description='Search for formats by name (case-insensitive partial match)') ] = None output_format_ids: Annotated[ list[format_id.FormatId] | None, Field( description="Filter to formats whose output_format_ids includes any of these format IDs. Returns formats that can produce these outputs — inspect each result's input_format_ids to see what inputs they accept.", min_length=1, ), ] = None pagination: pagination_request.PaginationRequest | None = None wcag_level: Annotated[ wcag_level_1.WcagLevel | None, Field( description='Filter to formats that meet at least this WCAG conformance level (A < AA < AAA)' ), ] = NoneBase model for AdCP types with spec-compliant serialization.
Defaults to
extra='ignore'so that unknown fields from newer spec versions are silently dropped rather than causing validation errors. Generated types whose schemas setadditionalProperties: trueoverride this withextra='allow'in their ownmodel_config. Consumers who want strict validation can override withextra='forbid'.Create a new model by parsing and validating input data from keyword arguments.
Raises [
ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.selfis explicitly positional-only to allowselfas a field name.Ancestors
- AdCPBaseModel
- pydantic.main.BaseModel
Class variables
var asset_types : list[AssetContentType] | Nonevar context : ContextObject | Nonevar disclosure_persistence : list[DisclosurePersistence] | Nonevar disclosure_positions : list[DisclosurePosition] | Nonevar ext : ExtensionObject | Nonevar format_ids : list[FormatId] | Nonevar input_format_ids : list[FormatId] | Nonevar is_responsive : bool | Nonevar max_height : int | Nonevar max_width : int | Nonevar min_height : int | Nonevar min_width : int | Nonevar model_configvar name_search : str | Nonevar output_format_ids : list[FormatId] | Nonevar pagination : PaginationRequest | Nonevar wcag_level : WcagLevel | None
Inherited members
class ListCreativeFormatsResponse (**data: Any)-
Expand source code
class ListCreativeFormatsResponse(AdCPBaseModel): model_config = ConfigDict( extra='allow', ) context: context_1.ContextObject | None = None creative_agents: Annotated[ list[CreativeAgent] | None, Field( description='Optional: Creative agents that provide additional formats. Buyers can recursively query these agents to discover more formats. No authentication required for list_creative_formats.' ), ] = None errors: Annotated[ list[error.Error] | None, Field(description='Task-specific errors and warnings (e.g., format availability issues)'), ] = None ext: ext_1.ExtensionObject | None = None formats: Annotated[ list[format.Format], Field( description="Full format definitions for all formats this agent supports. Each format's authoritative source is indicated by its agent_url field." ), ] pagination: pagination_response.PaginationResponse | None = None sandbox: Annotated[ bool | None, Field(description='When true, this response contains simulated data from sandbox mode.'), ] = NoneBase model for AdCP types with spec-compliant serialization.
Defaults to
extra='ignore'so that unknown fields from newer spec versions are silently dropped rather than causing validation errors. Generated types whose schemas setadditionalProperties: trueoverride this withextra='allow'in their ownmodel_config. Consumers who want strict validation can override withextra='forbid'.Create a new model by parsing and validating input data from keyword arguments.
Raises [
ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.selfis explicitly positional-only to allowselfas a field name.Ancestors
- AdCPBaseModel
- pydantic.main.BaseModel
Class variables
var context : ContextObject | Nonevar creative_agents : list[CreativeAgent] | Nonevar errors : list[Error] | Nonevar ext : ExtensionObject | Nonevar formats : list[Format]var model_configvar pagination : PaginationResponse | Nonevar sandbox : bool | None
Inherited members
class ListCreativesRequest (**data: Any)-
Expand source code
class ListCreativesRequest(AdCPBaseModel): model_config = ConfigDict( extra='allow', ) context: context_1.ContextObject | None = None ext: ext_1.ExtensionObject | None = None fields: Annotated[ list[Field1] | None, Field( description="Specific fields to include in response (omit for all fields). The 'concept' value returns both concept_id and concept_name.", min_length=1, ), ] = None filters: creative_filters.CreativeFilters | None = None include_assignments: Annotated[ bool | None, Field(description='Include package assignment information in response') ] = True include_items: Annotated[ bool | None, Field(description='Include items for multi-asset formats like carousels and native ads'), ] = False include_snapshot: Annotated[ bool | None, Field( description='Include a lightweight delivery snapshot per creative (lifetime impressions and last-served date). For detailed performance analytics, use get_creative_delivery.' ), ] = False include_variables: Annotated[ bool | None, Field( description='Include dynamic content variable definitions (DCO slots) for each creative' ), ] = False pagination: pagination_request.PaginationRequest | None = None sort: Annotated[Sort | None, Field(description='Sorting parameters')] = NoneBase model for AdCP types with spec-compliant serialization.
Defaults to
extra='ignore'so that unknown fields from newer spec versions are silently dropped rather than causing validation errors. Generated types whose schemas setadditionalProperties: trueoverride this withextra='allow'in their ownmodel_config. Consumers who want strict validation can override withextra='forbid'.Create a new model by parsing and validating input data from keyword arguments.
Raises [
ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.selfis explicitly positional-only to allowselfas a field name.Ancestors
- AdCPBaseModel
- pydantic.main.BaseModel
Class variables
var context : ContextObject | Nonevar ext : ExtensionObject | Nonevar fields : list[Field1] | Nonevar filters : CreativeFilters | Nonevar include_assignments : bool | Nonevar include_items : bool | Nonevar include_snapshot : bool | Nonevar include_variables : bool | Nonevar model_configvar pagination : PaginationRequest | Nonevar sort : Sort | None
Inherited members
class ListCreativesResponse (**data: Any)-
Expand source code
class ListCreativesResponse(AdCPBaseModel): model_config = ConfigDict( extra='allow', ) context: context_1.ContextObject | None = None creatives: Annotated[ list[Creative], Field(description='Array of creative assets matching the query') ] errors: Annotated[ list[error.Error] | None, Field(description='Task-specific errors (e.g., invalid filters, account not found)'), ] = None ext: ext_1.ExtensionObject | None = None format_summary: Annotated[ dict[Annotated[str, StringConstraints(pattern=r'^[a-zA-Z0-9_-]+$')], int] | None, Field( description="Breakdown of creatives by format. Keys are agent-defined format identifiers, optionally including dimensions (e.g., 'display_static_300x250', 'video_30s_vast'). Key construction is platform-specific — there is no required format." ), ] = None pagination: pagination_response.PaginationResponse query_summary: Annotated[ QuerySummary, Field(description='Summary of the query that was executed') ] sandbox: Annotated[ bool | None, Field(description='When true, this response contains simulated data from sandbox mode.'), ] = None status_summary: Annotated[ StatusSummary | None, Field(description='Breakdown of creatives by status') ] = NoneBase model for AdCP types with spec-compliant serialization.
Defaults to
extra='ignore'so that unknown fields from newer spec versions are silently dropped rather than causing validation errors. Generated types whose schemas setadditionalProperties: trueoverride this withextra='allow'in their ownmodel_config. Consumers who want strict validation can override withextra='forbid'.Create a new model by parsing and validating input data from keyword arguments.
Raises [
ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.selfis explicitly positional-only to allowselfas a field name.Ancestors
- AdCPBaseModel
- pydantic.main.BaseModel
Class variables
var context : ContextObject | Nonevar creatives : list[Creative]var errors : list[Error] | Nonevar ext : ExtensionObject | Nonevar format_summary : dict[str, int] | Nonevar model_configvar pagination : PaginationResponsevar query_summary : QuerySummaryvar sandbox : bool | Nonevar status_summary : StatusSummary | None
Inherited members
class LogEventRequest (**data: Any)-
Expand source code
class LogEventRequest(AdCPBaseModel): model_config = ConfigDict( extra='allow', ) context: context_1.ContextObject | None = None event_source_id: Annotated[ str, Field(description='Event source configured on the account via sync_event_sources') ] events: Annotated[ list[event.Event], Field(description='Events to log', max_length=10000, min_length=1) ] ext: ext_1.ExtensionObject | None = None idempotency_key: Annotated[ str | None, Field( description='Client-generated unique key for this request. Prevents duplicate event logging on retries. MUST be unique per (seller, request) pair to prevent cross-seller correlation. Use a fresh UUID v4 for each request.', max_length=255, min_length=16, ), ] = None test_event_code: Annotated[ str | None, Field( description="Test event code for validation without affecting production data. Events with this code appear in the platform's test events UI." ), ] = NoneBase model for AdCP types with spec-compliant serialization.
Defaults to
extra='ignore'so that unknown fields from newer spec versions are silently dropped rather than causing validation errors. Generated types whose schemas setadditionalProperties: trueoverride this withextra='allow'in their ownmodel_config. Consumers who want strict validation can override withextra='forbid'.Create a new model by parsing and validating input data from keyword arguments.
Raises [
ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.selfis explicitly positional-only to allowselfas a field name.Ancestors
- AdCPBaseModel
- pydantic.main.BaseModel
Class variables
var context : ContextObject | Nonevar event_source_id : strvar events : list[Event]var ext : ExtensionObject | Nonevar idempotency_key : str | Nonevar model_configvar test_event_code : str | None
Inherited members
class LogEventSuccessResponse (**data: Any)-
Expand source code
class LogEventResponse1(AdCPBaseModel): model_config = ConfigDict( extra='allow', ) context: context_1.ContextObject | None = None events_processed: Annotated[ int, Field(description='Number of events successfully queued for processing', ge=0) ] events_received: Annotated[int, Field(description='Number of events received', ge=0)] ext: ext_1.ExtensionObject | None = None match_quality: Annotated[ float | None, Field( description='Overall match quality score for the batch (0.0 = no matches, 1.0 = all matched)', ge=0.0, le=1.0, ), ] = None partial_failures: Annotated[ list[PartialFailure] | None, Field(description='Events that failed validation') ] = None sandbox: Annotated[ bool | None, Field(description='When true, this response contains simulated data from sandbox mode.'), ] = None warnings: Annotated[ list[str] | None, Field( description='Non-fatal issues (low match quality, missing recommended fields, deprecation notices)' ), ] = NoneBase model for AdCP types with spec-compliant serialization.
Defaults to
extra='ignore'so that unknown fields from newer spec versions are silently dropped rather than causing validation errors. Generated types whose schemas setadditionalProperties: trueoverride this withextra='allow'in their ownmodel_config. Consumers who want strict validation can override withextra='forbid'.Create a new model by parsing and validating input data from keyword arguments.
Raises [
ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.selfis explicitly positional-only to allowselfas a field name.Ancestors
- AdCPBaseModel
- pydantic.main.BaseModel
Class variables
var context : ContextObject | Nonevar events_processed : intvar events_received : intvar ext : ExtensionObject | Nonevar match_quality : float | Nonevar model_configvar partial_failures : list[PartialFailure] | Nonevar sandbox : bool | Nonevar warnings : list[str] | None
Inherited members
class LogEventErrorResponse (**data: Any)-
Expand source code
class LogEventResponse2(AdCPBaseModel): model_config = ConfigDict( extra='allow', ) context: context_1.ContextObject | None = None errors: Annotated[list[error.Error], Field(description='Operation-level errors', min_length=1)] ext: ext_1.ExtensionObject | None = NoneBase model for AdCP types with spec-compliant serialization.
Defaults to
extra='ignore'so that unknown fields from newer spec versions are silently dropped rather than causing validation errors. Generated types whose schemas setadditionalProperties: trueoverride this withextra='allow'in their ownmodel_config. Consumers who want strict validation can override withextra='forbid'.Create a new model by parsing and validating input data from keyword arguments.
Raises [
ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.selfis explicitly positional-only to allowselfas a field name.Ancestors
- AdCPBaseModel
- pydantic.main.BaseModel
Class variables
var context : ContextObject | Nonevar errors : list[Error]var ext : ExtensionObject | Nonevar model_config
Inherited members
class McpWebhookPayload (**data: Any)-
Expand source code
class McpWebhookPayload(AdCPBaseModel): model_config = ConfigDict( extra='allow', ) context_id: Annotated[ str | None, Field( description='Session/conversation identifier. Use this to continue the conversation if input-required status needs clarification or additional parameters.' ), ] = None domain: Annotated[ adcp_domain.AdcpDomain | None, Field( description='AdCP domain this task belongs to. Helps classify the operation type at a high level.' ), ] = None message: Annotated[ str | None, Field( description='Human-readable summary of the current task state. Provides context about what happened and what action may be needed.' ), ] = None operation_id: Annotated[ str | None, Field( description='Client-generated identifier that was embedded in the webhook URL by the buyer. Publishers echo this back in webhook payloads so clients can correlate notifications without parsing URL paths. Typically generated as a unique ID per task invocation.' ), ] = None result: Annotated[ async_response_data.AdcpAsyncResponseData | None, Field( description='Task-specific payload matching the status. For completed/failed, contains the full task response. For working/input-required/submitted, contains status-specific data. This is the data layer that AdCP specs - same structure used in A2A status.message.parts[].data.' ), ] = None status: Annotated[ task_status.TaskStatus, Field( description='Current task status. Webhooks are triggered for status changes after initial submission.' ), ] task_id: Annotated[ str, Field( description='Unique identifier for this task. Use this to correlate webhook notifications with the original task submission.' ), ] task_type: Annotated[ task_type_1.TaskType, Field( description='Type of AdCP operation that triggered this webhook. Enables webhook handlers to route to appropriate processing logic.' ), ] timestamp: Annotated[ AwareDatetime, Field(description='ISO 8601 timestamp when this webhook was generated.') ]Base model for AdCP types with spec-compliant serialization.
Defaults to
extra='ignore'so that unknown fields from newer spec versions are silently dropped rather than causing validation errors. Generated types whose schemas setadditionalProperties: trueoverride this withextra='allow'in their ownmodel_config. Consumers who want strict validation can override withextra='forbid'.Create a new model by parsing and validating input data from keyword arguments.
Raises [
ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.selfis explicitly positional-only to allowselfas a field name.Ancestors
- AdCPBaseModel
- pydantic.main.BaseModel
Class variables
var context_id : str | Nonevar domain : AdcpDomain | Nonevar message : str | Nonevar model_configvar operation_id : str | Nonevar result : AdcpAsyncResponseData | Nonevar status : TaskStatusvar task_id : strvar task_type : TaskTypevar timestamp : pydantic.types.AwareDatetime
Inherited members
class MediaBuy (**data: Any)-
Expand source code
class MediaBuy(AdCPBaseModel): model_config = ConfigDict( extra='allow', ) account: Annotated[ account_1.Account | None, Field(description='Account billed for this media buy') ] = None cancellation: Annotated[ Cancellation | None, Field(description="Cancellation metadata. Present only when status is 'canceled'."), ] = None confirmed_at: Annotated[ AwareDatetime | None, Field( description='ISO 8601 timestamp when the seller confirmed this media buy. A successful create_media_buy response constitutes order confirmation.' ), ] = None created_at: Annotated[AwareDatetime | None, Field(description='Creation timestamp')] = None creative_deadline: Annotated[ AwareDatetime | None, Field(description='ISO 8601 timestamp for creative upload deadline') ] = None ext: ext_1.ExtensionObject | None = None invoice_recipient: Annotated[ business_entity.BusinessEntity | None, Field( description="Per-buy override for who receives the invoice. When provided, the seller invoices this entity instead of the account's default billing_entity. The seller MUST validate the invoice recipient is authorized for this account. When governance_agents are configured, the seller MUST include invoice_recipient in the check_governance request." ), ] = None media_buy_id: Annotated[str, Field(description="Seller's unique identifier for the media buy")] packages: Annotated[ list[package.Package], Field(description='Array of packages within this media buy') ] rejection_reason: Annotated[ str | None, Field( description="Reason provided by the seller when status is 'rejected'. Present only when status is 'rejected'." ), ] = None revision: Annotated[ int | None, Field( description='Monotonically increasing revision number. Incremented on every state change or update. Callers MAY include this in update_media_buy requests for optimistic concurrency — sellers MUST reject with CONFLICT if the provided revision does not match the current value.', ge=1, ), ] = None status: media_buy_status.MediaBuyStatus total_budget: Annotated[float, Field(description='Total budget amount', ge=0.0)] updated_at: Annotated[AwareDatetime | None, Field(description='Last update timestamp')] = NoneBase model for AdCP types with spec-compliant serialization.
Defaults to
extra='ignore'so that unknown fields from newer spec versions are silently dropped rather than causing validation errors. Generated types whose schemas setadditionalProperties: trueoverride this withextra='allow'in their ownmodel_config. Consumers who want strict validation can override withextra='forbid'.Create a new model by parsing and validating input data from keyword arguments.
Raises [
ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.selfis explicitly positional-only to allowselfas a field name.Ancestors
- AdCPBaseModel
- pydantic.main.BaseModel
Class variables
var account : Account | Nonevar cancellation : Cancellation | Nonevar confirmed_at : pydantic.types.AwareDatetime | Nonevar created_at : pydantic.types.AwareDatetime | Nonevar creative_deadline : pydantic.types.AwareDatetime | Nonevar ext : ExtensionObject | Nonevar invoice_recipient : BusinessEntity | Nonevar media_buy_id : strvar model_configvar packages : list[Package]var rejection_reason : str | Nonevar revision : int | Nonevar status : MediaBuyStatusvar total_budget : floatvar updated_at : pydantic.types.AwareDatetime | None
Inherited members
class MediaBuyStatus (*args, **kwds)-
Expand source code
class MediaBuyStatus(Enum): pending_activation = 'pending_activation' active = 'active' paused = 'paused' completed = 'completed' rejected = 'rejected' canceled = 'canceled'Create a collection of name/value pairs.
Example enumeration:
>>> class Color(Enum): ... RED = 1 ... BLUE = 2 ... GREEN = 3Access them by:
- attribute access::
>>> Color.RED <Color.RED: 1>- value lookup:
>>> Color(1) <Color.RED: 1>- name lookup:
>>> Color['RED'] <Color.RED: 1>Enumerations can be iterated over, and know how many members they have:
>>> len(Color) 3>>> list(Color) [<Color.RED: 1>, <Color.BLUE: 2>, <Color.GREEN: 3>]Methods can be added to enumerations, and members can have their own attributes – see the documentation for details.
Ancestors
- enum.Enum
Class variables
var activevar canceledvar completedvar pausedvar pending_activationvar rejected
class MediaChannel (*args, **kwds)-
Expand source code
class MediaChannel(Enum): display = 'display' olv = 'olv' social = 'social' search = 'search' ctv = 'ctv' linear_tv = 'linear_tv' radio = 'radio' streaming_audio = 'streaming_audio' podcast = 'podcast' dooh = 'dooh' ooh = 'ooh' print = 'print' cinema = 'cinema' email = 'email' gaming = 'gaming' retail_media = 'retail_media' influencer = 'influencer' affiliate = 'affiliate' product_placement = 'product_placement' sponsored_intelligence = 'sponsored_intelligence'Create a collection of name/value pairs.
Example enumeration:
>>> class Color(Enum): ... RED = 1 ... BLUE = 2 ... GREEN = 3Access them by:
- attribute access::
>>> Color.RED <Color.RED: 1>- value lookup:
>>> Color(1) <Color.RED: 1>- name lookup:
>>> Color['RED'] <Color.RED: 1>Enumerations can be iterated over, and know how many members they have:
>>> len(Color) 3>>> list(Color) [<Color.RED: 1>, <Color.BLUE: 2>, <Color.GREEN: 3>]Methods can be added to enumerations, and members can have their own attributes – see the documentation for details.
Ancestors
- enum.Enum
Class variables
var affiliatevar cinemavar ctvvar displayvar doohvar emailvar gamingvar influencervar linear_tvvar olvvar oohvar podcastvar printvar product_placementvar radiovar retail_mediavar searchvar sponsored_intelligencevar streaming_audio
class Member (**data: Any)-
Expand source code
class Member(BaseModel): """An organization registered in the AAO member directory.""" model_config = ConfigDict(extra="allow") id: str slug: str display_name: str description: str | None = None tagline: str | None = None logo_url: str | None = None logo_light_url: str | None = None logo_dark_url: str | None = None contact_email: str | None = None contact_website: str | None = None offerings: list[str] = Field(default_factory=list) markets: list[str] = Field(default_factory=list) agents: list[dict[str, Any]] = Field(default_factory=list) brands: list[dict[str, Any]] = Field(default_factory=list) is_public: bool = True is_founding_member: bool = False featured: bool = False si_enabled: bool = FalseAn organization registered in the AAO member directory.
Create a new model by parsing and validating input data from keyword arguments.
Raises [
ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.selfis explicitly positional-only to allowselfas a field name.Ancestors
- pydantic.main.BaseModel
Class variables
var agents : list[dict[str, typing.Any]]var brands : list[dict[str, typing.Any]]var contact_email : str | Nonevar contact_website : str | Nonevar description : str | Nonevar display_name : strvar featured : boolvar id : strvar is_founding_member : boolvar is_public : boolvar logo_dark_url : str | Nonevar logo_light_url : str | Nonevar logo_url : str | Nonevar markets : list[str]var model_configvar offerings : list[str]var si_enabled : boolvar slug : strvar tagline : str | None
class OfferingAssetConstraint (**data: Any)-
Expand source code
class OfferingAssetConstraint(AdCPBaseModel): model_config = ConfigDict( extra='allow', ) asset_group_id: Annotated[ str, Field( description="The asset group this constraint applies to. Values are format-defined vocabulary — each format chooses its own group IDs (e.g., 'headlines', 'images', 'videos'). Buyers discover them via list_creative_formats." ), ] asset_requirements: Annotated[ asset_requirements_1.AssetRequirements | None, Field( description='Technical requirements for each item in this group (e.g., max_length for text, min_width/aspect_ratio for images). Applies uniformly to all items in the group.' ), ] = None asset_type: Annotated[ asset_content_type.AssetContentType, Field(description='The expected content type for this group.'), ] ext: ext_1.ExtensionObject | None = None max_count: Annotated[ int | None, Field(description='Maximum number of items allowed in this group.', ge=1) ] = None min_count: Annotated[ int | None, Field(description='Minimum number of items required in this group.', ge=1) ] = None required: Annotated[ bool | None, Field( description='Whether this asset group must be present in each offering. Defaults to true.' ), ] = TrueBase model for AdCP types with spec-compliant serialization.
Defaults to
extra='ignore'so that unknown fields from newer spec versions are silently dropped rather than causing validation errors. Generated types whose schemas setadditionalProperties: trueoverride this withextra='allow'in their ownmodel_config. Consumers who want strict validation can override withextra='forbid'.Create a new model by parsing and validating input data from keyword arguments.
Raises [
ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.selfis explicitly positional-only to allowselfas a field name.Ancestors
- AdCPBaseModel
- pydantic.main.BaseModel
Class variables
var asset_group_id : strvar asset_requirements : AssetRequirements | Nonevar asset_type : AssetContentTypevar ext : ExtensionObject | Nonevar max_count : int | Nonevar min_count : int | Nonevar model_configvar required : bool | None
Inherited members
class OfferingAssetGroup (**data: Any)-
Expand source code
class OfferingAssetGroup(AdCPBaseModel): model_config = ConfigDict( extra='allow', ) asset_group_id: Annotated[ str, Field( description="Identifies the creative role this group fills. Values are defined by each format's offering_asset_constraints — not protocol constants. Discover them via list_creative_formats (e.g., a format might declare 'headlines', 'images', or 'videos')." ), ] asset_type: Annotated[ asset_content_type.AssetContentType, Field(description='The content type of all items in this group.'), ] ext: ext_1.ExtensionObject | None = None items: Annotated[ list[ text_asset.TextAsset | image_asset.ImageAsset | video_asset.VideoAsset | audio_asset.AudioAsset | url_asset.UrlAsset | html_asset.HtmlAsset | markdown_asset.MarkdownAsset | vast_asset.VastAsset | daast_asset.DaastAsset | css_asset.CssAsset | javascript_asset.JavascriptAsset | webhook_asset.WebhookAsset ], Field( description='The assets in this group. Each item should match the structure for the declared asset_type. Note: JSON Schema validation accepts any valid asset structure here; enforcement that items match asset_type is the responsibility of the consuming agent.', min_length=1, ), ]Base model for AdCP types with spec-compliant serialization.
Defaults to
extra='ignore'so that unknown fields from newer spec versions are silently dropped rather than causing validation errors. Generated types whose schemas setadditionalProperties: trueoverride this withextra='allow'in their ownmodel_config. Consumers who want strict validation can override withextra='forbid'.Create a new model by parsing and validating input data from keyword arguments.
Raises [
ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.selfis explicitly positional-only to allowselfas a field name.Ancestors
- AdCPBaseModel
- pydantic.main.BaseModel
Class variables
var asset_group_id : strvar asset_type : AssetContentTypevar ext : ExtensionObject | Nonevar items : list[TextAsset | ImageAsset | VideoAsset | AudioAsset | UrlAsset | HtmlAsset | MarkdownAsset | VastAsset | DaastAsset | CssAsset | JavascriptAsset | WebhookAsset]var model_config
Inherited members
class OptimizationGoal (root: RootModelRootType = PydanticUndefined, **data)-
Expand source code
class OptimizationGoal(RootModel[OptimizationGoal1 | OptimizationGoal2]): root: Annotated[ OptimizationGoal1 | OptimizationGoal2, Field( description='A single optimization target for a package. Packages accept an array of optimization_goals. When multiple goals are present, priority determines which the seller focuses on — 1 is highest priority (primary goal); higher numbers are secondary. Duplicate priority values result in undefined seller behavior.', title='Optimization Goal', ), ] def __getattr__(self, name: str) -> Any: """Proxy attribute access to the wrapped type.""" if name.startswith('_'): raise AttributeError(name) return getattr(self.root, name)Usage Documentation
A Pydantic
BaseModelfor the root object of the model.Attributes
root- The root object of the model.
__pydantic_root_model__- Whether the model is a RootModel.
__pydantic_private__- Private fields in the model.
__pydantic_extra__- Extra fields in the model.
Create a new model by parsing and validating input data from keyword arguments.
Raises [
ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.selfis explicitly positional-only to allowselfas a field name.Ancestors
- pydantic.root_model.RootModel[Union[OptimizationGoal1, OptimizationGoal2]]
- pydantic.root_model.RootModel
- pydantic.main.BaseModel
- typing.Generic
Class variables
var model_configvar root : OptimizationGoal1 | OptimizationGoal2
class Overlay (**data: Any)-
Expand source code
class Overlay(AdCPBaseModel): model_config = ConfigDict( extra='forbid', ) bounds: Annotated[ Bounds, Field( description="Position and size of the overlay relative to the asset's own top-left corner. See 'unit' for coordinate interpretation." ), ] description: Annotated[ str | None, Field( description='Human-readable explanation of what this overlay is and how buyers should account for it' ), ] = None id: Annotated[ str, Field( description="Identifier for this overlay (e.g., 'play_pause', 'volume', 'publisher_logo', 'carousel_prev', 'carousel_next')" ), ] visual: Annotated[ Visual | None, Field( description='Optional visual reference for this overlay element. Useful for creative agents compositing previews and for buyers understanding what will appear over their content. Must include at least one of: url, light, or dark.' ), ] = NoneBase model for AdCP types with spec-compliant serialization.
Defaults to
extra='ignore'so that unknown fields from newer spec versions are silently dropped rather than causing validation errors. Generated types whose schemas setadditionalProperties: trueoverride this withextra='allow'in their ownmodel_config. Consumers who want strict validation can override withextra='forbid'.Create a new model by parsing and validating input data from keyword arguments.
Raises [
ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.selfis explicitly positional-only to allowselfas a field name.Ancestors
- AdCPBaseModel
- pydantic.main.BaseModel
Class variables
var bounds : Boundsvar description : str | Nonevar id : strvar model_configvar visual : Visual | None
Inherited members
class MediaBuyPackage (**data: Any)-
Expand source code
class Package(AdCPBaseModel): model_config = ConfigDict( extra='allow', ) bid_price: Annotated[ float | None, Field( description='Current bid price for auction-based packages. Denominated in package.currency when present, otherwise media_buy.currency. Relevant for automated price optimization loops.', ge=0.0, ), ] = None budget: Annotated[ float | None, Field( description='Package budget amount, denominated in package.currency when present, otherwise media_buy.currency', ge=0.0, ), ] = None canceled: Annotated[ bool | None, Field( description='Whether this package has been canceled. Canceled packages stop delivery and cannot be reactivated.' ), ] = None cancellation: Annotated[ Cancellation1 | None, Field(description='Cancellation metadata. Present only when canceled is true.'), ] = None creative_approvals: Annotated[ list[CreativeApproval] | None, Field( description='Approval status for each creative assigned to this package. Absent when no creatives have been assigned.' ), ] = None creative_deadline: Annotated[ AwareDatetime | None, Field( description="ISO 8601 timestamp for creative upload or change deadline for this package. After this deadline, creative changes are rejected. When absent, the media buy's creative_deadline applies." ), ] = None currency: Annotated[ str | None, Field( description='ISO 4217 currency code for monetary values at this package level (budget, bid_price, snapshot.spend). When absent, inherit media_buy.currency.', pattern='^[A-Z]{3}$', ), ] = None end_time: Annotated[ AwareDatetime | None, Field(description='ISO 8601 flight end time for this package') ] = None ext: ext_1.ExtensionObject | None = None format_ids_pending: Annotated[ list[format_id.FormatId] | None, Field( description='Format IDs from the original create_media_buy format_ids_to_provide that have not yet been uploaded via sync_creatives. When empty or absent, all required formats have been provided.' ), ] = None impressions: Annotated[ float | None, Field(description='Goal impression count for impression-based packages', ge=0.0), ] = None package_id: Annotated[str, Field(description="Seller's package identifier")] paused: Annotated[ bool | None, Field(description='Whether this package is currently paused by the buyer') ] = None product_id: Annotated[ str | None, Field(description='Product identifier this package is purchased from') ] = None snapshot: Annotated[ Snapshot | None, Field( description='Near-real-time delivery snapshot for this package. Only present when include_snapshot was true in the request. Represents the latest available entity-level stats from the platform — not billing-grade data.' ), ] = None snapshot_unavailable_reason: Annotated[ SnapshotUnavailableReason | None, Field( description='Machine-readable reason the snapshot is omitted. Present only when include_snapshot was true and snapshot is unavailable for this package.' ), ] = None start_time: Annotated[ AwareDatetime | None, Field( description='ISO 8601 flight start time for this package. Use to determine whether the package is within its scheduled flight before interpreting delivery status.' ), ] = NoneBase model for AdCP types with spec-compliant serialization.
Defaults to
extra='ignore'so that unknown fields from newer spec versions are silently dropped rather than causing validation errors. Generated types whose schemas setadditionalProperties: trueoverride this withextra='allow'in their ownmodel_config. Consumers who want strict validation can override withextra='forbid'.Create a new model by parsing and validating input data from keyword arguments.
Raises [
ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.selfis explicitly positional-only to allowselfas a field name.Ancestors
- AdCPBaseModel
- pydantic.main.BaseModel
Class variables
var bid_price : float | Nonevar budget : float | Nonevar canceled : bool | Nonevar cancellation : Cancellation1 | Nonevar creative_approvals : list[CreativeApproval] | Nonevar creative_deadline : pydantic.types.AwareDatetime | Nonevar currency : str | Nonevar end_time : pydantic.types.AwareDatetime | Nonevar ext : ExtensionObject | Nonevar format_ids_pending : list[FormatId] | Nonevar impressions : float | Nonevar model_configvar package_id : strvar paused : bool | Nonevar product_id : str | Nonevar snapshot : Snapshot | Nonevar start_time : pydantic.types.AwareDatetime | None
class Package (**data: Any)-
Expand source code
class Package(AdCPBaseModel): model_config = ConfigDict( extra='allow', ) bid_price: Annotated[ float | None, Field( description="Bid price for auction-based pricing. This is the exact bid/price to honor unless the selected pricing option has max_bid=true, in which case bid_price is the buyer's maximum willingness to pay (ceiling).", ge=0.0, ), ] = None budget: Annotated[ float | None, Field( description='Budget allocation for this package in the currency specified by the pricing option', ge=0.0, ), ] = None canceled: Annotated[ bool | None, Field( description='Whether this package has been canceled. Canceled packages stop delivery and cannot be reactivated. Defaults to false.' ), ] = False cancellation: Annotated[ Cancellation | None, Field(description='Cancellation metadata. Present only when canceled is true.'), ] = None catalogs: Annotated[ list[catalog.Catalog] | None, Field( description='Catalogs this package promotes. Each catalog MUST have a distinct type (e.g., one product catalog, one store catalog). This constraint is enforced at the application level — sellers MUST reject requests containing multiple catalogs of the same type with a validation_error. Echoed from the create_media_buy request.' ), ] = None context: context_1.ContextObject | None = None creative_assignments: Annotated[ list[creative_assignment.CreativeAssignment] | None, Field(description='Creative assets assigned to this package'), ] = None creative_deadline: Annotated[ AwareDatetime | None, Field( description="ISO 8601 timestamp for creative upload or change deadline for this package. After this deadline, creative changes are rejected. When absent, the media buy's creative_deadline applies." ), ] = None end_time: Annotated[ AwareDatetime | None, Field( description="Flight end date/time for this package in ISO 8601 format. When omitted, the package inherits the media buy's end_time. Sellers SHOULD always include the resolved value in responses, even when inherited." ), ] = None ext: ext_1.ExtensionObject | None = None format_ids: Annotated[ list[format_id.FormatId] | None, Field( description='Format IDs active for this package. Echoed from the create_media_buy request; omitted means all formats for the product are active.' ), ] = None format_ids_to_provide: Annotated[ list[format_id.FormatId] | None, Field(description='Format IDs that creative assets will be provided for this package'), ] = None impressions: Annotated[ float | None, Field(description='Impression goal for this package', ge=0.0) ] = None optimization_goals: Annotated[ list[optimization_goal.OptimizationGoal] | None, Field( description='Optimization targets for this package. The seller optimizes delivery toward these goals in priority order. Common pattern: event goals (purchase, install) as primary targets at priority 1; metric goals (clicks, views) as secondary proxy signals at priority 2+.', min_length=1, ), ] = None pacing: pacing_1.Pacing | None = None package_id: Annotated[str, Field(description="Seller's unique identifier for the package")] paused: Annotated[ bool | None, Field( description='Whether this package is paused by the buyer. Paused packages do not deliver impressions. Defaults to false.' ), ] = False price_breakdown: Annotated[ price_breakdown_1.PriceBreakdown | None, Field( description="Breakdown of the effective price for this package. On fixed-price packages, echoes the pricing option's breakdown. On auction packages, shows the clearing price breakdown including any commission or settlement terms." ), ] = None pricing_option_id: Annotated[ str | None, Field( description="ID of the selected pricing option from the product's pricing_options array" ), ] = None product_id: Annotated[ str | None, Field(description='ID of the product this package is based on') ] = None start_time: Annotated[ AwareDatetime | None, Field( description="Flight start date/time for this package in ISO 8601 format. When omitted, the package inherits the media buy's start_time. Sellers SHOULD always include the resolved value in responses, even when inherited." ), ] = None targeting_overlay: targeting.TargetingOverlay | None = NoneBase model for AdCP types with spec-compliant serialization.
Defaults to
extra='ignore'so that unknown fields from newer spec versions are silently dropped rather than causing validation errors. Generated types whose schemas setadditionalProperties: trueoverride this withextra='allow'in their ownmodel_config. Consumers who want strict validation can override withextra='forbid'.Create a new model by parsing and validating input data from keyword arguments.
Raises [
ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.selfis explicitly positional-only to allowselfas a field name.Ancestors
- AdCPBaseModel
- pydantic.main.BaseModel
Class variables
var bid_price : float | Nonevar budget : float | Nonevar canceled : bool | Nonevar cancellation : Cancellation | Nonevar catalogs : list[Catalog] | Nonevar context : ContextObject | Nonevar creative_assignments : list[CreativeAssignment] | Nonevar creative_deadline : pydantic.types.AwareDatetime | Nonevar end_time : pydantic.types.AwareDatetime | Nonevar ext : ExtensionObject | Nonevar format_ids : list[FormatId] | Nonevar format_ids_to_provide : list[FormatId] | Nonevar impressions : float | Nonevar model_configvar optimization_goals : list[OptimizationGoal] | Nonevar pacing : Pacing | Nonevar package_id : strvar paused : bool | Nonevar price_breakdown : PriceBreakdown | Nonevar pricing_option_id : str | Nonevar product_id : str | Nonevar start_time : pydantic.types.AwareDatetime | Nonevar targeting_overlay : TargetingOverlay | None
Inherited members
class PackageRequest (**data: Any)-
Expand source code
class PackageRequest(AdCPBaseModel): model_config = ConfigDict( extra='allow', ) bid_price: Annotated[ float | None, Field( description="Bid price for auction-based pricing options. This is the exact bid/price to honor unless selected pricing_option has max_bid=true, in which case bid_price is the buyer's maximum willingness to pay (ceiling).", ge=0.0, ), ] = None budget: Annotated[ float, Field(description="Budget allocation for this package in the media buy's currency", ge=0.0), ] catalogs: Annotated[ list[catalog.Catalog] | None, Field( description='Catalogs this package promotes. Each catalog MUST have a distinct type (e.g., one product catalog, one store catalog). This constraint is enforced at the application level — sellers MUST reject requests containing multiple catalogs of the same type with a validation_error. Makes the package catalog-driven: one budget envelope, platform optimizes across items.' ), ] = None context: context_1.ContextObject | None = None creative_assignments: Annotated[ list[creative_assignment.CreativeAssignment] | None, Field( description='Assign existing library creatives to this package with optional weights and placement targeting', min_length=1, ), ] = None creatives: Annotated[ list[creative_asset.CreativeAsset] | None, Field( description='Upload new creative assets and assign to this package (creatives will be added to library). Use creative_assignments instead for existing library creatives.', max_length=100, min_length=1, ), ] = None end_time: Annotated[ AwareDatetime | None, Field( description="Flight end date/time for this package in ISO 8601 format. When omitted, the package inherits the media buy's end_time. Must fall within the media buy's date range." ), ] = None ext: ext_1.ExtensionObject | None = None format_ids: Annotated[ list[format_id.FormatId] | None, Field( description='Array of format IDs that will be used for this package - must be supported by the product. If omitted, defaults to all formats supported by the product.', min_length=1, ), ] = None impressions: Annotated[ float | None, Field(description='Impression goal for this package', ge=0.0) ] = None optimization_goals: Annotated[ list[optimization_goal.OptimizationGoal] | None, Field( description='Optimization targets for this package. The seller optimizes delivery toward these goals in priority order. Common pattern: event goals (purchase, install) as primary targets at priority 1; metric goals (clicks, views) as secondary proxy signals at priority 2+.', min_length=1, ), ] = None pacing: pacing_1.Pacing | None = None paused: Annotated[ bool | None, Field( description='Whether this package should be created in a paused state. Paused packages do not deliver impressions. Defaults to false.' ), ] = False pricing_option_id: Annotated[ str, Field( description="ID of the selected pricing option from the product's pricing_options array" ), ] product_id: Annotated[str, Field(description='Product ID for this package')] start_time: Annotated[ AwareDatetime | None, Field( description="Flight start date/time for this package in ISO 8601 format. When omitted, the package inherits the media buy's start_time. Must fall within the media buy's date range." ), ] = None targeting_overlay: targeting.TargetingOverlay | None = NoneBase model for AdCP types with spec-compliant serialization.
Defaults to
extra='ignore'so that unknown fields from newer spec versions are silently dropped rather than causing validation errors. Generated types whose schemas setadditionalProperties: trueoverride this withextra='allow'in their ownmodel_config. Consumers who want strict validation can override withextra='forbid'.Create a new model by parsing and validating input data from keyword arguments.
Raises [
ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.selfis explicitly positional-only to allowselfas a field name.Ancestors
- AdCPBaseModel
- pydantic.main.BaseModel
Class variables
var bid_price : float | Nonevar budget : floatvar catalogs : list[Catalog] | Nonevar context : ContextObject | Nonevar creative_assignments : list[CreativeAssignment] | Nonevar creatives : list[CreativeAsset] | Nonevar end_time : pydantic.types.AwareDatetime | Nonevar ext : ExtensionObject | Nonevar format_ids : list[FormatId] | Nonevar impressions : float | Nonevar model_configvar optimization_goals : list[OptimizationGoal] | Nonevar pacing : Pacing | Nonevar paused : bool | Nonevar pricing_option_id : strvar product_id : strvar start_time : pydantic.types.AwareDatetime | Nonevar targeting_overlay : TargetingOverlay | None
Inherited members
class PaginationRequest (**data: Any)-
Expand source code
class PaginationRequest(AdCPBaseModel): model_config = ConfigDict( extra='forbid', ) cursor: Annotated[ str | None, Field(description='Opaque cursor from a previous response to fetch the next page'), ] = None max_results: Annotated[ int | None, Field(description='Maximum number of items to return per page', ge=1, le=100) ] = 50Base model for AdCP types with spec-compliant serialization.
Defaults to
extra='ignore'so that unknown fields from newer spec versions are silently dropped rather than causing validation errors. Generated types whose schemas setadditionalProperties: trueoverride this withextra='allow'in their ownmodel_config. Consumers who want strict validation can override withextra='forbid'.Create a new model by parsing and validating input data from keyword arguments.
Raises [
ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.selfis explicitly positional-only to allowselfas a field name.Ancestors
- AdCPBaseModel
- pydantic.main.BaseModel
Class variables
var cursor : str | Nonevar max_results : int | Nonevar model_config
Inherited members
class Policy (**data: Any)-
Expand source code
class Policy(PolicySummary): """Full governance policy including policy text and calibration exemplars.""" policy: str guidance: str | None = None exemplars: PolicyExemplars | None = None ext: dict[str, Any] | None = NoneFull governance policy including policy text and calibration exemplars.
Create a new model by parsing and validating input data from keyword arguments.
Raises [
ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.selfis explicitly positional-only to allowselfas a field name.Ancestors
- PolicySummary
- pydantic.main.BaseModel
Class variables
var exemplars : PolicyExemplars | Nonevar ext : dict[str, typing.Any] | Nonevar guidance : str | Nonevar model_configvar policy : str
class PolicyExemplar (**data: Any)-
Expand source code
class PolicyExemplar(BaseModel): """A pass/fail scenario used to calibrate governance agent interpretation.""" model_config = ConfigDict(extra="allow") scenario: str explanation: strA pass/fail scenario used to calibrate governance agent interpretation.
Create a new model by parsing and validating input data from keyword arguments.
Raises [
ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.selfis explicitly positional-only to allowselfas a field name.Ancestors
- pydantic.main.BaseModel
Class variables
var explanation : strvar model_configvar scenario : str
class PolicyExemplars (**data: Any)-
Expand source code
class PolicyExemplars(BaseModel): """Collection of pass/fail exemplars for a policy.""" model_config = ConfigDict(extra="allow") pass_: list[PolicyExemplar] = Field(default_factory=list, alias="pass") fail: list[PolicyExemplar] = Field(default_factory=list)Collection of pass/fail exemplars for a policy.
Create a new model by parsing and validating input data from keyword arguments.
Raises [
ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.selfis explicitly positional-only to allowselfas a field name.Ancestors
- pydantic.main.BaseModel
Class variables
var fail : list[PolicyExemplar]var model_configvar pass_ : list[PolicyExemplar]
class PolicyHistory (**data: Any)-
Expand source code
class PolicyHistory(BaseModel): """Edit history for a policy.""" model_config = ConfigDict(extra="allow") policy_id: str total: int revisions: list[PolicyRevision] = Field(default_factory=list)Edit history for a policy.
Create a new model by parsing and validating input data from keyword arguments.
Raises [
ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.selfis explicitly positional-only to allowselfas a field name.Ancestors
- pydantic.main.BaseModel
Class variables
var model_configvar policy_id : strvar revisions : list[PolicyRevision]var total : int
class PolicyRevision (**data: Any)-
Expand source code
class PolicyRevision(BaseModel): """A single revision in a policy's edit history.""" model_config = ConfigDict(extra="allow") revision_number: int editor_name: str edit_summary: str is_rollback: bool rolled_back_to: int | None = None created_at: strA single revision in a policy's edit history.
Create a new model by parsing and validating input data from keyword arguments.
Raises [
ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.selfis explicitly positional-only to allowselfas a field name.Ancestors
- pydantic.main.BaseModel
Class variables
var created_at : strvar edit_summary : strvar editor_name : strvar is_rollback : boolvar model_configvar revision_number : intvar rolled_back_to : int | None
class PolicySummary (**data: Any)-
Expand source code
class PolicySummary(BaseModel): """Summary of a governance policy from the registry.""" model_config = ConfigDict(extra="allow", populate_by_name=True) policy_id: str version: str name: str description: str | None = None category: str enforcement: str jurisdictions: list[str] = Field(default_factory=list) region_aliases: dict[str, list[str]] = Field(default_factory=dict) verticals: list[str] = Field(default_factory=list) channels: list[str] | None = None governance_domains: list[str] = Field(default_factory=list) effective_date: str | None = None sunset_date: str | None = None source_url: str | None = None source_name: str | None = None source_type: str | None = None review_status: str | None = None created_at: str | None = None updated_at: str | None = NoneSummary of a governance policy from the registry.
Create a new model by parsing and validating input data from keyword arguments.
Raises [
ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.selfis explicitly positional-only to allowselfas a field name.Ancestors
- pydantic.main.BaseModel
Subclasses
Class variables
var category : strvar channels : list[str] | Nonevar created_at : str | Nonevar description : str | Nonevar effective_date : str | Nonevar enforcement : strvar governance_domains : list[str]var jurisdictions : list[str]var model_configvar name : strvar policy_id : strvar region_aliases : dict[str, list[str]]var review_status : str | Nonevar source_name : str | Nonevar source_type : str | Nonevar source_url : str | Nonevar sunset_date : str | Nonevar updated_at : str | Nonevar version : strvar verticals : list[str]
class PreviewCreativeSingleRequest (**data: Any)-
Expand source code
class PreviewCreativeRequest1(AdCPBaseModel): model_config = ConfigDict( extra='allow', ) context: context_1.ContextObject | None = None creative_manifest: Annotated[ creative_manifest_1.CreativeManifest, Field(description='Complete creative manifest with all required assets for the format.'), ] ext: ext_1.ExtensionObject | None = None format_id: Annotated[ format_id_1.FormatId | None, Field( description='Format identifier for rendering the preview. Optional — defaults to creative_manifest_1.format_id if omitted.' ), ] = None inputs: Annotated[ list[Input] | None, Field( description='Array of input sets for generating multiple preview variants. Each input set defines macros and context values for one preview rendering. If not provided, creative agent will generate default previews.', min_length=1, ), ] = None item_limit: Annotated[ int | None, Field( description="Maximum number of catalog items to render in the preview. For catalog-driven generative formats, caps how many items are rendered per preview variant. When item_limit exceeds the format's max_items, the creative agent SHOULD use the lesser of the two. Ignored when the manifest contains no catalog assets. Creative agents SHOULD default to a reasonable sample when omitted and the catalog is large.", ge=1, ), ] = None output_format: Annotated[ preview_output_format.PreviewOutputFormat | None, Field( description="Output format for previews. 'url' returns preview_url (iframe-embeddable URL), 'html' returns preview_html (raw HTML for direct embedding). Default: 'url' for backward compatibility." ), ] = preview_output_format.PreviewOutputFormat.url quality: Annotated[ creative_quality.CreativeQuality | None, Field( description="Render quality for the preview. 'draft' produces fast, lower-fidelity renderings for rapid iteration. 'production' produces full-quality renderings for final review. If omitted, the creative agent uses its own default." ), ] = None request_type: Annotated[ Literal['single'], Field(description='Discriminator indicating this is a single preview request'), ] template_id: Annotated[ str | None, Field(description='Specific template ID for custom format rendering') ] = NoneBase model for AdCP types with spec-compliant serialization.
Defaults to
extra='ignore'so that unknown fields from newer spec versions are silently dropped rather than causing validation errors. Generated types whose schemas setadditionalProperties: trueoverride this withextra='allow'in their ownmodel_config. Consumers who want strict validation can override withextra='forbid'.Create a new model by parsing and validating input data from keyword arguments.
Raises [
ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.selfis explicitly positional-only to allowselfas a field name.Ancestors
- AdCPBaseModel
- pydantic.main.BaseModel
Class variables
var context : ContextObject | Nonevar creative_manifest : CreativeManifestvar ext : ExtensionObject | Nonevar format_id : FormatId | Nonevar inputs : list[Input] | Nonevar item_limit : int | Nonevar model_configvar output_format : PreviewOutputFormat | Nonevar quality : CreativeQuality | Nonevar request_type : Literal['single']var template_id : str | None
class PreviewCreativeFormatRequest (**data: Any)-
Expand source code
class PreviewCreativeRequest1(AdCPBaseModel): model_config = ConfigDict( extra='allow', ) context: context_1.ContextObject | None = None creative_manifest: Annotated[ creative_manifest_1.CreativeManifest, Field(description='Complete creative manifest with all required assets for the format.'), ] ext: ext_1.ExtensionObject | None = None format_id: Annotated[ format_id_1.FormatId | None, Field( description='Format identifier for rendering the preview. Optional — defaults to creative_manifest_1.format_id if omitted.' ), ] = None inputs: Annotated[ list[Input] | None, Field( description='Array of input sets for generating multiple preview variants. Each input set defines macros and context values for one preview rendering. If not provided, creative agent will generate default previews.', min_length=1, ), ] = None item_limit: Annotated[ int | None, Field( description="Maximum number of catalog items to render in the preview. For catalog-driven generative formats, caps how many items are rendered per preview variant. When item_limit exceeds the format's max_items, the creative agent SHOULD use the lesser of the two. Ignored when the manifest contains no catalog assets. Creative agents SHOULD default to a reasonable sample when omitted and the catalog is large.", ge=1, ), ] = None output_format: Annotated[ preview_output_format.PreviewOutputFormat | None, Field( description="Output format for previews. 'url' returns preview_url (iframe-embeddable URL), 'html' returns preview_html (raw HTML for direct embedding). Default: 'url' for backward compatibility." ), ] = preview_output_format.PreviewOutputFormat.url quality: Annotated[ creative_quality.CreativeQuality | None, Field( description="Render quality for the preview. 'draft' produces fast, lower-fidelity renderings for rapid iteration. 'production' produces full-quality renderings for final review. If omitted, the creative agent uses its own default." ), ] = None request_type: Annotated[ Literal['single'], Field(description='Discriminator indicating this is a single preview request'), ] template_id: Annotated[ str | None, Field(description='Specific template ID for custom format rendering') ] = NoneBase model for AdCP types with spec-compliant serialization.
Defaults to
extra='ignore'so that unknown fields from newer spec versions are silently dropped rather than causing validation errors. Generated types whose schemas setadditionalProperties: trueoverride this withextra='allow'in their ownmodel_config. Consumers who want strict validation can override withextra='forbid'.Create a new model by parsing and validating input data from keyword arguments.
Raises [
ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.selfis explicitly positional-only to allowselfas a field name.Ancestors
- AdCPBaseModel
- pydantic.main.BaseModel
Class variables
var context : ContextObject | Nonevar creative_manifest : CreativeManifestvar ext : ExtensionObject | Nonevar format_id : FormatId | Nonevar inputs : list[Input] | Nonevar item_limit : int | Nonevar model_configvar output_format : PreviewOutputFormat | Nonevar quality : CreativeQuality | Nonevar request_type : Literal['single']var template_id : str | None
Inherited members
class PreviewCreativeBatchRequest (**data: Any)-
Expand source code
class PreviewCreativeRequest2(AdCPBaseModel): model_config = ConfigDict( extra='allow', ) context: context_1.ContextObject | None = None ext: ext_1.ExtensionObject | None = None output_format: Annotated[ preview_output_format.PreviewOutputFormat | None, Field( description="Default output format for all requests in this batch. Individual requests can override this. 'url' returns preview_url (iframe-embeddable URL), 'html' returns preview_html (raw HTML for direct embedding)." ), ] = preview_output_format.PreviewOutputFormat.url quality: Annotated[ creative_quality.CreativeQuality | None, Field( description="Default render quality for all requests in this batch. Individual requests can override this. 'draft' produces fast, lower-fidelity renderings. 'production' produces full-quality renderings." ), ] = None request_type: Annotated[ Literal['batch'], Field(description='Discriminator indicating this is a batch preview request'), ] requests: Annotated[ list[Request], Field( description='Array of preview requests (1-50 items). Each follows the single request structure.', max_length=50, min_length=1, ), ]Base model for AdCP types with spec-compliant serialization.
Defaults to
extra='ignore'so that unknown fields from newer spec versions are silently dropped rather than causing validation errors. Generated types whose schemas setadditionalProperties: trueoverride this withextra='allow'in their ownmodel_config. Consumers who want strict validation can override withextra='forbid'.Create a new model by parsing and validating input data from keyword arguments.
Raises [
ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.selfis explicitly positional-only to allowselfas a field name.Ancestors
- AdCPBaseModel
- pydantic.main.BaseModel
Class variables
var context : ContextObject | Nonevar ext : ExtensionObject | Nonevar model_configvar output_format : PreviewOutputFormat | Nonevar quality : CreativeQuality | Nonevar request_type : Literal['batch']var requests : list[Request]
class PreviewCreativeManifestRequest (**data: Any)-
Expand source code
class PreviewCreativeRequest2(AdCPBaseModel): model_config = ConfigDict( extra='allow', ) context: context_1.ContextObject | None = None ext: ext_1.ExtensionObject | None = None output_format: Annotated[ preview_output_format.PreviewOutputFormat | None, Field( description="Default output format for all requests in this batch. Individual requests can override this. 'url' returns preview_url (iframe-embeddable URL), 'html' returns preview_html (raw HTML for direct embedding)." ), ] = preview_output_format.PreviewOutputFormat.url quality: Annotated[ creative_quality.CreativeQuality | None, Field( description="Default render quality for all requests in this batch. Individual requests can override this. 'draft' produces fast, lower-fidelity renderings. 'production' produces full-quality renderings." ), ] = None request_type: Annotated[ Literal['batch'], Field(description='Discriminator indicating this is a batch preview request'), ] requests: Annotated[ list[Request], Field( description='Array of preview requests (1-50 items). Each follows the single request structure.', max_length=50, min_length=1, ), ]Base model for AdCP types with spec-compliant serialization.
Defaults to
extra='ignore'so that unknown fields from newer spec versions are silently dropped rather than causing validation errors. Generated types whose schemas setadditionalProperties: trueoverride this withextra='allow'in their ownmodel_config. Consumers who want strict validation can override withextra='forbid'.Create a new model by parsing and validating input data from keyword arguments.
Raises [
ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.selfis explicitly positional-only to allowselfas a field name.Ancestors
- AdCPBaseModel
- pydantic.main.BaseModel
Class variables
var context : ContextObject | Nonevar ext : ExtensionObject | Nonevar model_configvar output_format : PreviewOutputFormat | Nonevar quality : CreativeQuality | Nonevar request_type : Literal['batch']var requests : list[Request]
Inherited members
class PreviewCreativeVariantRequest (**data: Any)-
Expand source code
class PreviewCreativeRequest3(AdCPBaseModel): model_config = ConfigDict( extra='allow', ) context: context_1.ContextObject | None = None creative_id: Annotated[str | None, Field(description='Creative identifier for context')] = None ext: ext_1.ExtensionObject | None = None output_format: Annotated[ preview_output_format.PreviewOutputFormat | None, Field( description="Output format for the preview. 'url' returns preview_url (iframe-embeddable URL), 'html' returns preview_html (raw HTML for direct embedding)." ), ] = preview_output_format.PreviewOutputFormat.url request_type: Annotated[ Literal['variant'], Field(description='Discriminator indicating this is a variant preview request'), ] variant_id: Annotated[ str, Field( description='Platform-assigned variant identifier from get_creative_delivery response' ), ]Base model for AdCP types with spec-compliant serialization.
Defaults to
extra='ignore'so that unknown fields from newer spec versions are silently dropped rather than causing validation errors. Generated types whose schemas setadditionalProperties: trueoverride this withextra='allow'in their ownmodel_config. Consumers who want strict validation can override withextra='forbid'.Create a new model by parsing and validating input data from keyword arguments.
Raises [
ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.selfis explicitly positional-only to allowselfas a field name.Ancestors
- AdCPBaseModel
- pydantic.main.BaseModel
Class variables
var context : ContextObject | Nonevar creative_id : str | Nonevar ext : ExtensionObject | Nonevar model_configvar output_format : PreviewOutputFormat | Nonevar request_type : Literal['variant']var variant_id : str
Inherited members
class PreviewCreativeSingleResponse (**data: Any)-
Expand source code
class PreviewCreativeResponse1(AdCPBaseModel): model_config = ConfigDict( extra='allow', ) context: context_1.ContextObject | None = None expires_at: Annotated[ AwareDatetime, Field(description='ISO 8601 timestamp when preview links expire') ] ext: ext_1.ExtensionObject | None = None interactive_url: Annotated[ AnyUrl | None, Field( description='Optional URL to an interactive testing page that shows all preview variants with controls to switch between them, modify macro values, and test different scenarios.' ), ] = None previews: Annotated[ list[Preview], Field( description='Array of preview variants. Each preview corresponds to an input set from the request. If no inputs were provided, returns a single default preview.', min_length=1, ), ] response_type: Annotated[ Literal['single'], Field(description='Discriminator indicating this is a single preview response'), ]Base model for AdCP types with spec-compliant serialization.
Defaults to
extra='ignore'so that unknown fields from newer spec versions are silently dropped rather than causing validation errors. Generated types whose schemas setadditionalProperties: trueoverride this withextra='allow'in their ownmodel_config. Consumers who want strict validation can override withextra='forbid'.Create a new model by parsing and validating input data from keyword arguments.
Raises [
ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.selfis explicitly positional-only to allowselfas a field name.Ancestors
- AdCPBaseModel
- pydantic.main.BaseModel
Class variables
var context : ContextObject | Nonevar expires_at : pydantic.types.AwareDatetimevar ext : ExtensionObject | Nonevar interactive_url : pydantic.networks.AnyUrl | Nonevar model_configvar previews : list[Preview]var response_type : Literal['single']
class PreviewCreativeStaticResponse (**data: Any)-
Expand source code
class PreviewCreativeResponse1(AdCPBaseModel): model_config = ConfigDict( extra='allow', ) context: context_1.ContextObject | None = None expires_at: Annotated[ AwareDatetime, Field(description='ISO 8601 timestamp when preview links expire') ] ext: ext_1.ExtensionObject | None = None interactive_url: Annotated[ AnyUrl | None, Field( description='Optional URL to an interactive testing page that shows all preview variants with controls to switch between them, modify macro values, and test different scenarios.' ), ] = None previews: Annotated[ list[Preview], Field( description='Array of preview variants. Each preview corresponds to an input set from the request. If no inputs were provided, returns a single default preview.', min_length=1, ), ] response_type: Annotated[ Literal['single'], Field(description='Discriminator indicating this is a single preview response'), ]Base model for AdCP types with spec-compliant serialization.
Defaults to
extra='ignore'so that unknown fields from newer spec versions are silently dropped rather than causing validation errors. Generated types whose schemas setadditionalProperties: trueoverride this withextra='allow'in their ownmodel_config. Consumers who want strict validation can override withextra='forbid'.Create a new model by parsing and validating input data from keyword arguments.
Raises [
ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.selfis explicitly positional-only to allowselfas a field name.Ancestors
- AdCPBaseModel
- pydantic.main.BaseModel
Class variables
var context : ContextObject | Nonevar expires_at : pydantic.types.AwareDatetimevar ext : ExtensionObject | Nonevar interactive_url : pydantic.networks.AnyUrl | Nonevar model_configvar previews : list[Preview]var response_type : Literal['single']
Inherited members
class PreviewCreativeBatchResponse (**data: Any)-
Expand source code
class PreviewCreativeResponse2(AdCPBaseModel): model_config = ConfigDict( extra='allow', ) context: context_1.ContextObject | None = None ext: ext_1.ExtensionObject | None = None response_type: Annotated[ Literal['batch'], Field(description='Discriminator indicating this is a batch preview response'), ] results: Annotated[ list[Results | Results1], Field( description='Array of preview results corresponding to each request in the same order. results[0] is the result for requests[0], results[1] for requests[1], etc. Order is guaranteed even when some requests fail. Each result contains either a successful preview response or an error.', min_length=1, ), ]Base model for AdCP types with spec-compliant serialization.
Defaults to
extra='ignore'so that unknown fields from newer spec versions are silently dropped rather than causing validation errors. Generated types whose schemas setadditionalProperties: trueoverride this withextra='allow'in their ownmodel_config. Consumers who want strict validation can override withextra='forbid'.Create a new model by parsing and validating input data from keyword arguments.
Raises [
ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.selfis explicitly positional-only to allowselfas a field name.Ancestors
- AdCPBaseModel
- pydantic.main.BaseModel
Class variables
var context : ContextObject | Nonevar ext : ExtensionObject | Nonevar model_configvar response_type : Literal['batch']var results : list[Results | Results1]
class PreviewCreativeInteractiveResponse (**data: Any)-
Expand source code
class PreviewCreativeResponse2(AdCPBaseModel): model_config = ConfigDict( extra='allow', ) context: context_1.ContextObject | None = None ext: ext_1.ExtensionObject | None = None response_type: Annotated[ Literal['batch'], Field(description='Discriminator indicating this is a batch preview response'), ] results: Annotated[ list[Results | Results1], Field( description='Array of preview results corresponding to each request in the same order. results[0] is the result for requests[0], results[1] for requests[1], etc. Order is guaranteed even when some requests fail. Each result contains either a successful preview response or an error.', min_length=1, ), ]Base model for AdCP types with spec-compliant serialization.
Defaults to
extra='ignore'so that unknown fields from newer spec versions are silently dropped rather than causing validation errors. Generated types whose schemas setadditionalProperties: trueoverride this withextra='allow'in their ownmodel_config. Consumers who want strict validation can override withextra='forbid'.Create a new model by parsing and validating input data from keyword arguments.
Raises [
ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.selfis explicitly positional-only to allowselfas a field name.Ancestors
- AdCPBaseModel
- pydantic.main.BaseModel
Class variables
var context : ContextObject | Nonevar ext : ExtensionObject | Nonevar model_configvar response_type : Literal['batch']var results : list[Results | Results1]
Inherited members
class PreviewCreativeVariantResponse (**data: Any)-
Expand source code
class PreviewCreativeResponse3(AdCPBaseModel): model_config = ConfigDict( extra='allow', ) context: context_1.ContextObject | None = None creative_id: Annotated[ str | None, Field(description='Creative identifier this variant belongs to') ] = None expires_at: Annotated[ AwareDatetime | None, Field(description='ISO 8601 timestamp when preview links expire') ] = None ext: ext_1.ExtensionObject | None = None manifest: Annotated[ creative_manifest.CreativeManifest | None, Field( description='The rendered creative manifest for this variant — the actual output that was served, not the input assets' ), ] = None previews: Annotated[ list[Preview7], Field( description='Array of rendered pieces for this variant. Most formats render as a single piece.', min_length=1, ), ] response_type: Annotated[ Literal['variant'], Field(description='Discriminator indicating this is a variant preview response'), ] variant_id: Annotated[str, Field(description='Platform-assigned variant identifier')]Base model for AdCP types with spec-compliant serialization.
Defaults to
extra='ignore'so that unknown fields from newer spec versions are silently dropped rather than causing validation errors. Generated types whose schemas setadditionalProperties: trueoverride this withextra='allow'in their ownmodel_config. Consumers who want strict validation can override withextra='forbid'.Create a new model by parsing and validating input data from keyword arguments.
Raises [
ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.selfis explicitly positional-only to allowselfas a field name.Ancestors
- AdCPBaseModel
- pydantic.main.BaseModel
Class variables
var context : ContextObject | Nonevar creative_id : str | Nonevar expires_at : pydantic.types.AwareDatetime | Nonevar ext : ExtensionObject | Nonevar manifest : CreativeManifest | Nonevar model_configvar previews : list[Preview7]var response_type : Literal['variant']var variant_id : str
Inherited members
class UrlPreviewRender (**data: Any)-
Expand source code
class PreviewRender1(AdCPBaseModel): model_config = ConfigDict( extra='allow', ) dimensions: Annotated[ Dimensions | None, Field(description='Dimensions for this rendered piece') ] = None embedding: Annotated[ Embedding | None, Field(description='Optional security and embedding metadata for safe iframe integration'), ] = None output_format: Annotated[ Literal['url'], Field(description='Discriminator indicating preview_url is provided') ] preview_url: Annotated[ AnyUrl, Field( description='URL to an HTML page that renders this piece. Can be embedded in an iframe.' ), ] render_id: Annotated[ str, Field(description='Unique identifier for this rendered piece within the variant') ] role: Annotated[ str, Field( description="Semantic role of this rendered piece. Use 'primary' for main content, 'companion' for associated banners, descriptive strings for device variants or custom roles." ), ]Base model for AdCP types with spec-compliant serialization.
Defaults to
extra='ignore'so that unknown fields from newer spec versions are silently dropped rather than causing validation errors. Generated types whose schemas setadditionalProperties: trueoverride this withextra='allow'in their ownmodel_config. Consumers who want strict validation can override withextra='forbid'.Create a new model by parsing and validating input data from keyword arguments.
Raises [
ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.selfis explicitly positional-only to allowselfas a field name.Ancestors
- AdCPBaseModel
- pydantic.main.BaseModel
Class variables
var dimensions : Dimensions | Nonevar embedding : Embedding | Nonevar model_configvar output_format : Literal['url']var preview_url : pydantic.networks.AnyUrlvar render_id : strvar role : str
Inherited members
class HtmlPreviewRender (**data: Any)-
Expand source code
class PreviewRender2(AdCPBaseModel): model_config = ConfigDict( extra='allow', ) dimensions: Annotated[ Dimensions | None, Field(description='Dimensions for this rendered piece') ] = None embedding: Annotated[ Embedding | None, Field(description='Optional security and embedding metadata') ] = None output_format: Annotated[ Literal['html'], Field(description='Discriminator indicating preview_html is provided') ] preview_html: Annotated[ str, Field( description='Raw HTML for this rendered piece. Can be embedded directly in the page without iframe. Security warning: Only use with trusted creative agents as this bypasses iframe sandboxing.' ), ] render_id: Annotated[ str, Field(description='Unique identifier for this rendered piece within the variant') ] role: Annotated[ str, Field( description="Semantic role of this rendered piece. Use 'primary' for main content, 'companion' for associated banners, descriptive strings for device variants or custom roles." ), ]Base model for AdCP types with spec-compliant serialization.
Defaults to
extra='ignore'so that unknown fields from newer spec versions are silently dropped rather than causing validation errors. Generated types whose schemas setadditionalProperties: trueoverride this withextra='allow'in their ownmodel_config. Consumers who want strict validation can override withextra='forbid'.Create a new model by parsing and validating input data from keyword arguments.
Raises [
ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.selfis explicitly positional-only to allowselfas a field name.Ancestors
- AdCPBaseModel
- pydantic.main.BaseModel
Class variables
var dimensions : Dimensions | Nonevar embedding : Embedding | Nonevar model_configvar output_format : Literal['html']var preview_html : strvar render_id : strvar role : str
Inherited members
class BothPreviewRender (**data: Any)-
Expand source code
class PreviewRender3(AdCPBaseModel): model_config = ConfigDict( extra='allow', ) dimensions: Annotated[ Dimensions | None, Field(description='Dimensions for this rendered piece') ] = None embedding: Annotated[ Embedding | None, Field(description='Optional security and embedding metadata for safe iframe integration'), ] = None output_format: Annotated[ Literal['both'], Field( description='Discriminator indicating both preview_url and preview_html are provided' ), ] preview_html: Annotated[ str, Field( description='Raw HTML for this rendered piece. Can be embedded directly in the page without iframe. Security warning: Only use with trusted creative agents as this bypasses iframe sandboxing.' ), ] preview_url: Annotated[ AnyUrl, Field( description='URL to an HTML page that renders this piece. Can be embedded in an iframe.' ), ] render_id: Annotated[ str, Field(description='Unique identifier for this rendered piece within the variant') ] role: Annotated[ str, Field( description="Semantic role of this rendered piece. Use 'primary' for main content, 'companion' for associated banners, descriptive strings for device variants or custom roles." ), ]Base model for AdCP types with spec-compliant serialization.
Defaults to
extra='ignore'so that unknown fields from newer spec versions are silently dropped rather than causing validation errors. Generated types whose schemas setadditionalProperties: trueoverride this withextra='allow'in their ownmodel_config. Consumers who want strict validation can override withextra='forbid'.Create a new model by parsing and validating input data from keyword arguments.
Raises [
ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.selfis explicitly positional-only to allowselfas a field name.Ancestors
- AdCPBaseModel
- pydantic.main.BaseModel
Class variables
var dimensions : Dimensions | Nonevar embedding : Embedding | Nonevar model_configvar output_format : Literal['both']var preview_html : strvar preview_url : pydantic.networks.AnyUrlvar render_id : strvar role : str
Inherited members
class PriceGuidance (**data: Any)-
Expand source code
class PriceGuidance(AdCPBaseModel): model_config = ConfigDict( extra='allow', ) p25: Annotated[ float | None, Field(description='25th percentile of recent winning bids', ge=0.0) ] = None p50: Annotated[float | None, Field(description='Median of recent winning bids', ge=0.0)] = None p75: Annotated[ float | None, Field(description='75th percentile of recent winning bids', ge=0.0) ] = None p90: Annotated[ float | None, Field(description='90th percentile of recent winning bids', ge=0.0) ] = NoneBase model for AdCP types with spec-compliant serialization.
Defaults to
extra='ignore'so that unknown fields from newer spec versions are silently dropped rather than causing validation errors. Generated types whose schemas setadditionalProperties: trueoverride this withextra='allow'in their ownmodel_config. Consumers who want strict validation can override withextra='forbid'.Create a new model by parsing and validating input data from keyword arguments.
Raises [
ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.selfis explicitly positional-only to allowselfas a field name.Ancestors
- AdCPBaseModel
- pydantic.main.BaseModel
Class variables
var model_configvar p25 : float | Nonevar p50 : float | Nonevar p75 : float | Nonevar p90 : float | None
Inherited members
class PricingModel (*args, **kwds)-
Expand source code
class PricingModel(Enum): cpm = 'cpm' vcpm = 'vcpm' cpc = 'cpc' cpcv = 'cpcv' cpv = 'cpv' cpp = 'cpp' cpa = 'cpa' flat_rate = 'flat_rate' time = 'time'Create a collection of name/value pairs.
Example enumeration:
>>> class Color(Enum): ... RED = 1 ... BLUE = 2 ... GREEN = 3Access them by:
- attribute access::
>>> Color.RED <Color.RED: 1>- value lookup:
>>> Color(1) <Color.RED: 1>- name lookup:
>>> Color['RED'] <Color.RED: 1>Enumerations can be iterated over, and know how many members they have:
>>> len(Color) 3>>> list(Color) [<Color.RED: 1>, <Color.BLUE: 2>, <Color.GREEN: 3>]Methods can be added to enumerations, and members can have their own attributes – see the documentation for details.
Ancestors
- enum.Enum
Class variables
var cpavar cpcvar cpcvvar cpmvar cppvar cpvvar flat_ratevar timevar vcpm
class Product (**data: Any)-
Expand source code
class Product(AdCPBaseModel): model_config = ConfigDict( extra='allow', ) brief_relevance: Annotated[ str | None, Field( description='Explanation of why this product matches the brief (only included when brief is provided)' ), ] = None catalog_match: Annotated[ CatalogMatch | None, Field( description='When the buyer provides a catalog on get_products, indicates which catalog items are eligible for this product. Only present for products where catalog matching is relevant (e.g., sponsored product listings, job boards, hotel ads).' ), ] = None catalog_types: Annotated[ list[catalog_type.CatalogType] | None, Field( description='Catalog types this product supports for catalog-driven campaigns. A sponsored product listing declares ["product"], a job board declares ["job", "offering"]. Buyers match synced catalogs to products via this field.', min_length=1, ), ] = None channels: Annotated[ list[channels_1.MediaChannel] | None, Field( description="Advertising channels this product is sold as. Products inherit from their properties' supported_channels but may narrow the scope. For example, a product covering YouTube properties might be sold as ['ctv'] even though those properties support ['olv', 'social', 'ctv']." ), ] = None collection_targeting_allowed: Annotated[ bool | None, Field( description="Whether buyers can target a subset of this product's collections. When false (default), the product is a bundle — buyers get all listed collections. When true, buyers can select specific collections in the media buy." ), ] = False collections: Annotated[ list[collection_selector.CollectionSelector] | None, Field( description='Collections available in this product. Each entry references collections declared in an adagents.json by domain and collection ID. Buyers resolve full collection objects from the referenced adagents.json.', min_length=1, ), ] = None conversion_tracking: Annotated[ ConversionTracking | None, Field( description="Conversion event tracking for this product. Presence indicates the product supports optimization_goals with kind: 'event'. Seller-level capabilities (supported event types, UID types, attribution windows) are declared in get_adcp_capabilities." ), ] = None creative_policy: creative_policy_1.CreativePolicy | None = None data_provider_signals: Annotated[ list[data_provider_signal_selector.DataProviderSignalSelector] | None, Field( description="Data provider signals available for this product. Buyers fetch signal definitions from each data provider's adagents.json and can verify agent authorization." ), ] = None delivery_measurement: Annotated[ DeliveryMeasurement | None, Field( description='Measurement provider and methodology for delivery metrics. The buyer accepts the declared provider as the source of truth for the buy. When absent, buyers should apply their own measurement defaults.' ), ] = None delivery_type: delivery_type_1.DeliveryType description: Annotated[ str, Field(description='Detailed description of the product and its inventory') ] enforced_policies: Annotated[ list[str] | None, Field( description='Registry policy IDs the seller enforces for this product. Enforcement level comes from the policy registry. Buyers can filter products by required policies.' ), ] = None exclusivity: Annotated[ exclusivity_1.Exclusivity | None, Field( description="Whether this product offers exclusive access to its inventory. Defaults to 'none' when absent. Most relevant for guaranteed products tied to specific collections or placements." ), ] = None expires_at: Annotated[ AwareDatetime | None, Field( description='Expiration timestamp. After this time, the product may no longer be available for purchase and create_media_buy may reject packages referencing it.' ), ] = None ext: ext_1.ExtensionObject | None = None forecast: Annotated[ delivery_forecast.DeliveryForecast | None, Field( description='Forecasted delivery metrics for this product. Gives buyers an estimate of expected performance before requesting a proposal.' ), ] = None format_ids: Annotated[ list[format_id_1.FormatId], Field( description='Array of supported creative format IDs - structured format_id objects with agent_url and id' ), ] installments: Annotated[ list[installment.Installment] | None, Field( description='Specific installments included in this product. Each installment references its parent collection via collection_id when the product spans multiple collections. When absent with collections present, the product covers the collections broadly (run-of-collection).' ), ] = None is_custom: Annotated[bool | None, Field(description='Whether this is a custom product')] = None material_submission: Annotated[ MaterialSubmission | None, Field( description="Instructions for submitting physical creative materials (print, static OOH, cinema). Present only for products requiring physical delivery outside the digital creative assignment flow. Buyer agents MUST validate url and email domains against the seller's known domains (from adagents.json) before submitting materials. Never auto-submit without human confirmation." ), ] = None max_optimization_goals: Annotated[ int | None, Field( description='Maximum number of optimization_goals this product accepts on a package. When absent, no limit is declared. Most social platforms accept only 1 goal — buyers sending arrays longer than this value should expect the seller to use only the highest-priority (lowest priority number) goal.', ge=1, ), ] = None measurement_readiness: Annotated[ measurement_readiness_1.MeasurementReadiness | None, Field( description="Assessment of whether the buyer's event source setup is sufficient for this product to optimize effectively. Only present when the seller can evaluate the buyer's account context. Buyers should check this before creating media buys with event-based optimization goals." ), ] = None metric_optimization: Annotated[ MetricOptimization | None, Field( description="Metric optimization capabilities for this product. Presence indicates the product supports optimization_goals with kind: 'metric'. No event source or conversion tracking setup required — the seller tracks these metrics natively." ), ] = None name: Annotated[str, Field(description='Human-readable product name')] outcome_measurement: outcome_measurement_1.OutcomeMeasurement | None = None placements: Annotated[ list[placement.Placement] | None, Field( description='Optional array of specific placements within this product. When provided, buyers can target specific placements when assigning creatives.', min_length=1, ), ] = None pricing_options: Annotated[ list[pricing_option.PricingOption], Field(description='Available pricing models for this product', min_length=1), ] product_card: Annotated[ ProductCard | None, Field( description='Optional standard visual card (300x400px) for displaying this product in user interfaces. Can be rendered via preview_creative or pre-generated.' ), ] = None product_card_detailed: Annotated[ ProductCardDetailed | None, Field( description='Optional detailed card with carousel and full specifications. Provides rich product presentation similar to media kit pages.' ), ] = None product_id: Annotated[str, Field(description='Unique identifier for the product')] property_targeting_allowed: Annotated[ bool | None, Field( description="Whether buyers can filter this product to a subset of its publisher_properties. When false (default), the product is 'all or nothing' - buyers must accept all properties or the product is excluded from property_list filtering results." ), ] = False publisher_properties: Annotated[ list[publisher_property_selector.PublisherPropertySelector], Field( description="Publisher properties covered by this product. Buyers fetch actual property definitions from each publisher's adagents.json and validate agent authorization. Selection patterns mirror the authorization patterns in adagents.json for consistency.", min_length=1, ), ] reporting_capabilities: reporting_capabilities_1.ReportingCapabilities | None = None signal_targeting_allowed: Annotated[ bool | None, Field( description='Whether buyers can filter this product to a subset of its data_provider_signals. When false (default), the product includes all listed signals as a bundle. When true, buyers can target specific signals.' ), ] = False trusted_match: Annotated[ TrustedMatch | None, Field( description='Trusted Match Protocol capabilities for this product. When present, the product supports real-time contextual and/or identity matching via TMP. Buyers use this to determine what response types the publisher can accept and whether brands can be selected dynamically at match time.' ), ] = NoneBase model for AdCP types with spec-compliant serialization.
Defaults to
extra='ignore'so that unknown fields from newer spec versions are silently dropped rather than causing validation errors. Generated types whose schemas setadditionalProperties: trueoverride this withextra='allow'in their ownmodel_config. Consumers who want strict validation can override withextra='forbid'.Create a new model by parsing and validating input data from keyword arguments.
Raises [
ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.selfis explicitly positional-only to allowselfas a field name.Ancestors
- AdCPBaseModel
- pydantic.main.BaseModel
Class variables
var brief_relevance : str | Nonevar catalog_match : CatalogMatch | Nonevar catalog_types : list[CatalogType] | Nonevar channels : list[MediaChannel] | Nonevar collection_targeting_allowed : bool | Nonevar collections : list[CollectionSelector] | Nonevar conversion_tracking : ConversionTracking | Nonevar creative_policy : CreativePolicy | Nonevar data_provider_signals : list[DataProviderSignalSelector] | Nonevar delivery_measurement : DeliveryMeasurement | Nonevar delivery_type : DeliveryTypevar description : strvar enforced_policies : list[str] | Nonevar exclusivity : Exclusivity | Nonevar expires_at : pydantic.types.AwareDatetime | Nonevar ext : ExtensionObject | Nonevar forecast : DeliveryForecast | Nonevar format_ids : list[FormatId]var installments : list[Installment] | Nonevar is_custom : bool | Nonevar material_submission : MaterialSubmission | Nonevar max_optimization_goals : int | Nonevar measurement_readiness : MeasurementReadiness | Nonevar metric_optimization : MetricOptimization | Nonevar model_configvar name : strvar outcome_measurement : OutcomeMeasurement | Nonevar placements : list[Placement] | Nonevar pricing_options : list[PricingOption]var product_card : ProductCard | Nonevar product_card_detailed : ProductCardDetailed | Nonevar product_id : strvar property_targeting_allowed : bool | Nonevar publisher_properties : list[PublisherPropertySelector]var reporting_capabilities : ReportingCapabilities | Nonevar signal_targeting_allowed : bool | Nonevar trusted_match : TrustedMatch | None
Inherited members
class ProductFilters (**data: Any)-
Expand source code
class ProductFilters(AdCPBaseModel): model_config = ConfigDict( extra='allow', ) budget_range: Annotated[ BudgetRange | BudgetRange1 | None, Field(description='Budget range to filter appropriate products'), ] = None channels: Annotated[ list[channels_1.MediaChannel] | None, Field( description="Filter by advertising channels (e.g., ['display', 'ctv', 'dooh'])", min_length=1, ), ] = None countries: Annotated[ list[Country] | None, Field( description="Filter by country coverage using ISO 3166-1 alpha-2 codes (e.g., ['US', 'CA', 'GB']). Works for all inventory types.", min_length=1, ), ] = None delivery_type: delivery_type_1.DeliveryType | None = None end_date: Annotated[ date_aliased | None, Field( description='Campaign end date (ISO 8601 date format: YYYY-MM-DD) for availability checks' ), ] = None exclusivity: Annotated[ exclusivity_1.Exclusivity | None, Field( description="Filter by exclusivity level. Returns products matching the specified exclusivity (e.g., 'exclusive' returns only sole-sponsorship products)." ), ] = None format_ids: Annotated[ list[format_id.FormatId] | None, Field(description='Filter by specific format IDs', min_length=1), ] = None geo_proximity: Annotated[ list[GeoProximity | GeoProximity2 | GeoProximity3] | None, Field( description='Filter by proximity to geographic points. Returns products with inventory coverage near these locations. Follows the same format as the targeting overlay — each entry uses exactly one method: travel_time + transport_mode, radius, or geometry. For locally-bound inventory (DOOH, radio), filters to products with coverage in the area. For digital inventory, filters to products from sellers supporting geo_proximity targeting.', min_length=1, ), ] = None is_fixed_price: Annotated[ bool | None, Field( description='Filter by pricing availability: true = products offering fixed pricing (at least one option with fixed_price), false = products offering auction pricing (at least one option without fixed_price). Products with both fixed and auction options match both true and false.' ), ] = None keywords: Annotated[ list[Keyword] | None, Field( description='Filter by keyword relevance for search and retail media platforms. Returns products that support keyword targeting for these terms. Allows the sell-side agent to assess keyword availability and recommend appropriate products. Use match_type to indicate the desired precision.', min_length=1, ), ] = None metros: Annotated[ list[Metro] | None, Field( description='Filter by metro coverage for locally-bound inventory (radio, DOOH, local TV). Use when products have DMA/metro-specific coverage. For digital inventory where products have broad coverage, use required_geo_targeting instead to filter by seller capability.', min_length=1, ), ] = None min_exposures: Annotated[ int | None, Field(description='Minimum exposures/impressions needed for measurement validity', ge=1), ] = None postal_areas: Annotated[ list[PostalArea] | None, Field( description='Filter by postal area coverage for locally-bound inventory (direct mail, DOOH, local campaigns). Use when products have postal-area-specific coverage. For digital inventory where products have broad coverage, use required_geo_targeting instead to filter by seller capability.', min_length=1, ), ] = None regions: Annotated[ list[Region] | None, Field( description="Filter by region coverage using ISO 3166-2 codes (e.g., ['US-NY', 'US-CA', 'GB-SCT']). Use for locally-bound inventory (regional OOH, local TV) where products have region-specific coverage.", min_length=1, ), ] = None required_axe_integrations: Annotated[ list[AnyUrl] | None, Field( deprecated=True, description='Deprecated: Use trusted_match filter instead. Filter to products executable through specific agentic ad exchanges. URLs are canonical identifiers.', ), ] = None required_features: Annotated[ media_buy_features.MediaBuyFeatures | None, Field( description='Filter to products from sellers supporting specific protocol features. Only features set to true are used for filtering.' ), ] = None required_geo_targeting: Annotated[ list[RequiredGeoTargetingItem] | None, Field( description='Filter to products from sellers supporting specific geo targeting capabilities. Each entry specifies a targeting level (country, region, metro, postal_area) and optionally a system for levels that have multiple classification systems.', min_length=1, ), ] = None signal_targeting: Annotated[ list[signal_targeting_1.SignalTargeting] | None, Field( description='Filter to products supporting specific signals from data provider catalogs. Products must have the requested signals in their data_provider_signals and signal_targeting_allowed must be true (or all signals requested).', min_length=1, ), ] = None standard_formats_only: Annotated[ bool | None, Field(description='Only return products accepting IAB standard formats') ] = None start_date: Annotated[ date_aliased | None, Field( description='Campaign start date (ISO 8601 date format: YYYY-MM-DD) for availability checks' ), ] = None trusted_match: Annotated[ TrustedMatch | None, Field( description='Filter products by Trusted Match Protocol capabilities. Only products with matching TMP support are returned.' ), ] = NoneBase model for AdCP types with spec-compliant serialization.
Defaults to
extra='ignore'so that unknown fields from newer spec versions are silently dropped rather than causing validation errors. Generated types whose schemas setadditionalProperties: trueoverride this withextra='allow'in their ownmodel_config. Consumers who want strict validation can override withextra='forbid'.Create a new model by parsing and validating input data from keyword arguments.
Raises [
ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.selfis explicitly positional-only to allowselfas a field name.Ancestors
- AdCPBaseModel
- pydantic.main.BaseModel
Class variables
var budget_range : BudgetRange | BudgetRange1 | Nonevar channels : list[MediaChannel] | Nonevar countries : list[Country] | Nonevar delivery_type : DeliveryType | Nonevar end_date : datetime.date | Nonevar exclusivity : Exclusivity | Nonevar format_ids : list[FormatId] | Nonevar geo_proximity : list[GeoProximity | GeoProximity2 | GeoProximity3] | Nonevar is_fixed_price : bool | Nonevar keywords : list[Keyword] | Nonevar metros : list[Metro] | Nonevar min_exposures : int | Nonevar model_configvar postal_areas : list[PostalArea] | Nonevar regions : list[Region] | Nonevar required_features : MediaBuyFeatures | Nonevar required_geo_targeting : list[RequiredGeoTargetingItem] | Nonevar signal_targeting : list[SignalTargeting] | Nonevar standard_formats_only : bool | Nonevar start_date : datetime.date | Nonevar trusted_match : TrustedMatch | None
Instance variables
var required_axe_integrations : list[pydantic.networks.AnyUrl] | None-
Expand source code
def __get__(self, obj: BaseModel | None, obj_type: type[BaseModel] | None = None) -> Any: if obj is None: if self.wrapped_property is not None: return self.wrapped_property.__get__(None, obj_type) raise AttributeError(self.field_name) warnings.warn(self.msg, DeprecationWarning, stacklevel=2) if self.wrapped_property is not None: return self.wrapped_property.__get__(obj, obj_type) return obj.__dict__[self.field_name]Read-only data descriptor used to emit a runtime deprecation warning before accessing a deprecated field.
Attributes
msg- The deprecation message to be emitted.
wrapped_property- The property instance if the deprecated field is a computed field, or
None. field_name- The name of the field being deprecated.
Inherited members
class Property (**data: Any)-
Expand source code
class Property(AdCPBaseModel): model_config = ConfigDict( extra='allow', ) identifiers: Annotated[ list[Identifier], Field(description='Array of identifiers for this property', min_length=1) ] name: Annotated[str, Field(description='Human-readable property name')] property_id: Annotated[ property_id_1.PropertyId | None, Field( description='Unique identifier for this property (optional). Enables referencing properties by ID instead of repeating full objects.' ), ] = None property_type: Annotated[ property_type_1.PropertyType, Field(description='Type of advertising property') ] publisher_domain: Annotated[ str | None, Field( description='Domain where adagents.json should be checked for authorization validation. Optional in adagents.json (file location implies domain).' ), ] = None supported_channels: Annotated[ list[channels.MediaChannel] | None, Field( description="Advertising channels this property supports (e.g., ['display', 'olv', 'social']). Publishers declare which channels their inventory aligns with. Properties may support multiple channels. See the Media Channel Taxonomy for definitions." ), ] = None tags: Annotated[ list[property_tag.PropertyTag] | None, Field( description='Tags for categorization and grouping (e.g., network membership, content categories)' ), ] = NoneBase model for AdCP types with spec-compliant serialization.
Defaults to
extra='ignore'so that unknown fields from newer spec versions are silently dropped rather than causing validation errors. Generated types whose schemas setadditionalProperties: trueoverride this withextra='allow'in their ownmodel_config. Consumers who want strict validation can override withextra='forbid'.Create a new model by parsing and validating input data from keyword arguments.
Raises [
ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.selfis explicitly positional-only to allowselfas a field name.Ancestors
- AdCPBaseModel
- pydantic.main.BaseModel
Class variables
var identifiers : list[Identifier]var model_configvar name : strvar property_id : PropertyId | Nonevar property_type : PropertyTypevar publisher_domain : str | Nonevar supported_channels : list[MediaChannel] | None
Inherited members
class PropertyActivity (**data: Any)-
Expand source code
class PropertyActivity(RegistryBaseModel): domain: Annotated[str, Field(examples=["examplepub.com"])] total: Annotated[int, Field(examples=[3])] revisions: list[ActivityRevision]Base model for registry API types.
Uses
extra='allow'so that new fields from the registry API are preserved rather than dropped. This differs from AdCPBaseModel which defaults toextra='ignore'for protocol types.Create a new model by parsing and validating input data from keyword arguments.
Raises [
ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.selfis explicitly positional-only to allowselfas a field name.Ancestors
- RegistryBaseModel
- pydantic.main.BaseModel
Class variables
var domain : strvar model_configvar revisions : list[ActivityRevision]var total : int
class PropertyId (root: RootModelRootType = PydanticUndefined, **data)-
Expand source code
class PropertyId(RootModel[str]): root: Annotated[ str, Field( description='Identifier for a publisher property. Must be lowercase alphanumeric with underscores only.', examples=['cnn_ctv_app', 'homepage', 'mobile_ios', 'instagram'], pattern='^[a-z0-9_]+$', title='Property ID', ), ]Usage Documentation
A Pydantic
BaseModelfor the root object of the model.Attributes
root- The root object of the model.
__pydantic_root_model__- Whether the model is a RootModel.
__pydantic_private__- Private fields in the model.
__pydantic_extra__- Extra fields in the model.
Create a new model by parsing and validating input data from keyword arguments.
Raises [
ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.selfis explicitly positional-only to allowselfas a field name.Ancestors
- pydantic.root_model.RootModel[str]
- pydantic.root_model.RootModel
- pydantic.main.BaseModel
- typing.Generic
Class variables
var model_configvar root : str
class PropertyIdentifier (**data: Any)-
Expand source code
class PropertyIdentifier(RegistryBaseModel): type: Annotated[str, Field(examples=["domain"])] value: Annotated[str, Field(examples=["examplepub.com"])]Base model for registry API types.
Uses
extra='allow'so that new fields from the registry API are preserved rather than dropped. This differs from AdCPBaseModel which defaults toextra='ignore'for protocol types.Create a new model by parsing and validating input data from keyword arguments.
Raises [
ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.selfis explicitly positional-only to allowselfas a field name.Ancestors
- RegistryBaseModel
- pydantic.main.BaseModel
Class variables
var model_configvar type : strvar value : str
class PropertyRegistry (client: RegistryClient,
*,
auth_token: str | None = None,
poll_interval: float = 60.0,
cursor_store: CursorStore | None = None)-
Expand source code
class PropertyRegistry: """Local cache of property/agent authorization relationships. Queries are synchronous dict lookups — no network calls. Background sync is opt-in via ``auth_token``. Args: client: RegistryClient for API calls. auth_token: Bearer token for change feed access. If omitted, background sync is disabled (load-only mode). poll_interval: Seconds between feed polls (default 60). cursor_store: Optional CursorStore for feed cursor persistence. """ def __init__( self, client: RegistryClient, *, auth_token: str | None = None, poll_interval: float = 60.0, cursor_store: CursorStore | None = None, ) -> None: self._client = client self._auth_token = auth_token self._poll_interval = poll_interval self._cursor_store = cursor_store self._domain_to_agents: dict[str, set[str]] = {} self._agent_to_domains: dict[str, set[str]] = {} self._loaded = False self._sync: RegistrySync | None = None self._task: asyncio.Task[None] | None = None # ------------------------------------------------------------------ # Queries (synchronous, no network) # ------------------------------------------------------------------ def is_authorized(self, agent_url: str, domain: str) -> bool: """Check if an agent is authorized for a domain.""" return agent_url in self._domain_to_agents.get(domain, set()) def get_domains(self, agent_url: str) -> frozenset[str]: """Get all domains authorized for an agent.""" return frozenset(self._agent_to_domains.get(agent_url, set())) def get_agents(self, domain: str) -> frozenset[str]: """Get all agents authorized for a domain.""" return frozenset(self._domain_to_agents.get(domain, set())) @property def agent_count(self) -> int: """Number of agents in the index.""" return len(self._agent_to_domains) @property def domain_count(self) -> int: """Number of domains in the index.""" return len(self._domain_to_agents) @property def loaded(self) -> bool: """Whether initial data has been loaded.""" return self._loaded # ------------------------------------------------------------------ # Lifecycle # ------------------------------------------------------------------ async def load(self) -> None: """Fetch initial state from the registry API. Calls ``list_agents()`` and builds the bidirectional authorization index from each agent's ``publisher_domains``. """ agents = await self._client.list_agents(properties=True) domain_to_agents: dict[str, set[str]] = {} agent_to_domains: dict[str, set[str]] = {} for agent in agents: domains = agent.publisher_domains or [] if domains: agent_to_domains[agent.url] = set(domains) for domain in domains: domain_to_agents.setdefault(domain, set()).add(agent.url) self._domain_to_agents = domain_to_agents self._agent_to_domains = agent_to_domains self._loaded = True logger.info( "PropertyRegistry loaded: %d agents, %d domains", len(agent_to_domains), len(domain_to_agents), ) async def start(self) -> None: """Load initial state and start background sync. If ``auth_token`` was not provided, only loads initial state without starting the polling loop. """ if not self._loaded: await self.load() if self._auth_token is None: logger.info( "PropertyRegistry: no auth_token, background sync disabled" ) return self._sync = RegistrySync( self._client, auth_token=self._auth_token, poll_interval=self._poll_interval, cursor_store=self._cursor_store, types="authorization.*,agent.*,property.*", ) self._sync.on_all(self._handle_event) self._task = asyncio.create_task(self._sync.start()) async def stop(self) -> None: """Stop background sync.""" if self._sync is not None: await self._sync.stop() if self._task is not None: await self._task self._task = None self._sync = None async def __aenter__(self) -> PropertyRegistry: await self.start() return self async def __aexit__(self, *args: object) -> None: await self.stop() async def refresh(self) -> None: """Force a full reload from the API.""" self._domain_to_agents.clear() self._agent_to_domains.clear() self._loaded = False await self.load() # ------------------------------------------------------------------ # Event handling # # Trust model: events are fetched over HTTPS from the registry API # using a Bearer token. The events are not cryptographically signed. # A compromised transport or registry could inject forged events. # ------------------------------------------------------------------ async def _handle_event(self, event: FeedEvent) -> None: """Route feed events to the appropriate handler.""" et = event.event_type if et.startswith("authorization."): self._apply_authorization(event) elif et == "agent.deleted": self._remove_agent(event.entity_id) elif et in ("agent.created", "agent.updated"): await self._refresh_agent(event.payload.get("url", event.entity_id)) elif et == "property.deleted": self._remove_domain(event.entity_id) # Unknown event types: ignore silently (forward compatible) _ADD_TYPES = {"authorization.created", "authorization.granted"} _REMOVE_TYPES = {"authorization.revoked", "authorization.deleted"} def _apply_authorization(self, event: FeedEvent) -> None: """Add or remove an authorization edge.""" agent_url = event.payload.get("agent_url", "") domain = event.payload.get("domain", "") if not agent_url or not domain: return if event.event_type in self._ADD_TYPES: self._domain_to_agents.setdefault(domain, set()).add(agent_url) self._agent_to_domains.setdefault(agent_url, set()).add(domain) elif event.event_type in self._REMOVE_TYPES: self._domain_to_agents.get(domain, set()).discard(agent_url) self._agent_to_domains.get(agent_url, set()).discard(domain) def _remove_agent(self, agent_url: str) -> None: """Remove all authorization edges for an agent.""" domains = self._agent_to_domains.pop(agent_url, set()) for domain in domains: agents = self._domain_to_agents.get(domain) if agents is not None: agents.discard(agent_url) if not agents: del self._domain_to_agents[domain] def _remove_domain(self, domain: str) -> None: """Remove all authorization edges for a domain.""" agents = self._domain_to_agents.pop(domain, set()) for agent_url in agents: domains = self._agent_to_domains.get(agent_url) if domains is not None: domains.discard(domain) if not domains: del self._agent_to_domains[agent_url] async def _refresh_agent(self, agent_url: str) -> None: """Re-fetch a single agent's domains and update indexes.""" try: data = await self._client.get_agent_domains(agent_url) new_domains = { p["domain"] for p in data.get("properties", []) if "domain" in p } except Exception as exc: logger.warning("Failed to refresh agent %s: %s", agent_url, exc) return # Remove old edges old_domains = self._agent_to_domains.get(agent_url, set()) for d in old_domains: s = self._domain_to_agents.get(d) if s is not None: s.discard(agent_url) if not s: del self._domain_to_agents[d] # Add new edges if new_domains: self._agent_to_domains[agent_url] = new_domains for d in new_domains: self._domain_to_agents.setdefault(d, set()).add(agent_url) else: self._agent_to_domains.pop(agent_url, None)Local cache of property/agent authorization relationships.
Queries are synchronous dict lookups — no network calls. Background sync is opt-in via
auth_token.Args
client- RegistryClient for API calls.
auth_token- Bearer token for change feed access. If omitted, background sync is disabled (load-only mode).
poll_interval- Seconds between feed polls (default 60).
cursor_store- Optional CursorStore for feed cursor persistence.
Instance variables
prop agent_count : int-
Expand source code
@property def agent_count(self) -> int: """Number of agents in the index.""" return len(self._agent_to_domains)Number of agents in the index.
prop domain_count : int-
Expand source code
@property def domain_count(self) -> int: """Number of domains in the index.""" return len(self._domain_to_agents)Number of domains in the index.
prop loaded : bool-
Expand source code
@property def loaded(self) -> bool: """Whether initial data has been loaded.""" return self._loadedWhether initial data has been loaded.
Methods
def get_agents(self, domain: str) ‑> frozenset[str]-
Expand source code
def get_agents(self, domain: str) -> frozenset[str]: """Get all agents authorized for a domain.""" return frozenset(self._domain_to_agents.get(domain, set()))Get all agents authorized for a domain.
def get_domains(self, agent_url: str) ‑> frozenset[str]-
Expand source code
def get_domains(self, agent_url: str) -> frozenset[str]: """Get all domains authorized for an agent.""" return frozenset(self._agent_to_domains.get(agent_url, set()))Get all domains authorized for an agent.
-
Expand source code
def is_authorized(self, agent_url: str, domain: str) -> bool: """Check if an agent is authorized for a domain.""" return agent_url in self._domain_to_agents.get(domain, set())Check if an agent is authorized for a domain.
async def load(self) ‑> None-
Expand source code
async def load(self) -> None: """Fetch initial state from the registry API. Calls ``list_agents()`` and builds the bidirectional authorization index from each agent's ``publisher_domains``. """ agents = await self._client.list_agents(properties=True) domain_to_agents: dict[str, set[str]] = {} agent_to_domains: dict[str, set[str]] = {} for agent in agents: domains = agent.publisher_domains or [] if domains: agent_to_domains[agent.url] = set(domains) for domain in domains: domain_to_agents.setdefault(domain, set()).add(agent.url) self._domain_to_agents = domain_to_agents self._agent_to_domains = agent_to_domains self._loaded = True logger.info( "PropertyRegistry loaded: %d agents, %d domains", len(agent_to_domains), len(domain_to_agents), )Fetch initial state from the registry API.
Calls
list_agents()and builds the bidirectional authorization index from each agent'spublisher_domains. async def refresh(self) ‑> None-
Expand source code
async def refresh(self) -> None: """Force a full reload from the API.""" self._domain_to_agents.clear() self._agent_to_domains.clear() self._loaded = False await self.load()Force a full reload from the API.
async def start(self) ‑> None-
Expand source code
async def start(self) -> None: """Load initial state and start background sync. If ``auth_token`` was not provided, only loads initial state without starting the polling loop. """ if not self._loaded: await self.load() if self._auth_token is None: logger.info( "PropertyRegistry: no auth_token, background sync disabled" ) return self._sync = RegistrySync( self._client, auth_token=self._auth_token, poll_interval=self._poll_interval, cursor_store=self._cursor_store, types="authorization.*,agent.*,property.*", ) self._sync.on_all(self._handle_event) self._task = asyncio.create_task(self._sync.start())Load initial state and start background sync.
If
auth_tokenwas not provided, only loads initial state without starting the polling loop. async def stop(self) ‑> None-
Expand source code
async def stop(self) -> None: """Stop background sync.""" if self._sync is not None: await self._sync.stop() if self._task is not None: await self._task self._task = None self._sync = NoneStop background sync.
class PropertyRegistryItem (**data: Any)-
Expand source code
class PropertyRegistryItem(RegistryBaseModel): domain: Annotated[str, Field(examples=["examplepub.com"])] source: PropertyRegistrySource property_count: int agent_count: int verified: boolBase model for registry API types.
Uses
extra='allow'so that new fields from the registry API are preserved rather than dropped. This differs from AdCPBaseModel which defaults toextra='ignore'for protocol types.Create a new model by parsing and validating input data from keyword arguments.
Raises [
ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.selfis explicitly positional-only to allowselfas a field name.Ancestors
- RegistryBaseModel
- pydantic.main.BaseModel
Class variables
var agent_count : intvar domain : strvar model_configvar property_count : intvar source : PropertyRegistrySourcevar verified : bool
class PropertySummary (**data: Any)-
Expand source code
class PropertySummary(RegistryBaseModel): total_count: int count_by_type: dict[str, int] tags: list[str] publisher_count: intBase model for registry API types.
Uses
extra='allow'so that new fields from the registry API are preserved rather than dropped. This differs from AdCPBaseModel which defaults toextra='ignore'for protocol types.Create a new model by parsing and validating input data from keyword arguments.
Raises [
ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.selfis explicitly positional-only to allowselfas a field name.Ancestors
- RegistryBaseModel
- pydantic.main.BaseModel
Class variables
var count_by_type : dict[str, int]var model_configvar publisher_count : intvar total_count : int
class PropertyTag (root: RootModelRootType = PydanticUndefined, **data)-
Expand source code
class PropertyTag(RootModel[str]): root: Annotated[ str, Field( description='Tag for categorizing publisher properties. Must be lowercase alphanumeric with underscores only.', examples=['ctv', 'premium', 'news', 'sports', 'meta_network', 'social_media'], pattern='^[a-z0-9_]+$', title='Property Tag', ), ]Usage Documentation
A Pydantic
BaseModelfor the root object of the model.Attributes
root- The root object of the model.
__pydantic_root_model__- Whether the model is a RootModel.
__pydantic_private__- Private fields in the model.
__pydantic_extra__- Extra fields in the model.
Create a new model by parsing and validating input data from keyword arguments.
Raises [
ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.selfis explicitly positional-only to allowselfas a field name.Ancestors
- pydantic.root_model.RootModel[str]
- pydantic.root_model.RootModel
- pydantic.main.BaseModel
- typing.Generic
Class variables
var model_configvar root : str
class Proposal (**data: Any)-
Expand source code
class Proposal(AdCPBaseModel): model_config = ConfigDict( extra='allow', ) allocations: Annotated[ list[product_allocation.ProductAllocation], Field( description='Budget allocations across products. Allocation percentages MUST sum to 100. Publishers are responsible for ensuring the sum equals 100; buyers SHOULD validate this before execution.', min_length=1, ), ] brief_alignment: Annotated[ str | None, Field( description='Explanation of how this proposal aligns with the campaign brief', max_length=2000, ), ] = None description: Annotated[ str | None, Field( description='Explanation of the proposal strategy and what it achieves', max_length=2000 ), ] = None expires_at: Annotated[ AwareDatetime | None, Field( description='When this proposal expires and can no longer be executed. For draft proposals, indicates when indicative pricing becomes stale. For committed proposals, indicates when the inventory hold lapses — the buyer must call create_media_buy before this time.' ), ] = None ext: ext_1.ExtensionObject | None = None forecast: Annotated[ delivery_forecast.DeliveryForecast | None, Field( description='Aggregate forecasted delivery metrics for the entire proposal. When both proposal-level and allocation-level forecasts are present, the proposal-level forecast is authoritative for total delivery estimation.' ), ] = None insertion_order: Annotated[ insertion_order_1.InsertionOrder | None, Field( description='Formal insertion order attached to a committed proposal. Present when the seller requires a signed agreement before the media buy can proceed. The buyer references the io_id in io_acceptance on create_media_buy.' ), ] = None name: Annotated[ str, Field(description='Human-readable name for this media plan proposal', max_length=500) ] proposal_id: Annotated[ str, Field( description='Unique identifier for this proposal. Used to execute it via create_media_buy.', max_length=255, ), ] proposal_status: Annotated[ proposal_status_1.ProposalStatus | None, Field( description="Lifecycle status of this proposal. When absent, the proposal is ready to buy (backward compatible). 'draft' means indicative pricing — finalize via refine before purchasing. 'committed' means firm pricing with inventory reserved until expires_at." ), ] = None total_budget_guidance: Annotated[ TotalBudgetGuidance | None, Field(description='Optional budget guidance for this proposal') ] = NoneBase model for AdCP types with spec-compliant serialization.
Defaults to
extra='ignore'so that unknown fields from newer spec versions are silently dropped rather than causing validation errors. Generated types whose schemas setadditionalProperties: trueoverride this withextra='allow'in their ownmodel_config. Consumers who want strict validation can override withextra='forbid'.Create a new model by parsing and validating input data from keyword arguments.
Raises [
ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.selfis explicitly positional-only to allowselfas a field name.Ancestors
- AdCPBaseModel
- pydantic.main.BaseModel
Class variables
var allocations : list[ProductAllocation]var brief_alignment : str | Nonevar description : str | Nonevar expires_at : pydantic.types.AwareDatetime | Nonevar ext : ExtensionObject | Nonevar forecast : DeliveryForecast | Nonevar insertion_order : InsertionOrder | Nonevar model_configvar name : strvar proposal_id : strvar proposal_status : ProposalStatus | Nonevar total_budget_guidance : TotalBudgetGuidance | None
Inherited members
class Protocol (*args, **kwds)-
Expand source code
class Protocol(str, Enum): """Supported protocols.""" A2A = "a2a" MCP = "mcp"Supported protocols.
Ancestors
- builtins.str
- enum.Enum
Class variables
var A2Avar MCP
class ProvidePerformanceFeedbackRequest (**data: Any)-
Expand source code
class ProvidePerformanceFeedbackRequest(AdCPBaseModel): model_config = ConfigDict( extra='allow', ) context: context_1.ContextObject | None = None creative_id: Annotated[ str | None, Field( description='Specific creative asset (if feedback is creative-specific)', min_length=1 ), ] = None ext: ext_1.ExtensionObject | None = None feedback_source: Annotated[ feedback_source_1.FeedbackSource | None, Field(description='Source of the performance data') ] = feedback_source_1.FeedbackSource.buyer_attribution idempotency_key: Annotated[ str | None, Field( description='Client-generated unique key for this request. Prevents duplicate feedback submissions on retries. MUST be unique per (seller, request) pair to prevent cross-seller correlation. Use a fresh UUID v4 for each request.', max_length=255, min_length=16, ), ] = None measurement_period: Annotated[ datetime_range.DatetimeRange, Field(description='Time period for performance measurement') ] media_buy_id: Annotated[str, Field(description="Seller's media buy identifier", min_length=1)] metric_type: Annotated[ metric_type_1.MetricType | None, Field(description='The business metric being measured') ] = metric_type_1.MetricType.overall_performance package_id: Annotated[ str | None, Field( description='Specific package within the media buy (if feedback is package-specific)', min_length=1, ), ] = None performance_index: Annotated[ float, Field( description='Normalized performance score (0.0 = no value, 1.0 = expected, >1.0 = above expected)', ge=0.0, ), ]Base model for AdCP types with spec-compliant serialization.
Defaults to
extra='ignore'so that unknown fields from newer spec versions are silently dropped rather than causing validation errors. Generated types whose schemas setadditionalProperties: trueoverride this withextra='allow'in their ownmodel_config. Consumers who want strict validation can override withextra='forbid'.Create a new model by parsing and validating input data from keyword arguments.
Raises [
ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.selfis explicitly positional-only to allowselfas a field name.Ancestors
- AdCPBaseModel
- pydantic.main.BaseModel
Class variables
var context : ContextObject | Nonevar creative_id : str | Nonevar ext : ExtensionObject | Nonevar feedback_source : FeedbackSource | Nonevar idempotency_key : str | Nonevar measurement_period : DatetimeRangevar media_buy_id : strvar metric_type : MetricType | Nonevar model_configvar package_id : str | Nonevar performance_index : float
class ProvidePerformanceFeedbackByBuyerRefRequest (**data: Any)-
Expand source code
class ProvidePerformanceFeedbackRequest(AdCPBaseModel): model_config = ConfigDict( extra='allow', ) context: context_1.ContextObject | None = None creative_id: Annotated[ str | None, Field( description='Specific creative asset (if feedback is creative-specific)', min_length=1 ), ] = None ext: ext_1.ExtensionObject | None = None feedback_source: Annotated[ feedback_source_1.FeedbackSource | None, Field(description='Source of the performance data') ] = feedback_source_1.FeedbackSource.buyer_attribution idempotency_key: Annotated[ str | None, Field( description='Client-generated unique key for this request. Prevents duplicate feedback submissions on retries. MUST be unique per (seller, request) pair to prevent cross-seller correlation. Use a fresh UUID v4 for each request.', max_length=255, min_length=16, ), ] = None measurement_period: Annotated[ datetime_range.DatetimeRange, Field(description='Time period for performance measurement') ] media_buy_id: Annotated[str, Field(description="Seller's media buy identifier", min_length=1)] metric_type: Annotated[ metric_type_1.MetricType | None, Field(description='The business metric being measured') ] = metric_type_1.MetricType.overall_performance package_id: Annotated[ str | None, Field( description='Specific package within the media buy (if feedback is package-specific)', min_length=1, ), ] = None performance_index: Annotated[ float, Field( description='Normalized performance score (0.0 = no value, 1.0 = expected, >1.0 = above expected)', ge=0.0, ), ]Base model for AdCP types with spec-compliant serialization.
Defaults to
extra='ignore'so that unknown fields from newer spec versions are silently dropped rather than causing validation errors. Generated types whose schemas setadditionalProperties: trueoverride this withextra='allow'in their ownmodel_config. Consumers who want strict validation can override withextra='forbid'.Create a new model by parsing and validating input data from keyword arguments.
Raises [
ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.selfis explicitly positional-only to allowselfas a field name.Ancestors
- AdCPBaseModel
- pydantic.main.BaseModel
Class variables
var context : ContextObject | Nonevar creative_id : str | Nonevar ext : ExtensionObject | Nonevar feedback_source : FeedbackSource | Nonevar idempotency_key : str | Nonevar measurement_period : DatetimeRangevar media_buy_id : strvar metric_type : MetricType | Nonevar model_configvar package_id : str | Nonevar performance_index : float
class ProvidePerformanceFeedbackByMediaBuyRequest (**data: Any)-
Expand source code
class ProvidePerformanceFeedbackRequest(AdCPBaseModel): model_config = ConfigDict( extra='allow', ) context: context_1.ContextObject | None = None creative_id: Annotated[ str | None, Field( description='Specific creative asset (if feedback is creative-specific)', min_length=1 ), ] = None ext: ext_1.ExtensionObject | None = None feedback_source: Annotated[ feedback_source_1.FeedbackSource | None, Field(description='Source of the performance data') ] = feedback_source_1.FeedbackSource.buyer_attribution idempotency_key: Annotated[ str | None, Field( description='Client-generated unique key for this request. Prevents duplicate feedback submissions on retries. MUST be unique per (seller, request) pair to prevent cross-seller correlation. Use a fresh UUID v4 for each request.', max_length=255, min_length=16, ), ] = None measurement_period: Annotated[ datetime_range.DatetimeRange, Field(description='Time period for performance measurement') ] media_buy_id: Annotated[str, Field(description="Seller's media buy identifier", min_length=1)] metric_type: Annotated[ metric_type_1.MetricType | None, Field(description='The business metric being measured') ] = metric_type_1.MetricType.overall_performance package_id: Annotated[ str | None, Field( description='Specific package within the media buy (if feedback is package-specific)', min_length=1, ), ] = None performance_index: Annotated[ float, Field( description='Normalized performance score (0.0 = no value, 1.0 = expected, >1.0 = above expected)', ge=0.0, ), ]Base model for AdCP types with spec-compliant serialization.
Defaults to
extra='ignore'so that unknown fields from newer spec versions are silently dropped rather than causing validation errors. Generated types whose schemas setadditionalProperties: trueoverride this withextra='allow'in their ownmodel_config. Consumers who want strict validation can override withextra='forbid'.Create a new model by parsing and validating input data from keyword arguments.
Raises [
ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.selfis explicitly positional-only to allowselfas a field name.Ancestors
- AdCPBaseModel
- pydantic.main.BaseModel
Class variables
var context : ContextObject | Nonevar creative_id : str | Nonevar ext : ExtensionObject | Nonevar feedback_source : FeedbackSource | Nonevar idempotency_key : str | Nonevar measurement_period : DatetimeRangevar media_buy_id : strvar metric_type : MetricType | Nonevar model_configvar package_id : str | Nonevar performance_index : float
Inherited members
class ProvidePerformanceFeedbackSuccessResponse (**data: Any)-
Expand source code
class ProvidePerformanceFeedbackResponse1(AdCPBaseModel): model_config = ConfigDict( extra='allow', ) context: context_1.ContextObject | None = None ext: ext_1.ExtensionObject | None = None sandbox: Annotated[ bool | None, Field(description='When true, this response contains simulated data from sandbox mode.'), ] = None success: Annotated[ Literal[True], Field(description='Whether the performance feedback was successfully received'), ]Base model for AdCP types with spec-compliant serialization.
Defaults to
extra='ignore'so that unknown fields from newer spec versions are silently dropped rather than causing validation errors. Generated types whose schemas setadditionalProperties: trueoverride this withextra='allow'in their ownmodel_config. Consumers who want strict validation can override withextra='forbid'.Create a new model by parsing and validating input data from keyword arguments.
Raises [
ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.selfis explicitly positional-only to allowselfas a field name.Ancestors
- AdCPBaseModel
- pydantic.main.BaseModel
Class variables
var context : ContextObject | Nonevar ext : ExtensionObject | Nonevar model_configvar sandbox : bool | Nonevar success : Literal[True]
Inherited members
class ProvidePerformanceFeedbackErrorResponse (**data: Any)-
Expand source code
class ProvidePerformanceFeedbackResponse2(AdCPBaseModel): model_config = ConfigDict( extra='allow', ) context: context_1.ContextObject | None = None errors: Annotated[ list[error.Error], Field( description='Array of errors explaining why feedback was rejected (e.g., invalid measurement period, missing campaign data)', min_length=1, ), ] ext: ext_1.ExtensionObject | None = NoneBase model for AdCP types with spec-compliant serialization.
Defaults to
extra='ignore'so that unknown fields from newer spec versions are silently dropped rather than causing validation errors. Generated types whose schemas setadditionalProperties: trueoverride this withextra='allow'in their ownmodel_config. Consumers who want strict validation can override withextra='forbid'.Create a new model by parsing and validating input data from keyword arguments.
Raises [
ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.selfis explicitly positional-only to allowselfas a field name.Ancestors
- AdCPBaseModel
- pydantic.main.BaseModel
Class variables
var context : ContextObject | Nonevar errors : list[Error]var ext : ExtensionObject | Nonevar model_config
Inherited members
class PublisherPropertiesAll (**data: Any)-
Expand source code
class PublisherPropertySelector1(AdCPBaseModel): model_config = ConfigDict( extra='allow', ) publisher_domain: Annotated[ str, Field( description="Domain where publisher's adagents.json is hosted (e.g., 'cnn.com')", pattern='^[a-z0-9]([a-z0-9-]*[a-z0-9])?(\\.[a-z0-9]([a-z0-9-]*[a-z0-9])?)*$', ), ] selection_type: Annotated[ Literal['all'], Field( description='Discriminator indicating all properties from this publisher are included' ), ]Base model for AdCP types with spec-compliant serialization.
Defaults to
extra='ignore'so that unknown fields from newer spec versions are silently dropped rather than causing validation errors. Generated types whose schemas setadditionalProperties: trueoverride this withextra='allow'in their ownmodel_config. Consumers who want strict validation can override withextra='forbid'.Create a new model by parsing and validating input data from keyword arguments.
Raises [
ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.selfis explicitly positional-only to allowselfas a field name.Ancestors
- AdCPBaseModel
- pydantic.main.BaseModel
Class variables
var model_configvar publisher_domain : strvar selection_type : Literal['all']
Inherited members
class PublisherPropertiesById (**data: Any)-
Expand source code
class PublisherPropertySelector2(AdCPBaseModel): model_config = ConfigDict( extra='allow', ) property_ids: Annotated[ list[property_id.PropertyId], Field(description="Specific property IDs from the publisher's adagents.json", min_length=1), ] publisher_domain: Annotated[ str, Field( description="Domain where publisher's adagents.json is hosted (e.g., 'cnn.com')", pattern='^[a-z0-9]([a-z0-9-]*[a-z0-9])?(\\.[a-z0-9]([a-z0-9-]*[a-z0-9])?)*$', ), ] selection_type: Annotated[ Literal['by_id'], Field(description='Discriminator indicating selection by specific property IDs'), ]Base model for AdCP types with spec-compliant serialization.
Defaults to
extra='ignore'so that unknown fields from newer spec versions are silently dropped rather than causing validation errors. Generated types whose schemas setadditionalProperties: trueoverride this withextra='allow'in their ownmodel_config. Consumers who want strict validation can override withextra='forbid'.Create a new model by parsing and validating input data from keyword arguments.
Raises [
ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.selfis explicitly positional-only to allowselfas a field name.Ancestors
- AdCPBaseModel
- pydantic.main.BaseModel
Class variables
var model_configvar property_ids : list[PropertyId]var publisher_domain : strvar selection_type : Literal['by_id']
Inherited members
class PublisherPropertiesByTag (**data: Any)-
Expand source code
class PublisherPropertySelector3(AdCPBaseModel): model_config = ConfigDict( extra='allow', ) property_tags: Annotated[ list[property_tag.PropertyTag], Field( description="Property tags from the publisher's adagents.json. Selector covers all properties with these tags", min_length=1, ), ] publisher_domain: Annotated[ str, Field( description="Domain where publisher's adagents.json is hosted (e.g., 'cnn.com')", pattern='^[a-z0-9]([a-z0-9-]*[a-z0-9])?(\\.[a-z0-9]([a-z0-9-]*[a-z0-9])?)*$', ), ] selection_type: Annotated[ Literal['by_tag'], Field(description='Discriminator indicating selection by property tags') ]Base model for AdCP types with spec-compliant serialization.
Defaults to
extra='ignore'so that unknown fields from newer spec versions are silently dropped rather than causing validation errors. Generated types whose schemas setadditionalProperties: trueoverride this withextra='allow'in their ownmodel_config. Consumers who want strict validation can override withextra='forbid'.Create a new model by parsing and validating input data from keyword arguments.
Raises [
ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.selfis explicitly positional-only to allowselfas a field name.Ancestors
- AdCPBaseModel
- pydantic.main.BaseModel
Class variables
var model_configvar publisher_domain : strvar selection_type : Literal['by_tag']
Inherited members
class PushNotificationConfig (**data: Any)-
Expand source code
class PushNotificationConfig(AdCPBaseModel): authentication: Annotated[ Authentication, Field(description='Authentication configuration for webhook delivery (A2A-compatible)'), ] token: Annotated[ str | None, Field( description='Optional client-provided token for webhook validation. Echoed back in webhook payload to validate request authenticity.', min_length=16, ), ] = None url: Annotated[AnyUrl, Field(description='Webhook endpoint URL for task status notifications')]Base model for AdCP types with spec-compliant serialization.
Defaults to
extra='ignore'so that unknown fields from newer spec versions are silently dropped rather than causing validation errors. Generated types whose schemas setadditionalProperties: trueoverride this withextra='allow'in their ownmodel_config. Consumers who want strict validation can override withextra='forbid'.Create a new model by parsing and validating input data from keyword arguments.
Raises [
ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.selfis explicitly positional-only to allowselfas a field name.Ancestors
- AdCPBaseModel
- pydantic.main.BaseModel
Class variables
var authentication : Authenticationvar model_configvar token : str | Nonevar url : pydantic.networks.AnyUrl
Inherited members
class Refine (**data: Any)-
Expand source code
class Refine(AdCPBaseModel): model_config = ConfigDict( extra='forbid', ) ask: Annotated[ str, Field( description="What the buyer is asking for at the request level (e.g., 'more video options and less display', 'suggest how to combine these products').", min_length=1, ), ] scope: Annotated[ Literal['request'], Field( description='Change scoped to the overall request — direction for the selection as a whole.' ), ]Base model for AdCP types with spec-compliant serialization.
Defaults to
extra='ignore'so that unknown fields from newer spec versions are silently dropped rather than causing validation errors. Generated types whose schemas setadditionalProperties: trueoverride this withextra='allow'in their ownmodel_config. Consumers who want strict validation can override withextra='forbid'.Create a new model by parsing and validating input data from keyword arguments.
Raises [
ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.selfis explicitly positional-only to allowselfas a field name.Ancestors
- AdCPBaseModel
- pydantic.main.BaseModel
Class variables
var ask : strvar model_configvar scope : Literal['request']
Inherited members
class RegistryClient (base_url: str = 'https://agenticadvertising.org',
timeout: float = 10.0,
client: httpx.AsyncClient | None = None,
user_agent: str = 'adcp-client-python')-
Expand source code
class RegistryClient: """Client for the AdCP registry API. Provides brand, property, and member lookups against the central AdCP registry. Args: base_url: Registry API base URL. timeout: Request timeout in seconds. client: Optional httpx.AsyncClient for connection pooling. If provided, caller is responsible for client lifecycle. user_agent: User-Agent header for requests. """ def __init__( self, base_url: str = DEFAULT_REGISTRY_URL, timeout: float = 10.0, client: httpx.AsyncClient | None = None, user_agent: str = "adcp-client-python", ): self._base_url = base_url.rstrip("/") self._timeout = timeout self._external_client = client self._owned_client: httpx.AsyncClient | None = None self._user_agent = user_agent async def _get_client(self) -> httpx.AsyncClient: """Get or create httpx client.""" if self._external_client is not None: return self._external_client if self._owned_client is None: self._owned_client = httpx.AsyncClient( limits=httpx.Limits( max_keepalive_connections=10, max_connections=20, ), ) return self._owned_client async def close(self) -> None: """Close owned HTTP client. No-op if using external client.""" if self._owned_client is not None: await self._owned_client.aclose() self._owned_client = None async def __aenter__(self) -> RegistryClient: return self async def __aexit__(self, *args: Any) -> None: await self.close() async def _request( self, method: str, path: str, *, params: dict[str, Any] | None = None, json_body: dict[str, Any] | None = None, auth_token: str | None = None, operation: str = "Registry request", allow_404: bool = False, expected_status: int | set[int] = 200, ) -> httpx.Response | None: """Execute a registry API request with standard error handling. Returns None if allow_404=True and the server returns 404. Raises RegistryError for all other non-expected status codes. """ client = await self._get_client() headers: dict[str, str] = {"User-Agent": self._user_agent} if auth_token is not None: headers["Authorization"] = f"Bearer {auth_token}" expected = {expected_status} if isinstance(expected_status, int) else expected_status try: if method == "GET": response = await client.get( f"{self._base_url}{path}", params=params, headers=headers, timeout=self._timeout, ) else: response = await client.post( f"{self._base_url}{path}", json=json_body, headers=headers, timeout=self._timeout, ) if allow_404 and response.status_code == 404: return None if response.status_code not in expected: raise RegistryError( f"{operation} failed: HTTP {response.status_code}", status_code=response.status_code, ) return response except RegistryError: raise except httpx.TimeoutException as e: raise RegistryError( f"{operation} timed out after {self._timeout}s" ) from e except httpx.HTTPError as e: raise RegistryError(f"{operation} failed: {e}") from e async def _request_ok( self, method: str, path: str, **kwargs: Any, ) -> httpx.Response: """Like _request but guarantees a non-None response. Use for endpoints that never return 404-as-None. """ resp = await self._request(method, path, **kwargs) if resp is None: raise RegistryError( f"{kwargs.get('operation', 'Request')} failed: unexpected empty response" ) return resp @staticmethod def _parse(model_cls: type[_T], data: Any, operation: str) -> _T: """Validate data against a Pydantic model, wrapping errors.""" try: return model_cls.model_validate(data) except (ValidationError, ValueError) as e: raise RegistryError( f"{operation} failed: invalid response: {e}" ) from e async def lookup_brand(self, domain: str) -> ResolvedBrand | None: """Resolve a domain to its brand identity. Works for any domain — brand houses, sub-brands, and operators (agencies, DSPs) are all brands in the registry. Args: domain: Domain to resolve (e.g., "nike.com", "wpp.com"). Returns: ResolvedBrand if found, None if not in the registry. Raises: RegistryError: On HTTP or parsing errors. Example: brand = await registry.lookup_brand(request.brand.domain) """ client = await self._get_client() try: response = await client.get( f"{self._base_url}/api/brands/resolve", params={"domain": domain}, headers={"User-Agent": self._user_agent}, timeout=self._timeout, ) if response.status_code == 404: return None if response.status_code != 200: raise RegistryError( f"Brand lookup failed: HTTP {response.status_code}", status_code=response.status_code, ) data = response.json() if data is None: return None return ResolvedBrand.model_validate(data) except RegistryError: raise except httpx.TimeoutException as e: raise RegistryError(f"Brand lookup timed out after {self._timeout}s") from e except httpx.HTTPError as e: raise RegistryError(f"Brand lookup failed: {e}") from e except (ValidationError, ValueError) as e: raise RegistryError(f"Brand lookup failed: invalid response: {e}") from e async def lookup_brands(self, domains: list[str]) -> dict[str, ResolvedBrand | None]: """Bulk resolve domains to brand identities. Automatically chunks requests exceeding 100 domains. Args: domains: List of domains to resolve. Returns: Dict mapping each domain to its ResolvedBrand, or None if not found. Raises: RegistryError: On HTTP or parsing errors. """ if not domains: return {} chunks = [ domains[i : i + MAX_BULK_DOMAINS] for i in range(0, len(domains), MAX_BULK_DOMAINS) ] chunk_results = await asyncio.gather( *[self._lookup_brands_chunk(chunk) for chunk in chunks] ) merged: dict[str, ResolvedBrand | None] = {} for result in chunk_results: merged.update(result) return merged async def _lookup_brands_chunk(self, domains: list[str]) -> dict[str, ResolvedBrand | None]: """Resolve a single chunk of brand domains (max 100).""" client = await self._get_client() try: response = await client.post( f"{self._base_url}/api/brands/resolve/bulk", json={"domains": domains}, headers={"User-Agent": self._user_agent}, timeout=self._timeout, ) if response.status_code != 200: raise RegistryError( f"Bulk brand lookup failed: HTTP {response.status_code}", status_code=response.status_code, ) data = response.json() results_raw = data.get("results", {}) results: dict[str, ResolvedBrand | None] = {d: None for d in domains} for domain, brand_data in results_raw.items(): if brand_data is not None: results[domain] = ResolvedBrand.model_validate(brand_data) return results except RegistryError: raise except httpx.TimeoutException as e: raise RegistryError(f"Bulk brand lookup timed out after {self._timeout}s") from e except httpx.HTTPError as e: raise RegistryError(f"Bulk brand lookup failed: {e}") from e except (ValidationError, ValueError) as e: raise RegistryError(f"Bulk brand lookup failed: invalid response: {e}") from e async def lookup_property(self, domain: str) -> ResolvedProperty | None: """Resolve a publisher domain to its property info. Args: domain: Publisher domain to resolve (e.g., "nytimes.com"). Returns: ResolvedProperty if found, None if the domain is not in the registry. Raises: RegistryError: On HTTP or parsing errors. """ client = await self._get_client() try: response = await client.get( f"{self._base_url}/api/properties/resolve", params={"domain": domain}, headers={"User-Agent": self._user_agent}, timeout=self._timeout, ) if response.status_code == 404: return None if response.status_code != 200: raise RegistryError( f"Property lookup failed: HTTP {response.status_code}", status_code=response.status_code, ) data = response.json() if data is None: return None return ResolvedProperty.model_validate(data) except RegistryError: raise except httpx.TimeoutException as e: raise RegistryError(f"Property lookup timed out after {self._timeout}s") from e except httpx.HTTPError as e: raise RegistryError(f"Property lookup failed: {e}") from e except (ValidationError, ValueError) as e: raise RegistryError(f"Property lookup failed: invalid response: {e}") from e async def lookup_properties(self, domains: list[str]) -> dict[str, ResolvedProperty | None]: """Bulk resolve publisher domains to property info. Automatically chunks requests exceeding 100 domains. Args: domains: List of publisher domains to resolve. Returns: Dict mapping each domain to its ResolvedProperty, or None if not found. Raises: RegistryError: On HTTP or parsing errors. """ if not domains: return {} chunks = [ domains[i : i + MAX_BULK_DOMAINS] for i in range(0, len(domains), MAX_BULK_DOMAINS) ] chunk_results = await asyncio.gather( *[self._lookup_properties_chunk(chunk) for chunk in chunks] ) merged: dict[str, ResolvedProperty | None] = {} for result in chunk_results: merged.update(result) return merged async def _lookup_properties_chunk( self, domains: list[str] ) -> dict[str, ResolvedProperty | None]: """Resolve a single chunk of property domains (max 100).""" client = await self._get_client() try: response = await client.post( f"{self._base_url}/api/properties/resolve/bulk", json={"domains": domains}, headers={"User-Agent": self._user_agent}, timeout=self._timeout, ) if response.status_code != 200: raise RegistryError( f"Bulk property lookup failed: HTTP {response.status_code}", status_code=response.status_code, ) data = response.json() results_raw = data.get("results", {}) results: dict[str, ResolvedProperty | None] = {d: None for d in domains} for domain, prop_data in results_raw.items(): if prop_data is not None: results[domain] = ResolvedProperty.model_validate(prop_data) return results except RegistryError: raise except httpx.TimeoutException as e: raise RegistryError(f"Bulk property lookup timed out after {self._timeout}s") from e except httpx.HTTPError as e: raise RegistryError(f"Bulk property lookup failed: {e}") from e except (ValidationError, ValueError) as e: raise RegistryError(f"Bulk property lookup failed: invalid response: {e}") from e async def list_members(self, limit: int = 100) -> list[Member]: """List organizations registered in the AAO member directory. Args: limit: Maximum number of members to return. Returns: List of Member objects. Raises: RegistryError: On HTTP or parsing errors. """ if limit < 1: raise ValueError(f"limit must be at least 1, got {limit}") client = await self._get_client() try: response = await client.get( f"{self._base_url}/api/members", params={"limit": limit}, headers={"User-Agent": self._user_agent}, timeout=self._timeout, ) if response.status_code != 200: raise RegistryError( f"Member list failed: HTTP {response.status_code}", status_code=response.status_code, ) data = response.json() return [Member.model_validate(m) for m in data.get("members", [])] except RegistryError: raise except httpx.TimeoutException as e: raise RegistryError(f"Member list timed out after {self._timeout}s") from e except httpx.HTTPError as e: raise RegistryError(f"Member list failed: {e}") from e except (ValidationError, ValueError) as e: raise RegistryError(f"Member list failed: invalid response: {e}") from e async def get_member(self, slug: str) -> Member | None: """Get a single AAO member by their slug. Args: slug: Member slug (e.g., "adgentek"). Returns: Member if found, None if not in the registry. Raises: RegistryError: On HTTP or parsing errors. ValueError: If slug contains path-traversal characters. """ if not slug or not re.fullmatch(r"[a-zA-Z0-9_-]+", slug): raise ValueError(f"Invalid member slug: {slug!r}") client = await self._get_client() try: response = await client.get( f"{self._base_url}/api/members/{slug}", headers={"User-Agent": self._user_agent}, timeout=self._timeout, ) if response.status_code == 404: return None if response.status_code != 200: raise RegistryError( f"Member lookup failed: HTTP {response.status_code}", status_code=response.status_code, ) data = response.json() if data is None: return None return Member.model_validate(data) except RegistryError: raise except httpx.TimeoutException as e: raise RegistryError(f"Member lookup timed out after {self._timeout}s") from e except httpx.HTTPError as e: raise RegistryError(f"Member lookup failed: {e}") from e except (ValidationError, ValueError) as e: raise RegistryError(f"Member lookup failed: invalid response: {e}") from e # ======================================================================== # Policy Registry Operations # ======================================================================== async def list_policies( self, search: str | None = None, category: str | None = None, enforcement: str | None = None, jurisdiction: str | None = None, vertical: str | None = None, domain: str | None = None, limit: int = 20, offset: int = 0, ) -> list[PolicySummary]: """List governance policies with optional filtering. Args: search: Full-text search on policy name and description. category: Filter by category ("regulation" or "standard"). enforcement: Filter by enforcement level ("must", "should", "may"). jurisdiction: Filter by jurisdiction with region alias matching. vertical: Filter by industry vertical. domain: Filter by governance domain ("campaign", "creative", etc.). limit: Results per page (default 20, max 1000). offset: Pagination offset. Returns: List of PolicySummary objects. Raises: RegistryError: On HTTP or parsing errors. """ client = await self._get_client() params: dict[str, str | int] = {"limit": limit, "offset": offset} if search is not None: params["search"] = search if category is not None: params["category"] = category if enforcement is not None: params["enforcement"] = enforcement if jurisdiction is not None: params["jurisdiction"] = jurisdiction if vertical is not None: params["vertical"] = vertical if domain is not None: params["domain"] = domain try: response = await client.get( f"{self._base_url}/api/policies/registry", params=params, headers={"User-Agent": self._user_agent}, timeout=self._timeout, ) if response.status_code != 200: raise RegistryError( f"Policy list failed: HTTP {response.status_code}", status_code=response.status_code, ) data = response.json() return [PolicySummary.model_validate(p) for p in data.get("policies", [])] except RegistryError: raise except httpx.TimeoutException as e: raise RegistryError(f"Policy list timed out after {self._timeout}s") from e except httpx.HTTPError as e: raise RegistryError(f"Policy list failed: {e}") from e except (ValidationError, ValueError) as e: raise RegistryError(f"Policy list failed: invalid response: {e}") from e async def resolve_policy( self, policy_id: str, version: str | None = None, ) -> Policy | None: """Resolve a single policy by ID. Args: policy_id: Policy identifier (e.g., "gdpr_consent"). version: Optional version pin; returns None if current version differs. Returns: Policy if found, None if not in the registry. Raises: RegistryError: On HTTP or parsing errors. """ client = await self._get_client() params: dict[str, str] = {"policy_id": policy_id} if version is not None: params["version"] = version try: response = await client.get( f"{self._base_url}/api/policies/resolve", params=params, headers={"User-Agent": self._user_agent}, timeout=self._timeout, ) if response.status_code == 404: return None if response.status_code != 200: raise RegistryError( f"Policy resolve failed: HTTP {response.status_code}", status_code=response.status_code, ) data = response.json() if data is None: return None return Policy.model_validate(data) except RegistryError: raise except httpx.TimeoutException as e: raise RegistryError(f"Policy resolve timed out after {self._timeout}s") from e except httpx.HTTPError as e: raise RegistryError(f"Policy resolve failed: {e}") from e except (ValidationError, ValueError) as e: raise RegistryError(f"Policy resolve failed: invalid response: {e}") from e async def resolve_policies( self, policy_ids: list[str], ) -> dict[str, Policy | None]: """Bulk resolve policies by ID. Automatically chunks requests exceeding 100 policy IDs. Args: policy_ids: List of policy identifiers to resolve. Returns: Dict mapping each policy_id to its Policy, or None if not found. Raises: RegistryError: On HTTP or parsing errors. """ if not policy_ids: return {} chunks = [ policy_ids[i : i + MAX_BULK_POLICIES] for i in range(0, len(policy_ids), MAX_BULK_POLICIES) ] chunk_results = await asyncio.gather( *[self._resolve_policies_chunk(chunk) for chunk in chunks] ) merged: dict[str, Policy | None] = {} for result in chunk_results: merged.update(result) return merged async def _resolve_policies_chunk( self, policy_ids: list[str] ) -> dict[str, Policy | None]: """Resolve a single chunk of policy IDs (max 100).""" client = await self._get_client() try: response = await client.post( f"{self._base_url}/api/policies/resolve/bulk", json={"policy_ids": policy_ids}, headers={"User-Agent": self._user_agent}, timeout=self._timeout, ) if response.status_code != 200: raise RegistryError( f"Bulk policy resolve failed: HTTP {response.status_code}", status_code=response.status_code, ) data = response.json() results_raw = data.get("results", {}) results: dict[str, Policy | None] = {pid: None for pid in policy_ids} for pid, policy_data in results_raw.items(): if policy_data is not None: results[pid] = Policy.model_validate(policy_data) return results except RegistryError: raise except httpx.TimeoutException as e: raise RegistryError( f"Bulk policy resolve timed out after {self._timeout}s" ) from e except httpx.HTTPError as e: raise RegistryError(f"Bulk policy resolve failed: {e}") from e except (ValidationError, ValueError) as e: raise RegistryError( f"Bulk policy resolve failed: invalid response: {e}" ) from e async def policy_history( self, policy_id: str, limit: int = 20, offset: int = 0, ) -> PolicyHistory | None: """Retrieve edit history for a policy. Args: policy_id: Policy identifier. limit: Maximum revisions to return (default 20, max 100). offset: Pagination offset. Returns: PolicyHistory if found, None if the policy doesn't exist. Raises: RegistryError: On HTTP or parsing errors. """ client = await self._get_client() try: response = await client.get( f"{self._base_url}/api/policies/history", params={"policy_id": policy_id, "limit": limit, "offset": offset}, headers={"User-Agent": self._user_agent}, timeout=self._timeout, ) if response.status_code == 404: return None if response.status_code != 200: raise RegistryError( f"Policy history failed: HTTP {response.status_code}", status_code=response.status_code, ) data = response.json() if data is None: return None return PolicyHistory.model_validate(data) except RegistryError: raise except httpx.TimeoutException as e: raise RegistryError( f"Policy history timed out after {self._timeout}s" ) from e except httpx.HTTPError as e: raise RegistryError(f"Policy history failed: {e}") from e except (ValidationError, ValueError) as e: raise RegistryError( f"Policy history failed: invalid response: {e}" ) from e async def save_policy( self, policy_id: str, version: str, name: str, category: str, enforcement: str, policy: str, *, auth_token: str, description: str | None = None, jurisdictions: list[str] | None = None, region_aliases: dict[str, list[str]] | None = None, verticals: list[str] | None = None, channels: list[str] | None = None, effective_date: str | None = None, sunset_date: str | None = None, governance_domains: list[str] | None = None, source_url: str | None = None, source_name: str | None = None, guidance: str | None = None, exemplars: dict[str, Any] | None = None, ext: dict[str, Any] | None = None, ) -> dict[str, Any]: """Create or update a community-contributed policy. Requires authentication. Cannot edit registry-sourced or pending policies. Args: policy_id: Policy identifier (lowercase alphanumeric with underscores). version: Semantic version string. name: Human-readable policy name. category: "regulation" or "standard". enforcement: "must", "should", or "may". policy: Natural language policy text. auth_token: API key for authentication. description: Policy description. jurisdictions: ISO jurisdiction codes. region_aliases: Region alias mappings (e.g., {"EU": ["DE", "FR"]}). verticals: Industry verticals. channels: Media channels. effective_date: ISO 8601 date when enforcement begins. sunset_date: ISO 8601 date when enforcement ends. governance_domains: Applicable domains ("campaign", "creative", etc.). source_url: URL of the source regulation/standard. source_name: Name of the source. guidance: Implementation guidance text. exemplars: Pass/fail calibration scenarios. ext: Extension data. Returns: Dict with success, message, policy_id, and revision_number. Raises: RegistryError: On HTTP or parsing errors (400, 401, 409, 429). """ client = await self._get_client() body: dict[str, Any] = { "policy_id": policy_id, "version": version, "name": name, "category": category, "enforcement": enforcement, "policy": policy, } for key, value in [ ("description", description), ("jurisdictions", jurisdictions), ("region_aliases", region_aliases), ("verticals", verticals), ("channels", channels), ("effective_date", effective_date), ("sunset_date", sunset_date), ("governance_domains", governance_domains), ("source_url", source_url), ("source_name", source_name), ("guidance", guidance), ("exemplars", exemplars), ("ext", ext), ]: if value is not None: body[key] = value try: response = await client.post( f"{self._base_url}/api/policies/save", json=body, headers={ "User-Agent": self._user_agent, "Authorization": f"Bearer {auth_token}", }, timeout=self._timeout, ) if response.status_code != 200: raise RegistryError( f"Policy save failed: HTTP {response.status_code}", status_code=response.status_code, ) result: dict[str, Any] = response.json() return result except RegistryError: raise except httpx.TimeoutException as e: raise RegistryError( f"Policy save timed out after {self._timeout}s" ) from e except httpx.HTTPError as e: raise RegistryError(f"Policy save failed: {e}") from e # ======================================================================== # Brand Registry Operations # ======================================================================== async def get_brand_json( self, domain: str, *, fresh: bool = False ) -> dict[str, Any] | None: """Fetch raw brand.json for a domain.""" params: dict[str, Any] = {"domain": domain} if fresh: params["fresh"] = "true" resp = await self._request( "GET", "/api/brands/brand-json", params=params, allow_404=True, operation="Brand JSON fetch", ) if resp is None: return None return cast(dict[str, Any], resp.json()) async def save_brand( self, domain: str, brand_name: str, *, auth_token: str, brand_manifest: dict[str, Any] | None = None, ) -> dict[str, Any]: """Save or update a brand in the registry (auth required).""" body: dict[str, Any] = {"domain": domain, "brand_name": brand_name} if brand_manifest is not None: body["brand_manifest"] = brand_manifest resp = await self._request_ok( "POST", "/api/brands/save", json_body=body, auth_token=auth_token, operation="Brand save", ) return cast(dict[str, Any], resp.json()) async def list_brands( self, search: str | None = None, limit: int = 100, offset: int = 0, ) -> list[BrandRegistryItem]: """List brands in the registry.""" params: dict[str, Any] = {"limit": limit, "offset": offset} if search is not None: params["search"] = search resp = await self._request_ok( "GET", "/api/brands/registry", params=params, operation="Brand list", ) data = resp.json() return [self._parse(BrandRegistryItem, b, "Brand list") for b in data.get("brands", [])] async def brand_history( self, domain: str, limit: int = 20, offset: int = 0, ) -> BrandActivity | None: """Get edit history for a brand.""" resp = await self._request( "GET", "/api/brands/history", params={"domain": domain, "limit": limit, "offset": offset}, allow_404=True, operation="Brand history", ) if resp is None: return None return self._parse(BrandActivity, resp.json(), "Brand history") async def enrich_brand(self, domain: str) -> dict[str, Any]: """Enrich brand data using Brandfetch.""" resp = await self._request_ok( "GET", "/api/brands/enrich", params={"domain": domain}, operation="Brand enrich", ) return cast(dict[str, Any], resp.json()) # ======================================================================== # Property Registry Operations # ======================================================================== async def list_properties( self, search: str | None = None, limit: int = 100, offset: int = 0, ) -> list[PropertyRegistryItem]: """List properties in the registry.""" params: dict[str, Any] = {"limit": limit, "offset": offset} if search is not None: params["search"] = search resp = await self._request_ok( "GET", "/api/properties/registry", params=params, operation="Property list", ) data = resp.json() return [ self._parse(PropertyRegistryItem, p, "Property list") for p in data.get("properties", []) ] async def validate_property(self, domain: str) -> ValidationResult: """Validate a domain's adagents.json configuration.""" resp = await self._request_ok( "GET", "/api/properties/validate", params={"domain": domain}, operation="Property validate", ) return self._parse(ValidationResult, resp.json(), "Property validate") async def save_property( self, publisher_domain: str, authorized_agents: list[dict[str, Any]], *, auth_token: str, properties: list[dict[str, Any]] | None = None, contact: dict[str, str] | None = None, ) -> dict[str, Any]: """Save or update a hosted property (auth required).""" body: dict[str, Any] = { "publisher_domain": publisher_domain, "authorized_agents": authorized_agents, } if properties is not None: body["properties"] = properties if contact is not None: body["contact"] = contact resp = await self._request_ok( "POST", "/api/properties/save", json_body=body, auth_token=auth_token, operation="Property save", ) return cast(dict[str, Any], resp.json()) async def property_history( self, domain: str, limit: int = 20, offset: int = 0, ) -> PropertyActivity | None: """Get edit history for a property.""" resp = await self._request( "GET", "/api/properties/history", params={"domain": domain, "limit": limit, "offset": offset}, allow_404=True, operation="Property history", ) if resp is None: return None return self._parse(PropertyActivity, resp.json(), "Property history") async def check_property_list( self, domains: list[str] ) -> dict[str, Any]: """Check publisher domains against the registry.""" resp = await self._request_ok( "POST", "/api/properties/check", json_body={"domains": domains}, operation="Property check", ) return cast(dict[str, Any], resp.json()) async def get_property_check_report( self, report_id: str ) -> dict[str, Any] | None: """Retrieve a property check report by ID.""" resp = await self._request( "GET", f"/api/properties/check/{url_quote(report_id, safe='')}", allow_404=True, operation="Property check report", ) if resp is None: return None return cast(dict[str, Any], resp.json()) # ======================================================================== # Agent Discovery # ======================================================================== async def list_agents( self, *, type: str | None = None, health: bool = False, capabilities: bool = False, properties: bool = False, compliance: bool = False, ) -> list[FederatedAgentWithDetails]: """List registered and discovered agents.""" params: dict[str, Any] = {} if type is not None: params["type"] = type if health: params["health"] = "true" if capabilities: params["capabilities"] = "true" if properties: params["properties"] = "true" if compliance: params["compliance"] = "true" resp = await self._request_ok( "GET", "/api/registry/agents", params=params, operation="Agent list", ) data = resp.json() return [ self._parse(FederatedAgentWithDetails, a, "Agent list") for a in data.get("agents", []) ] async def list_publishers(self) -> list[FederatedPublisher]: """List publishers in the registry.""" resp = await self._request_ok( "GET", "/api/registry/publishers", operation="Publisher list", ) data = resp.json() return [ self._parse(FederatedPublisher, p, "Publisher list") for p in data.get("publishers", []) ] async def get_registry_stats(self) -> dict[str, Any]: """Get aggregate registry statistics.""" resp = await self._request_ok( "GET", "/api/registry/stats", operation="Registry stats", ) return cast(dict[str, Any], resp.json()) async def search_agents( self, *, auth_token: str, channels: str | None = None, property_types: str | None = None, markets: str | None = None, categories: str | None = None, tags: str | None = None, delivery_types: str | None = None, has_tmp: bool | None = None, min_properties: int | None = None, cursor: str | None = None, limit: int = 50, ) -> dict[str, Any]: """Search agents by inventory profile (auth required).""" params: dict[str, Any] = {"limit": limit} for key, val in [ ("channels", channels), ("property_types", property_types), ("markets", markets), ("categories", categories), ("tags", tags), ("delivery_types", delivery_types), ("cursor", cursor), ]: if val is not None: params[key] = val if has_tmp is not None: params["has_tmp"] = str(has_tmp).lower() if min_properties is not None: params["min_properties"] = min_properties resp = await self._request_ok( "GET", "/api/registry/agents/search", params=params, auth_token=auth_token, operation="Agent search", ) return cast(dict[str, Any], resp.json()) async def request_crawl( self, domain: str, *, auth_token: str ) -> dict[str, Any]: """Request a domain re-crawl (auth required).""" resp = await self._request_ok( "POST", "/api/registry/crawl-request", json_body={"domain": domain}, auth_token=auth_token, operation="Crawl request", expected_status={200, 202}, ) return cast(dict[str, Any], resp.json()) # ======================================================================== # Lookups & Authorization # ======================================================================== async def lookup_domain(self, domain: str) -> DomainLookupResult: """Find all agents authorized for a publisher domain.""" resp = await self._request_ok( "GET", f"/api/registry/lookup/domain/{url_quote(domain, safe='')}", operation="Domain lookup", ) return self._parse(DomainLookupResult, resp.json(), "Domain lookup") async def lookup_property_identifier( self, type: str, value: str ) -> dict[str, Any]: """Find agents holding a specific property identifier.""" resp = await self._request_ok( "GET", "/api/registry/lookup/property", params={"type": type, "value": value}, operation="Property identifier lookup", ) return cast(dict[str, Any], resp.json()) async def get_agent_domains(self, agent_url: str) -> dict[str, Any]: """Get all publisher domains and identifiers for an agent.""" encoded = url_quote(agent_url, safe="") resp = await self._request_ok( "GET", f"/api/registry/lookup/agent/{encoded}/domains", operation="Agent domains lookup", ) return cast(dict[str, Any], resp.json()) async def validate_product_authorization( self, agent_url: str, publisher_properties: list[dict[str, Any]], ) -> dict[str, Any]: """Check whether an agent is authorized to sell products.""" resp = await self._request_ok( "POST", "/api/registry/validate/product-authorization", json_body={ "agent_url": agent_url, "publisher_properties": publisher_properties, }, operation="Product authorization", ) return cast(dict[str, Any], resp.json()) async def expand_product_identifiers( self, agent_url: str, publisher_properties: list[dict[str, Any]], ) -> dict[str, Any]: """Expand publisher_properties selectors into concrete identifiers.""" resp = await self._request_ok( "POST", "/api/registry/expand/product-identifiers", json_body={ "agent_url": agent_url, "publisher_properties": publisher_properties, }, operation="Expand product identifiers", ) return cast(dict[str, Any], resp.json()) async def validate_property_authorization( self, agent_url: str, identifier_type: str, identifier_value: str, ) -> dict[str, Any]: """Quick check if a property identifier is authorized for an agent.""" resp = await self._request_ok( "GET", "/api/registry/validate/property-authorization", params={ "agent_url": agent_url, "identifier_type": identifier_type, "identifier_value": identifier_value, }, operation="Property authorization", ) return cast(dict[str, Any], resp.json()) # ======================================================================== # Validation Tools # ======================================================================== async def validate_adagents(self, domain: str) -> dict[str, Any]: """Validate a domain's adagents.json via the registry API.""" resp = await self._request_ok( "POST", "/api/adagents/validate", json_body={"domain": domain}, operation="Adagents validate", ) return cast(dict[str, Any], resp.json()) async def create_adagents( self, authorized_agents: list[dict[str, Any]], *, include_schema: bool = False, include_timestamp: bool = False, properties: list[Any] | None = None, ) -> dict[str, Any]: """Generate a valid adagents.json from authorized agents.""" body: dict[str, Any] = {"authorized_agents": authorized_agents} if include_schema: body["include_schema"] = True if include_timestamp: body["include_timestamp"] = True if properties is not None: body["properties"] = properties resp = await self._request_ok( "POST", "/api/adagents/create", json_body=body, operation="Adagents create", ) return cast(dict[str, Any], resp.json()) # ======================================================================== # Search # ======================================================================== async def api_discovery(self) -> dict[str, Any]: """Get API discovery info (links to entry points and docs).""" resp = await self._request_ok( "GET", "/api", operation="API discovery", ) return cast(dict[str, Any], resp.json()) async def search(self, q: str) -> dict[str, Any]: """Search across brands, publishers, and properties.""" resp = await self._request_ok( "GET", "/api/search", params={"q": q}, operation="Search", ) return cast(dict[str, Any], resp.json()) async def lookup_manifest_ref( self, domain: str, *, type: str | None = None ) -> dict[str, Any]: """Find the best manifest reference for a domain.""" params: dict[str, Any] = {"domain": domain} if type is not None: params["type"] = type resp = await self._request_ok( "GET", "/api/manifest-refs/lookup", params=params, operation="Manifest ref lookup", ) return cast(dict[str, Any], resp.json()) # ======================================================================== # Agent Probing # ======================================================================== async def discover_agent(self, url: str) -> dict[str, Any]: """Probe an agent URL to discover its capabilities.""" resp = await self._request_ok( "GET", "/api/public/discover-agent", params={"url": url}, operation="Agent discovery", ) return cast(dict[str, Any], resp.json()) async def get_agent_formats(self, url: str) -> dict[str, Any]: """Fetch creative formats from an agent.""" resp = await self._request_ok( "GET", "/api/public/agent-formats", params={"url": url}, operation="Agent formats", ) return cast(dict[str, Any], resp.json()) async def get_agent_products(self, url: str) -> dict[str, Any]: """Fetch products from a sales agent.""" resp = await self._request_ok( "GET", "/api/public/agent-products", params={"url": url}, operation="Agent products", ) return cast(dict[str, Any], resp.json()) async def validate_publisher(self, domain: str) -> dict[str, Any]: """Validate a publisher domain's adagents.json and return stats.""" resp = await self._request_ok( "GET", "/api/public/validate-publisher", params={"domain": domain}, operation="Publisher validation", ) return cast(dict[str, Any], resp.json()) # ======================================================================== # Change Feed # ======================================================================== async def get_feed( self, *, auth_token: str, cursor: str | None = None, types: str | None = None, limit: int = 100, ) -> FeedPage: """Poll the registry change feed (auth required). Returns a FeedPage with events, cursor, and has_more. Pass cursor from previous response to resume. """ params: dict[str, Any] = {"limit": limit} if cursor is not None: params["cursor"] = cursor if types is not None: params["types"] = types resp = await self._request_ok( "GET", "/api/registry/feed", params=params, auth_token=auth_token, operation="Feed poll", ) return self._parse(FeedPage, resp.json(), "Feed poll")Client for the AdCP registry API.
Provides brand, property, and member lookups against the central AdCP registry.
Args
base_url- Registry API base URL.
timeout- Request timeout in seconds.
client- Optional httpx.AsyncClient for connection pooling. If provided, caller is responsible for client lifecycle.
user_agent- User-Agent header for requests.
Methods
async def api_discovery(self) ‑> dict[str, typing.Any]-
Expand source code
async def api_discovery(self) -> dict[str, Any]: """Get API discovery info (links to entry points and docs).""" resp = await self._request_ok( "GET", "/api", operation="API discovery", ) return cast(dict[str, Any], resp.json())Get API discovery info (links to entry points and docs).
async def brand_history(self, domain: str, limit: int = 20, offset: int = 0) ‑> BrandActivity | None-
Expand source code
async def brand_history( self, domain: str, limit: int = 20, offset: int = 0, ) -> BrandActivity | None: """Get edit history for a brand.""" resp = await self._request( "GET", "/api/brands/history", params={"domain": domain, "limit": limit, "offset": offset}, allow_404=True, operation="Brand history", ) if resp is None: return None return self._parse(BrandActivity, resp.json(), "Brand history")Get edit history for a brand.
async def check_property_list(self, domains: list[str]) ‑> dict[str, typing.Any]-
Expand source code
async def check_property_list( self, domains: list[str] ) -> dict[str, Any]: """Check publisher domains against the registry.""" resp = await self._request_ok( "POST", "/api/properties/check", json_body={"domains": domains}, operation="Property check", ) return cast(dict[str, Any], resp.json())Check publisher domains against the registry.
async def close(self) ‑> None-
Expand source code
async def close(self) -> None: """Close owned HTTP client. No-op if using external client.""" if self._owned_client is not None: await self._owned_client.aclose() self._owned_client = NoneClose owned HTTP client. No-op if using external client.
async def create_adagents(self,
authorized_agents: list[dict[str, Any]],
*,
include_schema: bool = False,
include_timestamp: bool = False,
properties: list[Any] | None = None) ‑> dict[str, typing.Any]-
Expand source code
async def create_adagents( self, authorized_agents: list[dict[str, Any]], *, include_schema: bool = False, include_timestamp: bool = False, properties: list[Any] | None = None, ) -> dict[str, Any]: """Generate a valid adagents.json from authorized agents.""" body: dict[str, Any] = {"authorized_agents": authorized_agents} if include_schema: body["include_schema"] = True if include_timestamp: body["include_timestamp"] = True if properties is not None: body["properties"] = properties resp = await self._request_ok( "POST", "/api/adagents/create", json_body=body, operation="Adagents create", ) return cast(dict[str, Any], resp.json())Generate a valid adagents.json from authorized agents.
async def discover_agent(self, url: str) ‑> dict[str, typing.Any]-
Expand source code
async def discover_agent(self, url: str) -> dict[str, Any]: """Probe an agent URL to discover its capabilities.""" resp = await self._request_ok( "GET", "/api/public/discover-agent", params={"url": url}, operation="Agent discovery", ) return cast(dict[str, Any], resp.json())Probe an agent URL to discover its capabilities.
async def enrich_brand(self, domain: str) ‑> dict[str, typing.Any]-
Expand source code
async def enrich_brand(self, domain: str) -> dict[str, Any]: """Enrich brand data using Brandfetch.""" resp = await self._request_ok( "GET", "/api/brands/enrich", params={"domain": domain}, operation="Brand enrich", ) return cast(dict[str, Any], resp.json())Enrich brand data using Brandfetch.
async def expand_product_identifiers(self, agent_url: str, publisher_properties: list[dict[str, Any]]) ‑> dict[str, typing.Any]-
Expand source code
async def expand_product_identifiers( self, agent_url: str, publisher_properties: list[dict[str, Any]], ) -> dict[str, Any]: """Expand publisher_properties selectors into concrete identifiers.""" resp = await self._request_ok( "POST", "/api/registry/expand/product-identifiers", json_body={ "agent_url": agent_url, "publisher_properties": publisher_properties, }, operation="Expand product identifiers", ) return cast(dict[str, Any], resp.json())Expand publisher_properties selectors into concrete identifiers.
async def get_agent_domains(self, agent_url: str) ‑> dict[str, typing.Any]-
Expand source code
async def get_agent_domains(self, agent_url: str) -> dict[str, Any]: """Get all publisher domains and identifiers for an agent.""" encoded = url_quote(agent_url, safe="") resp = await self._request_ok( "GET", f"/api/registry/lookup/agent/{encoded}/domains", operation="Agent domains lookup", ) return cast(dict[str, Any], resp.json())Get all publisher domains and identifiers for an agent.
async def get_agent_formats(self, url: str) ‑> dict[str, typing.Any]-
Expand source code
async def get_agent_formats(self, url: str) -> dict[str, Any]: """Fetch creative formats from an agent.""" resp = await self._request_ok( "GET", "/api/public/agent-formats", params={"url": url}, operation="Agent formats", ) return cast(dict[str, Any], resp.json())Fetch creative formats from an agent.
async def get_agent_products(self, url: str) ‑> dict[str, typing.Any]-
Expand source code
async def get_agent_products(self, url: str) -> dict[str, Any]: """Fetch products from a sales agent.""" resp = await self._request_ok( "GET", "/api/public/agent-products", params={"url": url}, operation="Agent products", ) return cast(dict[str, Any], resp.json())Fetch products from a sales agent.
async def get_brand_json(self, domain: str, *, fresh: bool = False) ‑> dict[str, typing.Any] | None-
Expand source code
async def get_brand_json( self, domain: str, *, fresh: bool = False ) -> dict[str, Any] | None: """Fetch raw brand.json for a domain.""" params: dict[str, Any] = {"domain": domain} if fresh: params["fresh"] = "true" resp = await self._request( "GET", "/api/brands/brand-json", params=params, allow_404=True, operation="Brand JSON fetch", ) if resp is None: return None return cast(dict[str, Any], resp.json())Fetch raw brand.json for a domain.
async def get_feed(self,
*,
auth_token: str,
cursor: str | None = None,
types: str | None = None,
limit: int = 100) ‑> FeedPage-
Expand source code
async def get_feed( self, *, auth_token: str, cursor: str | None = None, types: str | None = None, limit: int = 100, ) -> FeedPage: """Poll the registry change feed (auth required). Returns a FeedPage with events, cursor, and has_more. Pass cursor from previous response to resume. """ params: dict[str, Any] = {"limit": limit} if cursor is not None: params["cursor"] = cursor if types is not None: params["types"] = types resp = await self._request_ok( "GET", "/api/registry/feed", params=params, auth_token=auth_token, operation="Feed poll", ) return self._parse(FeedPage, resp.json(), "Feed poll")Poll the registry change feed (auth required).
Returns a FeedPage with events, cursor, and has_more. Pass cursor from previous response to resume.
async def get_member(self, slug: str) ‑> Member | None-
Expand source code
async def get_member(self, slug: str) -> Member | None: """Get a single AAO member by their slug. Args: slug: Member slug (e.g., "adgentek"). Returns: Member if found, None if not in the registry. Raises: RegistryError: On HTTP or parsing errors. ValueError: If slug contains path-traversal characters. """ if not slug or not re.fullmatch(r"[a-zA-Z0-9_-]+", slug): raise ValueError(f"Invalid member slug: {slug!r}") client = await self._get_client() try: response = await client.get( f"{self._base_url}/api/members/{slug}", headers={"User-Agent": self._user_agent}, timeout=self._timeout, ) if response.status_code == 404: return None if response.status_code != 200: raise RegistryError( f"Member lookup failed: HTTP {response.status_code}", status_code=response.status_code, ) data = response.json() if data is None: return None return Member.model_validate(data) except RegistryError: raise except httpx.TimeoutException as e: raise RegistryError(f"Member lookup timed out after {self._timeout}s") from e except httpx.HTTPError as e: raise RegistryError(f"Member lookup failed: {e}") from e except (ValidationError, ValueError) as e: raise RegistryError(f"Member lookup failed: invalid response: {e}") from eGet a single AAO member by their slug.
Args
slug- Member slug (e.g., "adgentek").
Returns
Member if found, None if not in the registry.
Raises
RegistryError- On HTTP or parsing errors.
ValueError- If slug contains path-traversal characters.
async def get_property_check_report(self, report_id: str) ‑> dict[str, typing.Any] | None-
Expand source code
async def get_property_check_report( self, report_id: str ) -> dict[str, Any] | None: """Retrieve a property check report by ID.""" resp = await self._request( "GET", f"/api/properties/check/{url_quote(report_id, safe='')}", allow_404=True, operation="Property check report", ) if resp is None: return None return cast(dict[str, Any], resp.json())Retrieve a property check report by ID.
async def get_registry_stats(self) ‑> dict[str, typing.Any]-
Expand source code
async def get_registry_stats(self) -> dict[str, Any]: """Get aggregate registry statistics.""" resp = await self._request_ok( "GET", "/api/registry/stats", operation="Registry stats", ) return cast(dict[str, Any], resp.json())Get aggregate registry statistics.
async def list_agents(self,
*,
type: str | None = None,
health: bool = False,
capabilities: bool = False,
properties: bool = False,
compliance: bool = False) ‑> list[FederatedAgentWithDetails]-
Expand source code
async def list_agents( self, *, type: str | None = None, health: bool = False, capabilities: bool = False, properties: bool = False, compliance: bool = False, ) -> list[FederatedAgentWithDetails]: """List registered and discovered agents.""" params: dict[str, Any] = {} if type is not None: params["type"] = type if health: params["health"] = "true" if capabilities: params["capabilities"] = "true" if properties: params["properties"] = "true" if compliance: params["compliance"] = "true" resp = await self._request_ok( "GET", "/api/registry/agents", params=params, operation="Agent list", ) data = resp.json() return [ self._parse(FederatedAgentWithDetails, a, "Agent list") for a in data.get("agents", []) ]List registered and discovered agents.
async def list_brands(self, search: str | None = None, limit: int = 100, offset: int = 0) ‑> list[BrandRegistryItem]-
Expand source code
async def list_brands( self, search: str | None = None, limit: int = 100, offset: int = 0, ) -> list[BrandRegistryItem]: """List brands in the registry.""" params: dict[str, Any] = {"limit": limit, "offset": offset} if search is not None: params["search"] = search resp = await self._request_ok( "GET", "/api/brands/registry", params=params, operation="Brand list", ) data = resp.json() return [self._parse(BrandRegistryItem, b, "Brand list") for b in data.get("brands", [])]List brands in the registry.
async def list_members(self, limit: int = 100) ‑> list[Member]-
Expand source code
async def list_members(self, limit: int = 100) -> list[Member]: """List organizations registered in the AAO member directory. Args: limit: Maximum number of members to return. Returns: List of Member objects. Raises: RegistryError: On HTTP or parsing errors. """ if limit < 1: raise ValueError(f"limit must be at least 1, got {limit}") client = await self._get_client() try: response = await client.get( f"{self._base_url}/api/members", params={"limit": limit}, headers={"User-Agent": self._user_agent}, timeout=self._timeout, ) if response.status_code != 200: raise RegistryError( f"Member list failed: HTTP {response.status_code}", status_code=response.status_code, ) data = response.json() return [Member.model_validate(m) for m in data.get("members", [])] except RegistryError: raise except httpx.TimeoutException as e: raise RegistryError(f"Member list timed out after {self._timeout}s") from e except httpx.HTTPError as e: raise RegistryError(f"Member list failed: {e}") from e except (ValidationError, ValueError) as e: raise RegistryError(f"Member list failed: invalid response: {e}") from eList organizations registered in the AAO member directory.
Args
limit- Maximum number of members to return.
Returns
List of Member objects.
Raises
RegistryError- On HTTP or parsing errors.
async def list_policies(self,
search: str | None = None,
category: str | None = None,
enforcement: str | None = None,
jurisdiction: str | None = None,
vertical: str | None = None,
domain: str | None = None,
limit: int = 20,
offset: int = 0) ‑> list[PolicySummary]-
Expand source code
async def list_policies( self, search: str | None = None, category: str | None = None, enforcement: str | None = None, jurisdiction: str | None = None, vertical: str | None = None, domain: str | None = None, limit: int = 20, offset: int = 0, ) -> list[PolicySummary]: """List governance policies with optional filtering. Args: search: Full-text search on policy name and description. category: Filter by category ("regulation" or "standard"). enforcement: Filter by enforcement level ("must", "should", "may"). jurisdiction: Filter by jurisdiction with region alias matching. vertical: Filter by industry vertical. domain: Filter by governance domain ("campaign", "creative", etc.). limit: Results per page (default 20, max 1000). offset: Pagination offset. Returns: List of PolicySummary objects. Raises: RegistryError: On HTTP or parsing errors. """ client = await self._get_client() params: dict[str, str | int] = {"limit": limit, "offset": offset} if search is not None: params["search"] = search if category is not None: params["category"] = category if enforcement is not None: params["enforcement"] = enforcement if jurisdiction is not None: params["jurisdiction"] = jurisdiction if vertical is not None: params["vertical"] = vertical if domain is not None: params["domain"] = domain try: response = await client.get( f"{self._base_url}/api/policies/registry", params=params, headers={"User-Agent": self._user_agent}, timeout=self._timeout, ) if response.status_code != 200: raise RegistryError( f"Policy list failed: HTTP {response.status_code}", status_code=response.status_code, ) data = response.json() return [PolicySummary.model_validate(p) for p in data.get("policies", [])] except RegistryError: raise except httpx.TimeoutException as e: raise RegistryError(f"Policy list timed out after {self._timeout}s") from e except httpx.HTTPError as e: raise RegistryError(f"Policy list failed: {e}") from e except (ValidationError, ValueError) as e: raise RegistryError(f"Policy list failed: invalid response: {e}") from eList governance policies with optional filtering.
Args
search- Full-text search on policy name and description.
category- Filter by category ("regulation" or "standard").
enforcement- Filter by enforcement level ("must", "should", "may").
jurisdiction- Filter by jurisdiction with region alias matching.
vertical- Filter by industry vertical.
domain- Filter by governance domain ("campaign", "creative", etc.).
limit- Results per page (default 20, max 1000).
offset- Pagination offset.
Returns
List of PolicySummary objects.
Raises
RegistryError- On HTTP or parsing errors.
async def list_properties(self, search: str | None = None, limit: int = 100, offset: int = 0) ‑> list[PropertyRegistryItem]-
Expand source code
async def list_properties( self, search: str | None = None, limit: int = 100, offset: int = 0, ) -> list[PropertyRegistryItem]: """List properties in the registry.""" params: dict[str, Any] = {"limit": limit, "offset": offset} if search is not None: params["search"] = search resp = await self._request_ok( "GET", "/api/properties/registry", params=params, operation="Property list", ) data = resp.json() return [ self._parse(PropertyRegistryItem, p, "Property list") for p in data.get("properties", []) ]List properties in the registry.
async def list_publishers(self) ‑> list[FederatedPublisher]-
Expand source code
async def list_publishers(self) -> list[FederatedPublisher]: """List publishers in the registry.""" resp = await self._request_ok( "GET", "/api/registry/publishers", operation="Publisher list", ) data = resp.json() return [ self._parse(FederatedPublisher, p, "Publisher list") for p in data.get("publishers", []) ]List publishers in the registry.
async def lookup_brand(self, domain: str) ‑> ResolvedBrand | None-
Expand source code
async def lookup_brand(self, domain: str) -> ResolvedBrand | None: """Resolve a domain to its brand identity. Works for any domain — brand houses, sub-brands, and operators (agencies, DSPs) are all brands in the registry. Args: domain: Domain to resolve (e.g., "nike.com", "wpp.com"). Returns: ResolvedBrand if found, None if not in the registry. Raises: RegistryError: On HTTP or parsing errors. Example: brand = await registry.lookup_brand(request.brand.domain) """ client = await self._get_client() try: response = await client.get( f"{self._base_url}/api/brands/resolve", params={"domain": domain}, headers={"User-Agent": self._user_agent}, timeout=self._timeout, ) if response.status_code == 404: return None if response.status_code != 200: raise RegistryError( f"Brand lookup failed: HTTP {response.status_code}", status_code=response.status_code, ) data = response.json() if data is None: return None return ResolvedBrand.model_validate(data) except RegistryError: raise except httpx.TimeoutException as e: raise RegistryError(f"Brand lookup timed out after {self._timeout}s") from e except httpx.HTTPError as e: raise RegistryError(f"Brand lookup failed: {e}") from e except (ValidationError, ValueError) as e: raise RegistryError(f"Brand lookup failed: invalid response: {e}") from eResolve a domain to its brand identity.
Works for any domain — brand houses, sub-brands, and operators (agencies, DSPs) are all brands in the registry.
Args
domain- Domain to resolve (e.g., "nike.com", "wpp.com").
Returns
ResolvedBrand if found, None if not in the registry.
Raises
RegistryError- On HTTP or parsing errors.
Example
brand = await registry.lookup_brand(request.brand.domain)
async def lookup_brands(self, domains: list[str]) ‑> dict[str, ResolvedBrand | None]-
Expand source code
async def lookup_brands(self, domains: list[str]) -> dict[str, ResolvedBrand | None]: """Bulk resolve domains to brand identities. Automatically chunks requests exceeding 100 domains. Args: domains: List of domains to resolve. Returns: Dict mapping each domain to its ResolvedBrand, or None if not found. Raises: RegistryError: On HTTP or parsing errors. """ if not domains: return {} chunks = [ domains[i : i + MAX_BULK_DOMAINS] for i in range(0, len(domains), MAX_BULK_DOMAINS) ] chunk_results = await asyncio.gather( *[self._lookup_brands_chunk(chunk) for chunk in chunks] ) merged: dict[str, ResolvedBrand | None] = {} for result in chunk_results: merged.update(result) return mergedBulk resolve domains to brand identities.
Automatically chunks requests exceeding 100 domains.
Args
domains- List of domains to resolve.
Returns
Dict mapping each domain to its ResolvedBrand, or None if not found.
Raises
RegistryError- On HTTP or parsing errors.
async def lookup_domain(self, domain: str) ‑> DomainLookupResult-
Expand source code
async def lookup_domain(self, domain: str) -> DomainLookupResult: """Find all agents authorized for a publisher domain.""" resp = await self._request_ok( "GET", f"/api/registry/lookup/domain/{url_quote(domain, safe='')}", operation="Domain lookup", ) return self._parse(DomainLookupResult, resp.json(), "Domain lookup")Find all agents authorized for a publisher domain.
async def lookup_manifest_ref(self, domain: str, *, type: str | None = None) ‑> dict[str, typing.Any]-
Expand source code
async def lookup_manifest_ref( self, domain: str, *, type: str | None = None ) -> dict[str, Any]: """Find the best manifest reference for a domain.""" params: dict[str, Any] = {"domain": domain} if type is not None: params["type"] = type resp = await self._request_ok( "GET", "/api/manifest-refs/lookup", params=params, operation="Manifest ref lookup", ) return cast(dict[str, Any], resp.json())Find the best manifest reference for a domain.
async def lookup_properties(self, domains: list[str]) ‑> dict[str, ResolvedProperty | None]-
Expand source code
async def lookup_properties(self, domains: list[str]) -> dict[str, ResolvedProperty | None]: """Bulk resolve publisher domains to property info. Automatically chunks requests exceeding 100 domains. Args: domains: List of publisher domains to resolve. Returns: Dict mapping each domain to its ResolvedProperty, or None if not found. Raises: RegistryError: On HTTP or parsing errors. """ if not domains: return {} chunks = [ domains[i : i + MAX_BULK_DOMAINS] for i in range(0, len(domains), MAX_BULK_DOMAINS) ] chunk_results = await asyncio.gather( *[self._lookup_properties_chunk(chunk) for chunk in chunks] ) merged: dict[str, ResolvedProperty | None] = {} for result in chunk_results: merged.update(result) return mergedBulk resolve publisher domains to property info.
Automatically chunks requests exceeding 100 domains.
Args
domains- List of publisher domains to resolve.
Returns
Dict mapping each domain to its ResolvedProperty, or None if not found.
Raises
RegistryError- On HTTP or parsing errors.
async def lookup_property(self, domain: str) ‑> ResolvedProperty | None-
Expand source code
async def lookup_property(self, domain: str) -> ResolvedProperty | None: """Resolve a publisher domain to its property info. Args: domain: Publisher domain to resolve (e.g., "nytimes.com"). Returns: ResolvedProperty if found, None if the domain is not in the registry. Raises: RegistryError: On HTTP or parsing errors. """ client = await self._get_client() try: response = await client.get( f"{self._base_url}/api/properties/resolve", params={"domain": domain}, headers={"User-Agent": self._user_agent}, timeout=self._timeout, ) if response.status_code == 404: return None if response.status_code != 200: raise RegistryError( f"Property lookup failed: HTTP {response.status_code}", status_code=response.status_code, ) data = response.json() if data is None: return None return ResolvedProperty.model_validate(data) except RegistryError: raise except httpx.TimeoutException as e: raise RegistryError(f"Property lookup timed out after {self._timeout}s") from e except httpx.HTTPError as e: raise RegistryError(f"Property lookup failed: {e}") from e except (ValidationError, ValueError) as e: raise RegistryError(f"Property lookup failed: invalid response: {e}") from eResolve a publisher domain to its property info.
Args
domain- Publisher domain to resolve (e.g., "nytimes.com").
Returns
ResolvedProperty if found, None if the domain is not in the registry.
Raises
RegistryError- On HTTP or parsing errors.
async def lookup_property_identifier(self, type: str, value: str) ‑> dict[str, typing.Any]-
Expand source code
async def lookup_property_identifier( self, type: str, value: str ) -> dict[str, Any]: """Find agents holding a specific property identifier.""" resp = await self._request_ok( "GET", "/api/registry/lookup/property", params={"type": type, "value": value}, operation="Property identifier lookup", ) return cast(dict[str, Any], resp.json())Find agents holding a specific property identifier.
async def policy_history(self, policy_id: str, limit: int = 20, offset: int = 0) ‑> PolicyHistory | None-
Expand source code
async def policy_history( self, policy_id: str, limit: int = 20, offset: int = 0, ) -> PolicyHistory | None: """Retrieve edit history for a policy. Args: policy_id: Policy identifier. limit: Maximum revisions to return (default 20, max 100). offset: Pagination offset. Returns: PolicyHistory if found, None if the policy doesn't exist. Raises: RegistryError: On HTTP or parsing errors. """ client = await self._get_client() try: response = await client.get( f"{self._base_url}/api/policies/history", params={"policy_id": policy_id, "limit": limit, "offset": offset}, headers={"User-Agent": self._user_agent}, timeout=self._timeout, ) if response.status_code == 404: return None if response.status_code != 200: raise RegistryError( f"Policy history failed: HTTP {response.status_code}", status_code=response.status_code, ) data = response.json() if data is None: return None return PolicyHistory.model_validate(data) except RegistryError: raise except httpx.TimeoutException as e: raise RegistryError( f"Policy history timed out after {self._timeout}s" ) from e except httpx.HTTPError as e: raise RegistryError(f"Policy history failed: {e}") from e except (ValidationError, ValueError) as e: raise RegistryError( f"Policy history failed: invalid response: {e}" ) from eRetrieve edit history for a policy.
Args
policy_id- Policy identifier.
limit- Maximum revisions to return (default 20, max 100).
offset- Pagination offset.
Returns
PolicyHistory if found, None if the policy doesn't exist.
Raises
RegistryError- On HTTP or parsing errors.
async def property_history(self, domain: str, limit: int = 20, offset: int = 0) ‑> PropertyActivity | None-
Expand source code
async def property_history( self, domain: str, limit: int = 20, offset: int = 0, ) -> PropertyActivity | None: """Get edit history for a property.""" resp = await self._request( "GET", "/api/properties/history", params={"domain": domain, "limit": limit, "offset": offset}, allow_404=True, operation="Property history", ) if resp is None: return None return self._parse(PropertyActivity, resp.json(), "Property history")Get edit history for a property.
async def request_crawl(self, domain: str, *, auth_token: str) ‑> dict[str, typing.Any]-
Expand source code
async def request_crawl( self, domain: str, *, auth_token: str ) -> dict[str, Any]: """Request a domain re-crawl (auth required).""" resp = await self._request_ok( "POST", "/api/registry/crawl-request", json_body={"domain": domain}, auth_token=auth_token, operation="Crawl request", expected_status={200, 202}, ) return cast(dict[str, Any], resp.json())Request a domain re-crawl (auth required).
async def resolve_policies(self, policy_ids: list[str]) ‑> dict[str, Policy | None]-
Expand source code
async def resolve_policies( self, policy_ids: list[str], ) -> dict[str, Policy | None]: """Bulk resolve policies by ID. Automatically chunks requests exceeding 100 policy IDs. Args: policy_ids: List of policy identifiers to resolve. Returns: Dict mapping each policy_id to its Policy, or None if not found. Raises: RegistryError: On HTTP or parsing errors. """ if not policy_ids: return {} chunks = [ policy_ids[i : i + MAX_BULK_POLICIES] for i in range(0, len(policy_ids), MAX_BULK_POLICIES) ] chunk_results = await asyncio.gather( *[self._resolve_policies_chunk(chunk) for chunk in chunks] ) merged: dict[str, Policy | None] = {} for result in chunk_results: merged.update(result) return mergedBulk resolve policies by ID.
Automatically chunks requests exceeding 100 policy IDs.
Args
policy_ids- List of policy identifiers to resolve.
Returns
Dict mapping each policy_id to its Policy, or None if not found.
Raises
RegistryError- On HTTP or parsing errors.
async def resolve_policy(self, policy_id: str, version: str | None = None) ‑> Policy | None-
Expand source code
async def resolve_policy( self, policy_id: str, version: str | None = None, ) -> Policy | None: """Resolve a single policy by ID. Args: policy_id: Policy identifier (e.g., "gdpr_consent"). version: Optional version pin; returns None if current version differs. Returns: Policy if found, None if not in the registry. Raises: RegistryError: On HTTP or parsing errors. """ client = await self._get_client() params: dict[str, str] = {"policy_id": policy_id} if version is not None: params["version"] = version try: response = await client.get( f"{self._base_url}/api/policies/resolve", params=params, headers={"User-Agent": self._user_agent}, timeout=self._timeout, ) if response.status_code == 404: return None if response.status_code != 200: raise RegistryError( f"Policy resolve failed: HTTP {response.status_code}", status_code=response.status_code, ) data = response.json() if data is None: return None return Policy.model_validate(data) except RegistryError: raise except httpx.TimeoutException as e: raise RegistryError(f"Policy resolve timed out after {self._timeout}s") from e except httpx.HTTPError as e: raise RegistryError(f"Policy resolve failed: {e}") from e except (ValidationError, ValueError) as e: raise RegistryError(f"Policy resolve failed: invalid response: {e}") from eResolve a single policy by ID.
Args
policy_id- Policy identifier (e.g., "gdpr_consent").
version- Optional version pin; returns None if current version differs.
Returns
Policy if found, None if not in the registry.
Raises
RegistryError- On HTTP or parsing errors.
async def save_brand(self,
domain: str,
brand_name: str,
*,
auth_token: str,
brand_manifest: dict[str, Any] | None = None) ‑> dict[str, typing.Any]-
Expand source code
async def save_brand( self, domain: str, brand_name: str, *, auth_token: str, brand_manifest: dict[str, Any] | None = None, ) -> dict[str, Any]: """Save or update a brand in the registry (auth required).""" body: dict[str, Any] = {"domain": domain, "brand_name": brand_name} if brand_manifest is not None: body["brand_manifest"] = brand_manifest resp = await self._request_ok( "POST", "/api/brands/save", json_body=body, auth_token=auth_token, operation="Brand save", ) return cast(dict[str, Any], resp.json())Save or update a brand in the registry (auth required).
async def save_policy(self,
policy_id: str,
version: str,
name: str,
category: str,
enforcement: str,
policy: str,
*,
auth_token: str,
description: str | None = None,
jurisdictions: list[str] | None = None,
region_aliases: dict[str, list[str]] | None = None,
verticals: list[str] | None = None,
channels: list[str] | None = None,
effective_date: str | None = None,
sunset_date: str | None = None,
governance_domains: list[str] | None = None,
source_url: str | None = None,
source_name: str | None = None,
guidance: str | None = None,
exemplars: dict[str, Any] | None = None,
ext: dict[str, Any] | None = None) ‑> dict[str, typing.Any]-
Expand source code
async def save_policy( self, policy_id: str, version: str, name: str, category: str, enforcement: str, policy: str, *, auth_token: str, description: str | None = None, jurisdictions: list[str] | None = None, region_aliases: dict[str, list[str]] | None = None, verticals: list[str] | None = None, channels: list[str] | None = None, effective_date: str | None = None, sunset_date: str | None = None, governance_domains: list[str] | None = None, source_url: str | None = None, source_name: str | None = None, guidance: str | None = None, exemplars: dict[str, Any] | None = None, ext: dict[str, Any] | None = None, ) -> dict[str, Any]: """Create or update a community-contributed policy. Requires authentication. Cannot edit registry-sourced or pending policies. Args: policy_id: Policy identifier (lowercase alphanumeric with underscores). version: Semantic version string. name: Human-readable policy name. category: "regulation" or "standard". enforcement: "must", "should", or "may". policy: Natural language policy text. auth_token: API key for authentication. description: Policy description. jurisdictions: ISO jurisdiction codes. region_aliases: Region alias mappings (e.g., {"EU": ["DE", "FR"]}). verticals: Industry verticals. channels: Media channels. effective_date: ISO 8601 date when enforcement begins. sunset_date: ISO 8601 date when enforcement ends. governance_domains: Applicable domains ("campaign", "creative", etc.). source_url: URL of the source regulation/standard. source_name: Name of the source. guidance: Implementation guidance text. exemplars: Pass/fail calibration scenarios. ext: Extension data. Returns: Dict with success, message, policy_id, and revision_number. Raises: RegistryError: On HTTP or parsing errors (400, 401, 409, 429). """ client = await self._get_client() body: dict[str, Any] = { "policy_id": policy_id, "version": version, "name": name, "category": category, "enforcement": enforcement, "policy": policy, } for key, value in [ ("description", description), ("jurisdictions", jurisdictions), ("region_aliases", region_aliases), ("verticals", verticals), ("channels", channels), ("effective_date", effective_date), ("sunset_date", sunset_date), ("governance_domains", governance_domains), ("source_url", source_url), ("source_name", source_name), ("guidance", guidance), ("exemplars", exemplars), ("ext", ext), ]: if value is not None: body[key] = value try: response = await client.post( f"{self._base_url}/api/policies/save", json=body, headers={ "User-Agent": self._user_agent, "Authorization": f"Bearer {auth_token}", }, timeout=self._timeout, ) if response.status_code != 200: raise RegistryError( f"Policy save failed: HTTP {response.status_code}", status_code=response.status_code, ) result: dict[str, Any] = response.json() return result except RegistryError: raise except httpx.TimeoutException as e: raise RegistryError( f"Policy save timed out after {self._timeout}s" ) from e except httpx.HTTPError as e: raise RegistryError(f"Policy save failed: {e}") from eCreate or update a community-contributed policy.
Requires authentication. Cannot edit registry-sourced or pending policies.
Args
policy_id- Policy identifier (lowercase alphanumeric with underscores).
version- Semantic version string.
name- Human-readable policy name.
category- "regulation" or "standard".
enforcement- "must", "should", or "may".
policy- Natural language policy text.
auth_token- API key for authentication.
description- Policy description.
jurisdictions- ISO jurisdiction codes.
region_aliases- Region alias mappings (e.g., {"EU": ["DE", "FR"]}).
verticals- Industry verticals.
channels- Media channels.
effective_date- ISO 8601 date when enforcement begins.
sunset_date- ISO 8601 date when enforcement ends.
governance_domains- Applicable domains ("campaign", "creative", etc.).
source_url- URL of the source regulation/standard.
source_name- Name of the source.
guidance- Implementation guidance text.
exemplars- Pass/fail calibration scenarios.
ext- Extension data.
Returns
Dict with success, message, policy_id, and revision_number.
Raises
RegistryError- On HTTP or parsing errors (400, 401, 409, 429).
async def save_property(self,
publisher_domain: str,
authorized_agents: list[dict[str, Any]],
*,
auth_token: str,
properties: list[dict[str, Any]] | None = None,
contact: dict[str, str] | None = None) ‑> dict[str, typing.Any]-
Expand source code
async def save_property( self, publisher_domain: str, authorized_agents: list[dict[str, Any]], *, auth_token: str, properties: list[dict[str, Any]] | None = None, contact: dict[str, str] | None = None, ) -> dict[str, Any]: """Save or update a hosted property (auth required).""" body: dict[str, Any] = { "publisher_domain": publisher_domain, "authorized_agents": authorized_agents, } if properties is not None: body["properties"] = properties if contact is not None: body["contact"] = contact resp = await self._request_ok( "POST", "/api/properties/save", json_body=body, auth_token=auth_token, operation="Property save", ) return cast(dict[str, Any], resp.json())Save or update a hosted property (auth required).
async def search(self, q: str) ‑> dict[str, typing.Any]-
Expand source code
async def search(self, q: str) -> dict[str, Any]: """Search across brands, publishers, and properties.""" resp = await self._request_ok( "GET", "/api/search", params={"q": q}, operation="Search", ) return cast(dict[str, Any], resp.json())Search across brands, publishers, and properties.
async def search_agents(self,
*,
auth_token: str,
channels: str | None = None,
property_types: str | None = None,
markets: str | None = None,
categories: str | None = None,
tags: str | None = None,
delivery_types: str | None = None,
has_tmp: bool | None = None,
min_properties: int | None = None,
cursor: str | None = None,
limit: int = 50) ‑> dict[str, typing.Any]-
Expand source code
async def search_agents( self, *, auth_token: str, channels: str | None = None, property_types: str | None = None, markets: str | None = None, categories: str | None = None, tags: str | None = None, delivery_types: str | None = None, has_tmp: bool | None = None, min_properties: int | None = None, cursor: str | None = None, limit: int = 50, ) -> dict[str, Any]: """Search agents by inventory profile (auth required).""" params: dict[str, Any] = {"limit": limit} for key, val in [ ("channels", channels), ("property_types", property_types), ("markets", markets), ("categories", categories), ("tags", tags), ("delivery_types", delivery_types), ("cursor", cursor), ]: if val is not None: params[key] = val if has_tmp is not None: params["has_tmp"] = str(has_tmp).lower() if min_properties is not None: params["min_properties"] = min_properties resp = await self._request_ok( "GET", "/api/registry/agents/search", params=params, auth_token=auth_token, operation="Agent search", ) return cast(dict[str, Any], resp.json())Search agents by inventory profile (auth required).
async def validate_adagents(self, domain: str) ‑> dict[str, typing.Any]-
Expand source code
async def validate_adagents(self, domain: str) -> dict[str, Any]: """Validate a domain's adagents.json via the registry API.""" resp = await self._request_ok( "POST", "/api/adagents/validate", json_body={"domain": domain}, operation="Adagents validate", ) return cast(dict[str, Any], resp.json())Validate a domain's adagents.json via the registry API.
-
Expand source code
async def validate_product_authorization( self, agent_url: str, publisher_properties: list[dict[str, Any]], ) -> dict[str, Any]: """Check whether an agent is authorized to sell products.""" resp = await self._request_ok( "POST", "/api/registry/validate/product-authorization", json_body={ "agent_url": agent_url, "publisher_properties": publisher_properties, }, operation="Product authorization", ) return cast(dict[str, Any], resp.json())Check whether an agent is authorized to sell products.
async def validate_property(self, domain: str) ‑> ValidationResult-
Expand source code
async def validate_property(self, domain: str) -> ValidationResult: """Validate a domain's adagents.json configuration.""" resp = await self._request_ok( "GET", "/api/properties/validate", params={"domain": domain}, operation="Property validate", ) return self._parse(ValidationResult, resp.json(), "Property validate")Validate a domain's adagents.json configuration.
-
Expand source code
async def validate_property_authorization( self, agent_url: str, identifier_type: str, identifier_value: str, ) -> dict[str, Any]: """Quick check if a property identifier is authorized for an agent.""" resp = await self._request_ok( "GET", "/api/registry/validate/property-authorization", params={ "agent_url": agent_url, "identifier_type": identifier_type, "identifier_value": identifier_value, }, operation="Property authorization", ) return cast(dict[str, Any], resp.json())Quick check if a property identifier is authorized for an agent.
async def validate_publisher(self, domain: str) ‑> dict[str, typing.Any]-
Expand source code
async def validate_publisher(self, domain: str) -> dict[str, Any]: """Validate a publisher domain's adagents.json and return stats.""" resp = await self._request_ok( "GET", "/api/public/validate-publisher", params={"domain": domain}, operation="Publisher validation", ) return cast(dict[str, Any], resp.json())Validate a publisher domain's adagents.json and return stats.
class RegistryError (message: str, status_code: int | None = None)-
Expand source code
class RegistryError(ADCPError): """Error from AdCP registry API operations (brand/property lookups).""" def __init__(self, message: str, status_code: int | None = None): """Initialize registry error.""" self.status_code = status_code suggestion = "Check that the registry API is accessible and the domain is valid." super().__init__(message, suggestion=suggestion)Error from AdCP registry API operations (brand/property lookups).
Initialize registry error.
Ancestors
- ADCPError
- builtins.Exception
- builtins.BaseException
class RegistrySync (client: RegistryClient,
*,
auth_token: str,
poll_interval: float = 60.0,
cursor_store: CursorStore | None = None,
types: str | None = None,
batch_size: int = 100)-
Expand source code
class RegistrySync: """Polls the registry change feed and dispatches events to handlers. Args: client: RegistryClient instance for HTTP calls. auth_token: Bearer token for feed access. poll_interval: Seconds between polls (default 60). cursor_store: Optional CursorStore for persistence. Defaults to FileCursorStore. types: Optional event type filter (e.g., "property.*,agent.*"). batch_size: Max events per poll (default 100, max 10000). """ def __init__( self, client: RegistryClient, *, auth_token: str, poll_interval: float = 60.0, cursor_store: CursorStore | None = None, types: str | None = None, batch_size: int = 100, ) -> None: self._client = client self._auth_token = auth_token self._poll_interval = poll_interval self._cursor_store: CursorStore = cursor_store or FileCursorStore() self._types = types self._batch_size = min(batch_size, 10000) self._handlers: dict[str, list[ChangeHandler]] = defaultdict(list) self._all_handlers: list[ChangeHandler] = [] self._cursor: str | None = None self._cursor_loaded = False self._stop_event: asyncio.Event | None = None self._running = False def on(self, event_type: str, handler: ChangeHandler) -> None: """Register a handler for a specific event type. Supports glob patterns: "property.*" matches "property.created", "property.updated", etc. """ self._handlers[event_type].append(handler) def on_all(self, handler: ChangeHandler) -> None: """Register a handler for all events.""" self._all_handlers.append(handler) @property def cursor(self) -> str | None: """Current cursor position.""" return self._cursor async def _load_cursor(self) -> None: """Load cursor from store on first use.""" if not self._cursor_loaded: self._cursor = await self._cursor_store.load() self._cursor_loaded = True async def _dispatch(self, event: FeedEvent) -> None: """Dispatch a single event to matching handlers.""" # Dispatch to type-specific handlers for pattern, handlers in self._handlers.items(): if fnmatch(event.event_type, pattern): for handler in handlers: try: await handler(event) except Exception: logger.exception( "Handler error for event %s (%s)", event.event_id, event.event_type, ) # Dispatch to catch-all handlers for handler in self._all_handlers: try: await handler(event) except Exception: logger.exception( "Handler error for event %s (%s)", event.event_id, event.event_type, ) async def poll_once(self) -> list[FeedEvent]: """Poll the feed once and dispatch events. Returns the list of events processed. """ await self._load_cursor() try: page = await self._client.get_feed( auth_token=self._auth_token, cursor=self._cursor, types=self._types, limit=self._batch_size, ) except RegistryError as e: if e.status_code == 410: logger.warning("Feed cursor expired, resetting to start") self._cursor = None await self._cursor_store.save("") return [] raise for event in page.events: await self._dispatch(event) if page.cursor: self._cursor = page.cursor await self._cursor_store.save(page.cursor) return list(page.events) async def start(self) -> None: """Start the polling loop. Runs until stop() is called.""" if self._running: return self._running = True self._stop_event = asyncio.Event() logger.info("RegistrySync started (interval=%.1fs)", self._poll_interval) try: while not self._stop_event.is_set(): try: events = await self.poll_once() if events: logger.debug("Processed %d events", len(events)) except RegistryError as e: logger.error("Feed poll failed: %s", e) except Exception: logger.exception("Unexpected error in feed poll") # Wait for interval or stop signal try: await asyncio.wait_for( self._stop_event.wait(), timeout=self._poll_interval, ) except asyncio.TimeoutError: pass # Normal - poll interval elapsed finally: self._running = False logger.info("RegistrySync stopped") async def stop(self) -> None: """Stop the polling loop gracefully.""" if self._stop_event is not None: self._stop_event.set()Polls the registry change feed and dispatches events to handlers.
Args
client- RegistryClient instance for HTTP calls.
auth_token- Bearer token for feed access.
poll_interval- Seconds between polls (default 60).
cursor_store- Optional CursorStore for persistence. Defaults to FileCursorStore.
types- Optional event type filter (e.g., "property.,agent.").
batch_size- Max events per poll (default 100, max 10000).
Instance variables
prop cursor : str | None-
Expand source code
@property def cursor(self) -> str | None: """Current cursor position.""" return self._cursorCurrent cursor position.
Methods
def on(self, event_type: str, handler: ChangeHandler) ‑> None-
Expand source code
def on(self, event_type: str, handler: ChangeHandler) -> None: """Register a handler for a specific event type. Supports glob patterns: "property.*" matches "property.created", "property.updated", etc. """ self._handlers[event_type].append(handler)Register a handler for a specific event type.
Supports glob patterns: "property.*" matches "property.created", "property.updated", etc.
def on_all(self, handler: ChangeHandler) ‑> None-
Expand source code
def on_all(self, handler: ChangeHandler) -> None: """Register a handler for all events.""" self._all_handlers.append(handler)Register a handler for all events.
async def poll_once(self) ‑> list[FeedEvent]-
Expand source code
async def poll_once(self) -> list[FeedEvent]: """Poll the feed once and dispatch events. Returns the list of events processed. """ await self._load_cursor() try: page = await self._client.get_feed( auth_token=self._auth_token, cursor=self._cursor, types=self._types, limit=self._batch_size, ) except RegistryError as e: if e.status_code == 410: logger.warning("Feed cursor expired, resetting to start") self._cursor = None await self._cursor_store.save("") return [] raise for event in page.events: await self._dispatch(event) if page.cursor: self._cursor = page.cursor await self._cursor_store.save(page.cursor) return list(page.events)Poll the feed once and dispatch events.
Returns the list of events processed.
async def start(self) ‑> None-
Expand source code
async def start(self) -> None: """Start the polling loop. Runs until stop() is called.""" if self._running: return self._running = True self._stop_event = asyncio.Event() logger.info("RegistrySync started (interval=%.1fs)", self._poll_interval) try: while not self._stop_event.is_set(): try: events = await self.poll_once() if events: logger.debug("Processed %d events", len(events)) except RegistryError as e: logger.error("Feed poll failed: %s", e) except Exception: logger.exception("Unexpected error in feed poll") # Wait for interval or stop signal try: await asyncio.wait_for( self._stop_event.wait(), timeout=self._poll_interval, ) except asyncio.TimeoutError: pass # Normal - poll interval elapsed finally: self._running = False logger.info("RegistrySync stopped")Start the polling loop. Runs until stop() is called.
async def stop(self) ‑> None-
Expand source code
async def stop(self) -> None: """Stop the polling loop gracefully.""" if self._stop_event is not None: self._stop_event.set()Stop the polling loop gracefully.
class ReportPlanOutcomeRequest (**data: Any)-
Expand source code
class ReportPlanOutcomeRequest(AdCPBaseModel): model_config = ConfigDict( extra='forbid', ) check_id: Annotated[ str | None, Field( description="The check_id from check_governance. Links the outcome to the governance check that authorized it. Required for 'completed' and 'failed' outcomes." ), ] = None delivery: Annotated[ Delivery | None, Field(description="Delivery metrics. Required when outcome is 'delivery'.") ] = None error: Annotated[ Error | None, Field(description="Error details. Required when outcome is 'failed'.") ] = None governance_context: Annotated[ str, Field( description='Opaque governance context from the check_governance response that authorized this action. Enables the governance agent to correlate the outcome to the original check.', max_length=4096, min_length=1, pattern='^[\\x20-\\x7E]+$', ), ] idempotency_key: Annotated[ str | None, Field( description='Client-generated unique key for this request. Prevents duplicate outcome reports on retries. MUST be unique per (seller, request) pair to prevent cross-seller correlation. Use a fresh UUID v4 for each request.', max_length=255, min_length=16, ), ] = None outcome: Annotated[outcome_type.OutcomeType, Field(description='Outcome type.')] plan_id: Annotated[str, Field(description='The plan this outcome is for.')] seller_response: Annotated[ SellerResponse | None, Field(description="The seller's full response. Required when outcome is 'completed'."), ] = NoneBase model for AdCP types with spec-compliant serialization.
Defaults to
extra='ignore'so that unknown fields from newer spec versions are silently dropped rather than causing validation errors. Generated types whose schemas setadditionalProperties: trueoverride this withextra='allow'in their ownmodel_config. Consumers who want strict validation can override withextra='forbid'.Create a new model by parsing and validating input data from keyword arguments.
Raises [
ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.selfis explicitly positional-only to allowselfas a field name.Ancestors
- AdCPBaseModel
- pydantic.main.BaseModel
Class variables
var check_id : str | Nonevar delivery : Delivery | Nonevar error : Error | Nonevar governance_context : strvar idempotency_key : str | Nonevar model_configvar outcome : OutcomeTypevar plan_id : strvar seller_response : SellerResponse | None
Inherited members
class ReportPlanOutcomeResponse (**data: Any)-
Expand source code
class ReportPlanOutcomeResponse(AdCPBaseModel): model_config = ConfigDict( extra='forbid', ) committed_budget: Annotated[ float | None, Field( description="Budget committed from this outcome. Present for 'completed' and 'failed' outcomes." ), ] = None findings: Annotated[ list[Finding] | None, Field(description="Issues detected. Present only when status is 'findings'."), ] = None outcome_id: Annotated[str, Field(description='Unique identifier for this outcome record.')] plan_summary: Annotated[ PlanSummary | None, Field( description="Updated plan budget state. Present for 'completed' and 'failed' outcomes." ), ] = None status: Annotated[ Status, Field( description="'accepted' means state updated with no issues. 'findings' means issues were detected." ), ]Base model for AdCP types with spec-compliant serialization.
Defaults to
extra='ignore'so that unknown fields from newer spec versions are silently dropped rather than causing validation errors. Generated types whose schemas setadditionalProperties: trueoverride this withextra='allow'in their ownmodel_config. Consumers who want strict validation can override withextra='forbid'.Create a new model by parsing and validating input data from keyword arguments.
Raises [
ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.selfis explicitly positional-only to allowselfas a field name.Ancestors
- AdCPBaseModel
- pydantic.main.BaseModel
Class variables
var committed_budget : float | Nonevar findings : list[Finding] | Nonevar model_configvar outcome_id : strvar plan_summary : PlanSummary | Nonevar status : Status
Inherited members
class ReportUsageRequest (**data: Any)-
Expand source code
class ReportUsageRequest(AdCPBaseModel): model_config = ConfigDict( extra='allow', ) context: context_1.ContextObject | None = None ext: ext_1.ExtensionObject | None = None idempotency_key: Annotated[ str | None, Field( description='Client-generated unique key for this request. If a request with the same key has already been accepted, the server returns the original response without re-processing. MUST be unique per (seller, request) pair to prevent cross-seller correlation. Use a fresh UUID v4 for each request. Prevents duplicate billing on retries.' ), ] = None reporting_period: Annotated[ datetime_range.DatetimeRange, Field( description='The time range covered by this usage report. Applies to all records in the request.' ), ] usage: Annotated[ list[UsageItem], Field( description='One or more usage records. Each record is self-contained: it carries its own account, allowing a single request to span multiple accounts.', min_length=1, ), ]Base model for AdCP types with spec-compliant serialization.
Defaults to
extra='ignore'so that unknown fields from newer spec versions are silently dropped rather than causing validation errors. Generated types whose schemas setadditionalProperties: trueoverride this withextra='allow'in their ownmodel_config. Consumers who want strict validation can override withextra='forbid'.Create a new model by parsing and validating input data from keyword arguments.
Raises [
ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.selfis explicitly positional-only to allowselfas a field name.Ancestors
- AdCPBaseModel
- pydantic.main.BaseModel
Class variables
var context : ContextObject | Nonevar ext : ExtensionObject | Nonevar idempotency_key : str | Nonevar model_configvar reporting_period : DatetimeRangevar usage : list[UsageItem]
Inherited members
class ReportUsageResponse (**data: Any)-
Expand source code
class ReportUsageResponse(AdCPBaseModel): model_config = ConfigDict( extra='allow', ) accepted: Annotated[ int, Field(description='Number of usage records successfully stored.', ge=0) ] context: context_1.ContextObject | None = None errors: Annotated[ list[error.Error] | None, Field( description="Validation errors for individual records. The field property identifies which record failed (e.g., 'usage[1].pricing_option_id')." ), ] = None ext: ext_1.ExtensionObject | None = None sandbox: Annotated[ bool | None, Field(description='When true, the account is a sandbox account and no billing occurred.'), ] = NoneBase model for AdCP types with spec-compliant serialization.
Defaults to
extra='ignore'so that unknown fields from newer spec versions are silently dropped rather than causing validation errors. Generated types whose schemas setadditionalProperties: trueoverride this withextra='allow'in their ownmodel_config. Consumers who want strict validation can override withextra='forbid'.Create a new model by parsing and validating input data from keyword arguments.
Raises [
ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.selfis explicitly positional-only to allowselfas a field name.Ancestors
- AdCPBaseModel
- pydantic.main.BaseModel
Class variables
var accepted : intvar context : ContextObject | Nonevar errors : list[Error] | Nonevar ext : ExtensionObject | Nonevar model_configvar sandbox : bool | None
Inherited members
class ResolvedBrand (**data: Any)-
Expand source code
class ResolvedBrand(BaseModel): """Brand identity resolved from the AdCP registry.""" model_config = ConfigDict(extra="allow") canonical_id: str canonical_domain: str brand_name: str names: list[dict[str, str]] | None = None keller_type: str | None = None parent_brand: str | None = None house_domain: str | None = None house_name: str | None = None brand_agent_url: str | None = None brand: dict[str, Any] | None = None brand_manifest: dict[str, Any] | None = None source: str @model_validator(mode="before") @classmethod def _normalize_brand_fields(cls, data: Any) -> Any: """Cross-populate brand and brand_manifest so both names are always accessible.""" if isinstance(data, dict): data = dict(data) if "brand" in data and "brand_manifest" not in data: data["brand_manifest"] = data["brand"] elif "brand_manifest" in data and "brand" not in data: data["brand"] = data["brand_manifest"] return dataBrand identity resolved from the AdCP registry.
Create a new model by parsing and validating input data from keyword arguments.
Raises [
ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.selfis explicitly positional-only to allowselfas a field name.Ancestors
- pydantic.main.BaseModel
Class variables
var brand : dict[str, typing.Any] | Nonevar brand_agent_url : str | Nonevar brand_manifest : dict[str, typing.Any] | Nonevar brand_name : strvar canonical_domain : strvar canonical_id : strvar house_domain : str | Nonevar house_name : str | Nonevar keller_type : str | Nonevar model_configvar names : list[dict[str, str]] | Nonevar parent_brand : str | Nonevar source : str
class ResolvedProperty (**data: Any)-
Expand source code
class ResolvedProperty(BaseModel): """Property information resolved from the AdCP registry.""" model_config = ConfigDict(extra="allow") publisher_domain: str source: str authorized_agents: list[dict[str, Any]] properties: list[dict[str, Any]] verified: boolProperty information resolved from the AdCP registry.
Create a new model by parsing and validating input data from keyword arguments.
Raises [
ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.selfis explicitly positional-only to allowselfas a field name.Ancestors
- pydantic.main.BaseModel
Class variables
var model_configvar properties : list[dict[str, typing.Any]]var publisher_domain : strvar source : strvar verified : bool
class SiSendActionResponseRequest (**data: Any)-
Expand source code
class SiSendMessageRequest(AdCPBaseModel): model_config = ConfigDict( extra='allow', ) action_response: Annotated[ ActionResponse | None, Field(description='Response to a previous action_button (e.g., user clicked checkout)'), ] = None ext: ext_1.ExtensionObject | None = None message: Annotated[str | None, Field(description="User's message to the brand agent")] = None session_id: Annotated[str, Field(description='Active session identifier')]Base model for AdCP types with spec-compliant serialization.
Defaults to
extra='ignore'so that unknown fields from newer spec versions are silently dropped rather than causing validation errors. Generated types whose schemas setadditionalProperties: trueoverride this withextra='allow'in their ownmodel_config. Consumers who want strict validation can override withextra='forbid'.Create a new model by parsing and validating input data from keyword arguments.
Raises [
ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.selfis explicitly positional-only to allowselfas a field name.Ancestors
- AdCPBaseModel
- pydantic.main.BaseModel
Class variables
var action_response : ActionResponse | Nonevar ext : ExtensionObject | Nonevar message : str | Nonevar model_configvar session_id : str
class SiSendTextMessageRequest (**data: Any)-
Expand source code
class SiSendMessageRequest(AdCPBaseModel): model_config = ConfigDict( extra='allow', ) action_response: Annotated[ ActionResponse | None, Field(description='Response to a previous action_button (e.g., user clicked checkout)'), ] = None ext: ext_1.ExtensionObject | None = None message: Annotated[str | None, Field(description="User's message to the brand agent")] = None session_id: Annotated[str, Field(description='Active session identifier')]Base model for AdCP types with spec-compliant serialization.
Defaults to
extra='ignore'so that unknown fields from newer spec versions are silently dropped rather than causing validation errors. Generated types whose schemas setadditionalProperties: trueoverride this withextra='allow'in their ownmodel_config. Consumers who want strict validation can override withextra='forbid'.Create a new model by parsing and validating input data from keyword arguments.
Raises [
ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.selfis explicitly positional-only to allowselfas a field name.Ancestors
- AdCPBaseModel
- pydantic.main.BaseModel
Class variables
var action_response : ActionResponse | Nonevar ext : ExtensionObject | Nonevar message : str | Nonevar model_configvar session_id : str
Inherited members
class SignalCatalogType (*args, **kwds)-
Expand source code
class SignalCatalogType(Enum): marketplace = 'marketplace' custom = 'custom' owned = 'owned'Create a collection of name/value pairs.
Example enumeration:
>>> class Color(Enum): ... RED = 1 ... BLUE = 2 ... GREEN = 3Access them by:
- attribute access::
>>> Color.RED <Color.RED: 1>- value lookup:
>>> Color(1) <Color.RED: 1>- name lookup:
>>> Color['RED'] <Color.RED: 1>Enumerations can be iterated over, and know how many members they have:
>>> len(Color) 3>>> list(Color) [<Color.RED: 1>, <Color.BLUE: 2>, <Color.GREEN: 3>]Methods can be added to enumerations, and members can have their own attributes – see the documentation for details.
Ancestors
- enum.Enum
Class variables
var customvar marketplacevar owned
class SignalFilters (**data: Any)-
Expand source code
class SignalFilters(AdCPBaseModel): model_config = ConfigDict( extra='allow', ) catalog_types: Annotated[ list[signal_catalog_type.SignalCatalogType] | None, Field(description='Filter by catalog type', min_length=1), ] = None data_providers: Annotated[ list[str] | None, Field(description='Filter by specific data providers', min_length=1) ] = None max_cpm: Annotated[ float | None, Field(description="Maximum CPM filter. Applies only to signals with model='cpm'.", ge=0.0), ] = None max_percent: Annotated[ float | None, Field( description='Maximum percent-of-media rate filter. Signals where all percent_of_media pricing options exceed this value are excluded. Does not account for max_cpm caps.', ge=0.0, le=100.0, ), ] = None min_coverage_percentage: Annotated[ float | None, Field(description='Minimum coverage requirement', ge=0.0, le=100.0) ] = NoneBase model for AdCP types with spec-compliant serialization.
Defaults to
extra='ignore'so that unknown fields from newer spec versions are silently dropped rather than causing validation errors. Generated types whose schemas setadditionalProperties: trueoverride this withextra='allow'in their ownmodel_config. Consumers who want strict validation can override withextra='forbid'.Create a new model by parsing and validating input data from keyword arguments.
Raises [
ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.selfis explicitly positional-only to allowselfas a field name.Ancestors
- AdCPBaseModel
- pydantic.main.BaseModel
Class variables
var catalog_types : list[SignalCatalogType] | Nonevar data_providers : list[str] | Nonevar max_cpm : float | Nonevar max_percent : float | Nonevar min_coverage_percentage : float | Nonevar model_config
Inherited members
class SignalPricing (root: RootModelRootType = PydanticUndefined, **data)-
Expand source code
class SignalPricing(RootModel[SignalPricing1 | SignalPricing2 | SignalPricing3]): root: Annotated[ SignalPricing1 | SignalPricing2 | SignalPricing3, Field( description="Pricing model for a signal. Discriminated by model: 'cpm' (fixed CPM), 'percent_of_media' (percentage of spend with optional CPM cap), or 'flat_fee' (fixed charge per reporting period, e.g. monthly licensed segments).", title='Signal Pricing', ), ] def __getattr__(self, name: str) -> Any: """Proxy attribute access to the wrapped type.""" if name.startswith('_'): raise AttributeError(name) return getattr(self.root, name)Usage Documentation
A Pydantic
BaseModelfor the root object of the model.Attributes
root- The root object of the model.
__pydantic_root_model__- Whether the model is a RootModel.
__pydantic_private__- Private fields in the model.
__pydantic_extra__- Extra fields in the model.
Create a new model by parsing and validating input data from keyword arguments.
Raises [
ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.selfis explicitly positional-only to allowselfas a field name.Ancestors
- pydantic.root_model.RootModel[Union[SignalPricing1, SignalPricing2, SignalPricing3]]
- pydantic.root_model.RootModel
- pydantic.main.BaseModel
- typing.Generic
Class variables
var model_configvar root : SignalPricing1 | SignalPricing2 | SignalPricing3
class SignalPricingOption (root: RootModelRootType = PydanticUndefined, **data)-
Expand source code
class SignalPricingOption( RootModel[SignalPricingOption5 | SignalPricingOption6 | SignalPricingOption7] ): root: Annotated[ SignalPricingOption5 | SignalPricingOption6 | SignalPricingOption7, Field( description='A pricing option offered by a signals agent. Combines pricing_option_id with the signal pricing model fields at the same level — pass pricing_option_id in report_usage for billing verification.', title='Signal Pricing Option', ), ] def __getattr__(self, name: str) -> Any: """Proxy attribute access to the wrapped type.""" if name.startswith('_'): raise AttributeError(name) return getattr(self.root, name)Usage Documentation
A Pydantic
BaseModelfor the root object of the model.Attributes
root- The root object of the model.
__pydantic_root_model__- Whether the model is a RootModel.
__pydantic_private__- Private fields in the model.
__pydantic_extra__- Extra fields in the model.
Create a new model by parsing and validating input data from keyword arguments.
Raises [
ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.selfis explicitly positional-only to allowselfas a field name.Ancestors
- pydantic.root_model.RootModel[Union[SignalPricingOption5, SignalPricingOption6, SignalPricingOption7]]
- pydantic.root_model.RootModel
- pydantic.main.BaseModel
- typing.Generic
Class variables
var model_configvar root : SignalPricingOption5 | SignalPricingOption6 | SignalPricingOption7
class CpmSignalPricingOption (**data: Any)-
Expand source code
class SignalPricingOption5(SignalPricingOption1, SignalPricingOption4): passBase model for AdCP types with spec-compliant serialization.
Defaults to
extra='ignore'so that unknown fields from newer spec versions are silently dropped rather than causing validation errors. Generated types whose schemas setadditionalProperties: trueoverride this withextra='allow'in their ownmodel_config. Consumers who want strict validation can override withextra='forbid'.Create a new model by parsing and validating input data from keyword arguments.
Raises [
ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.selfis explicitly positional-only to allowselfas a field name.Ancestors
- SignalPricingOption1
- SignalPricingOption4
- AdCPBaseModel
- pydantic.main.BaseModel
Class variables
var model_config
Inherited members
class PercentOfMediaSignalPricingOption (**data: Any)-
Expand source code
class SignalPricingOption6(SignalPricingOption2, SignalPricingOption4): passBase model for AdCP types with spec-compliant serialization.
Defaults to
extra='ignore'so that unknown fields from newer spec versions are silently dropped rather than causing validation errors. Generated types whose schemas setadditionalProperties: trueoverride this withextra='allow'in their ownmodel_config. Consumers who want strict validation can override withextra='forbid'.Create a new model by parsing and validating input data from keyword arguments.
Raises [
ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.selfis explicitly positional-only to allowselfas a field name.Ancestors
- SignalPricingOption2
- SignalPricingOption4
- AdCPBaseModel
- pydantic.main.BaseModel
Class variables
var model_config
Inherited members
class FlatFeeSignalPricingOption (**data: Any)-
Expand source code
class SignalPricingOption7(SignalPricingOption3, SignalPricingOption4): passBase model for AdCP types with spec-compliant serialization.
Defaults to
extra='ignore'so that unknown fields from newer spec versions are silently dropped rather than causing validation errors. Generated types whose schemas setadditionalProperties: trueoverride this withextra='allow'in their ownmodel_config. Consumers who want strict validation can override withextra='forbid'.Create a new model by parsing and validating input data from keyword arguments.
Raises [
ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.selfis explicitly positional-only to allowselfas a field name.Ancestors
- SignalPricingOption3
- SignalPricingOption4
- AdCPBaseModel
- pydantic.main.BaseModel
Class variables
var model_config
Inherited members
class Snapshot (**data: Any)-
Expand source code
class Snapshot(AdCPBaseModel): model_config = ConfigDict( extra='allow', ) as_of: Annotated[ AwareDatetime, Field(description='When this snapshot was captured by the platform') ] impressions: Annotated[ int, Field( description='Lifetime impressions across all assignments. Not scoped to any date range.', ge=0, ), ] last_served: Annotated[ AwareDatetime | None, Field( description='Last time this creative served an impression. Absent when the creative has never served.' ), ] = None staleness_seconds: Annotated[ int, Field( description='Maximum age of this data in seconds. For example, 3600 means the data may be up to 1 hour old.', ge=0, ), ]Base model for AdCP types with spec-compliant serialization.
Defaults to
extra='ignore'so that unknown fields from newer spec versions are silently dropped rather than causing validation errors. Generated types whose schemas setadditionalProperties: trueoverride this withextra='allow'in their ownmodel_config. Consumers who want strict validation can override withextra='forbid'.Create a new model by parsing and validating input data from keyword arguments.
Raises [
ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.selfis explicitly positional-only to allowselfas a field name.Ancestors
- AdCPBaseModel
- pydantic.main.BaseModel
Class variables
var as_of : pydantic.types.AwareDatetimevar impressions : intvar last_served : pydantic.types.AwareDatetime | Nonevar model_configvar staleness_seconds : int
Inherited members
-
Expand source code
class SnapshotUnavailableReason(Enum): SNAPSHOT_UNSUPPORTED = 'SNAPSHOT_UNSUPPORTED' SNAPSHOT_TEMPORARILY_UNAVAILABLE = 'SNAPSHOT_TEMPORARILY_UNAVAILABLE' SNAPSHOT_PERMISSION_DENIED = 'SNAPSHOT_PERMISSION_DENIED'Create a collection of name/value pairs.
Example enumeration:
>>> class Color(Enum): ... RED = 1 ... BLUE = 2 ... GREEN = 3Access them by:
- attribute access::
>>> Color.RED <Color.RED: 1>- value lookup:
>>> Color(1) <Color.RED: 1>- name lookup:
>>> Color['RED'] <Color.RED: 1>Enumerations can be iterated over, and know how many members they have:
>>> len(Color) 3>>> list(Color) [<Color.RED: 1>, <Color.BLUE: 2>, <Color.GREEN: 3>]Methods can be added to enumerations, and members can have their own attributes – see the documentation for details.
Ancestors
- enum.Enum
Class variables
class MediaBuyDeliveryStatus (*args, **kwds)-
Expand source code
class Status(Enum): pending_activation = 'pending_activation' pending = 'pending' active = 'active' paused = 'paused' completed = 'completed' rejected = 'rejected' canceled = 'canceled' failed = 'failed' reporting_delayed = 'reporting_delayed'Create a collection of name/value pairs.
Example enumeration:
>>> class Color(Enum): ... RED = 1 ... BLUE = 2 ... GREEN = 3Access them by:
- attribute access::
>>> Color.RED <Color.RED: 1>- value lookup:
>>> Color(1) <Color.RED: 1>- name lookup:
>>> Color['RED'] <Color.RED: 1>Enumerations can be iterated over, and know how many members they have:
>>> len(Color) 3>>> list(Color) [<Color.RED: 1>, <Color.BLUE: 2>, <Color.GREEN: 3>]Methods can be added to enumerations, and members can have their own attributes – see the documentation for details.
Ancestors
- enum.Enum
Class variables
var activevar canceledvar completedvar failedvar pausedvar pendingvar pending_activationvar rejectedvar reporting_delayed
class SyncAccountsRequest (**data: Any)-
Expand source code
class SyncAccountsRequest(AdCPBaseModel): model_config = ConfigDict( extra='allow', ) accounts: Annotated[ list[Account], Field(description='Advertiser accounts to sync', max_length=1000) ] context: context_1.ContextObject | None = None delete_missing: Annotated[ bool | None, Field( description='When true, accounts previously synced by this agent but not included in this request will be deactivated. Scoped to the authenticated agent — does not affect accounts managed by other agents. Use with caution.' ), ] = False dry_run: Annotated[ bool | None, Field( description='When true, preview what would change without applying. Returns what would be created/updated/deactivated.' ), ] = False ext: ext_1.ExtensionObject | None = None push_notification_config: Annotated[ push_notification_config_1.PushNotificationConfig | None, Field( description='Webhook for async notifications when account status changes (e.g., pending_approval transitions to active).' ), ] = NoneBase model for AdCP types with spec-compliant serialization.
Defaults to
extra='ignore'so that unknown fields from newer spec versions are silently dropped rather than causing validation errors. Generated types whose schemas setadditionalProperties: trueoverride this withextra='allow'in their ownmodel_config. Consumers who want strict validation can override withextra='forbid'.Create a new model by parsing and validating input data from keyword arguments.
Raises [
ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.selfis explicitly positional-only to allowselfas a field name.Ancestors
- AdCPBaseModel
- pydantic.main.BaseModel
Class variables
var accounts : list[Account]var context : ContextObject | Nonevar delete_missing : bool | Nonevar dry_run : bool | Nonevar ext : ExtensionObject | Nonevar model_configvar push_notification_config : PushNotificationConfig | None
Inherited members
class SyncAccountsSuccessResponse (**data: Any)-
Expand source code
class SyncAccountsResponse1(AdCPBaseModel): model_config = ConfigDict( extra='allow', ) accounts: Annotated[list[Account], Field(description='Results for each account processed')] context: context_1.ContextObject | None = None dry_run: Annotated[ bool | None, Field(description='Whether this was a dry run (no actual changes made)') ] = None ext: ext_1.ExtensionObject | None = NoneBase model for AdCP types with spec-compliant serialization.
Defaults to
extra='ignore'so that unknown fields from newer spec versions are silently dropped rather than causing validation errors. Generated types whose schemas setadditionalProperties: trueoverride this withextra='allow'in their ownmodel_config. Consumers who want strict validation can override withextra='forbid'.Create a new model by parsing and validating input data from keyword arguments.
Raises [
ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.selfis explicitly positional-only to allowselfas a field name.Ancestors
- AdCPBaseModel
- pydantic.main.BaseModel
Class variables
var accounts : list[Account]var context : ContextObject | Nonevar dry_run : bool | Nonevar ext : ExtensionObject | Nonevar model_config
Inherited members
class SyncAccountsErrorResponse (**data: Any)-
Expand source code
class SyncAccountsResponse2(AdCPBaseModel): model_config = ConfigDict( extra='allow', ) context: context_1.ContextObject | None = None errors: Annotated[ list[error.Error], Field( description='Operation-level errors (e.g., authentication failure, service unavailable)', min_length=1, ), ] ext: ext_1.ExtensionObject | None = NoneBase model for AdCP types with spec-compliant serialization.
Defaults to
extra='ignore'so that unknown fields from newer spec versions are silently dropped rather than causing validation errors. Generated types whose schemas setadditionalProperties: trueoverride this withextra='allow'in their ownmodel_config. Consumers who want strict validation can override withextra='forbid'.Create a new model by parsing and validating input data from keyword arguments.
Raises [
ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.selfis explicitly positional-only to allowselfas a field name.Ancestors
- AdCPBaseModel
- pydantic.main.BaseModel
Class variables
var context : ContextObject | Nonevar errors : list[Error]var ext : ExtensionObject | Nonevar model_config
Inherited members
class SyncAudiencesRequest (**data: Any)-
Expand source code
class SyncAudiencesRequest(AdCPBaseModel): model_config = ConfigDict( extra='allow', ) account: Annotated[ account_ref.AccountReference, Field(description='Account to manage audiences for.') ] audiences: Annotated[ list[Audience] | None, Field( description='Audiences to sync (create or update). When omitted, the call is discovery-only and returns all existing audiences on the account without modification.', min_length=1, ), ] = None context: context_1.ContextObject | None = None delete_missing: Annotated[ bool | None, Field( description='When true, buyer-managed audiences on the account not included in this sync will be removed. Does not affect seller-managed audiences. Do not combine with an omitted audiences array or all buyer-managed audiences will be deleted.' ), ] = False ext: ext_1.ExtensionObject | None = NoneBase model for AdCP types with spec-compliant serialization.
Defaults to
extra='ignore'so that unknown fields from newer spec versions are silently dropped rather than causing validation errors. Generated types whose schemas setadditionalProperties: trueoverride this withextra='allow'in their ownmodel_config. Consumers who want strict validation can override withextra='forbid'.Create a new model by parsing and validating input data from keyword arguments.
Raises [
ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.selfis explicitly positional-only to allowselfas a field name.Ancestors
- AdCPBaseModel
- pydantic.main.BaseModel
Class variables
var account : AccountReferencevar audiences : list[Audience] | Nonevar context : ContextObject | Nonevar delete_missing : bool | Nonevar ext : ExtensionObject | Nonevar model_config
Inherited members
class SyncAudiencesSuccessResponse (**data: Any)-
Expand source code
class SyncAudiencesResponse1(AdCPBaseModel): model_config = ConfigDict( extra='allow', ) audiences: Annotated[ list[Audience], Field(description='Results for each audience on the account') ] context: context_1.ContextObject | None = None ext: ext_1.ExtensionObject | None = None sandbox: Annotated[ bool | None, Field(description='When true, this response contains simulated data from sandbox mode.'), ] = NoneBase model for AdCP types with spec-compliant serialization.
Defaults to
extra='ignore'so that unknown fields from newer spec versions are silently dropped rather than causing validation errors. Generated types whose schemas setadditionalProperties: trueoverride this withextra='allow'in their ownmodel_config. Consumers who want strict validation can override withextra='forbid'.Create a new model by parsing and validating input data from keyword arguments.
Raises [
ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.selfis explicitly positional-only to allowselfas a field name.Ancestors
- AdCPBaseModel
- pydantic.main.BaseModel
Class variables
var audiences : list[Audience]var context : ContextObject | Nonevar ext : ExtensionObject | Nonevar model_configvar sandbox : bool | None
Inherited members
class SyncAudiencesErrorResponse (**data: Any)-
Expand source code
class SyncAudiencesResponse2(AdCPBaseModel): model_config = ConfigDict( extra='allow', ) context: context_1.ContextObject | None = None errors: Annotated[ list[error.Error], Field(description='Operation-level errors that prevented processing', min_length=1), ] ext: ext_1.ExtensionObject | None = NoneBase model for AdCP types with spec-compliant serialization.
Defaults to
extra='ignore'so that unknown fields from newer spec versions are silently dropped rather than causing validation errors. Generated types whose schemas setadditionalProperties: trueoverride this withextra='allow'in their ownmodel_config. Consumers who want strict validation can override withextra='forbid'.Create a new model by parsing and validating input data from keyword arguments.
Raises [
ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.selfis explicitly positional-only to allowselfas a field name.Ancestors
- AdCPBaseModel
- pydantic.main.BaseModel
Class variables
var context : ContextObject | Nonevar errors : list[Error]var ext : ExtensionObject | Nonevar model_config
Inherited members
class SyncCatalogsInputRequired (**data: Any)-
Expand source code
class SyncCatalogsInputRequired(AdCPBaseModel): model_config = ConfigDict( extra='allow', ) context: context_1.ContextObject | None = None ext: ext_1.ExtensionObject | None = None reason: Annotated[ Reason | None, Field( description='Reason code indicating why buyer input is needed. APPROVAL_REQUIRED: platform requires explicit approval before activating the catalog. FEED_VALIDATION: feed URL returned unexpected format or schema errors. ITEM_REVIEW: platform flagged items for manual review. FEED_ACCESS: platform cannot access the feed URL (authentication, CORS, etc.).' ), ] = NoneBase model for AdCP types with spec-compliant serialization.
Defaults to
extra='ignore'so that unknown fields from newer spec versions are silently dropped rather than causing validation errors. Generated types whose schemas setadditionalProperties: trueoverride this withextra='allow'in their ownmodel_config. Consumers who want strict validation can override withextra='forbid'.Create a new model by parsing and validating input data from keyword arguments.
Raises [
ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.selfis explicitly positional-only to allowselfas a field name.Ancestors
- AdCPBaseModel
- pydantic.main.BaseModel
Class variables
var context : ContextObject | Nonevar ext : ExtensionObject | Nonevar model_configvar reason : Reason | None
Inherited members
class SyncCatalogsRequest (**data: Any)-
Expand source code
class SyncCatalogsRequest(AdCPBaseModel): model_config = ConfigDict( extra='allow', ) account: Annotated[ account_ref.AccountReference, Field(description='Account that owns these catalogs.') ] catalog_ids: Annotated[ list[str] | None, Field( description='Optional filter to limit sync scope to specific catalog IDs. When provided, only these catalogs will be created/updated. Other catalogs on the account are unaffected.', max_length=50, min_length=1, ), ] = None catalogs: Annotated[ list[catalog.Catalog] | None, Field( description='Array of catalog feeds to sync (create or update). When omitted, the call is discovery-only and returns all existing catalogs on the account without modification.', max_length=50, min_length=1, ), ] = None context: context_1.ContextObject | None = None delete_missing: Annotated[ bool | None, Field( description='When true, buyer-managed catalogs on the account not included in this sync will be removed. Does not affect seller-managed catalogs. Do not combine with an omitted catalogs array or all buyer-managed catalogs will be deleted.' ), ] = False dry_run: Annotated[ bool | None, Field( description='When true, preview changes without applying them. Returns what would be created/updated/deleted.' ), ] = False ext: ext_1.ExtensionObject | None = None push_notification_config: Annotated[ push_notification_config_1.PushNotificationConfig | None, Field( description='Optional webhook configuration for async sync notifications. Publisher will send webhook when sync completes if operation takes longer than immediate response time (common for large feeds requiring platform review).' ), ] = None validation_mode: Annotated[ validation_mode_1.ValidationMode | None, Field( description="Validation strictness. 'strict' fails entire sync on any validation error. 'lenient' processes valid catalogs and reports errors." ), ] = validation_mode_1.ValidationMode.strictBase model for AdCP types with spec-compliant serialization.
Defaults to
extra='ignore'so that unknown fields from newer spec versions are silently dropped rather than causing validation errors. Generated types whose schemas setadditionalProperties: trueoverride this withextra='allow'in their ownmodel_config. Consumers who want strict validation can override withextra='forbid'.Create a new model by parsing and validating input data from keyword arguments.
Raises [
ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.selfis explicitly positional-only to allowselfas a field name.Ancestors
- AdCPBaseModel
- pydantic.main.BaseModel
Class variables
var account : AccountReferencevar catalog_ids : list[str] | Nonevar catalogs : list[Catalog] | Nonevar context : ContextObject | Nonevar delete_missing : bool | Nonevar dry_run : bool | Nonevar ext : ExtensionObject | Nonevar model_configvar push_notification_config : PushNotificationConfig | Nonevar validation_mode : ValidationMode | None
Inherited members
class SyncCatalogsSuccessResponse (**data: Any)-
Expand source code
class SyncCatalogsResponse1(AdCPBaseModel): model_config = ConfigDict( extra='allow', ) catalogs: Annotated[ list[Catalog], Field( description="Results for each catalog processed. Items with action='failed' indicate per-catalog validation/processing failures, not operation-level failures." ), ] context: context_1.ContextObject | None = None dry_run: Annotated[ bool | None, Field(description='Whether this was a dry run (no actual changes made)') ] = None ext: ext_1.ExtensionObject | None = None sandbox: Annotated[ bool | None, Field(description='When true, this response contains simulated data from sandbox mode.'), ] = NoneBase model for AdCP types with spec-compliant serialization.
Defaults to
extra='ignore'so that unknown fields from newer spec versions are silently dropped rather than causing validation errors. Generated types whose schemas setadditionalProperties: trueoverride this withextra='allow'in their ownmodel_config. Consumers who want strict validation can override withextra='forbid'.Create a new model by parsing and validating input data from keyword arguments.
Raises [
ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.selfis explicitly positional-only to allowselfas a field name.Ancestors
- AdCPBaseModel
- pydantic.main.BaseModel
Class variables
var catalogs : list[Catalog]var context : ContextObject | Nonevar dry_run : bool | Nonevar ext : ExtensionObject | Nonevar model_configvar sandbox : bool | None
Inherited members
class SyncCatalogsErrorResponse (**data: Any)-
Expand source code
class SyncCatalogsResponse2(AdCPBaseModel): model_config = ConfigDict( extra='allow', ) context: context_1.ContextObject | None = None errors: Annotated[ list[error.Error], Field( description='Operation-level errors that prevented processing any catalogs (e.g., authentication failure, service unavailable, invalid request format)', min_length=1, ), ] ext: ext_1.ExtensionObject | None = NoneBase model for AdCP types with spec-compliant serialization.
Defaults to
extra='ignore'so that unknown fields from newer spec versions are silently dropped rather than causing validation errors. Generated types whose schemas setadditionalProperties: trueoverride this withextra='allow'in their ownmodel_config. Consumers who want strict validation can override withextra='forbid'.Create a new model by parsing and validating input data from keyword arguments.
Raises [
ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.selfis explicitly positional-only to allowselfas a field name.Ancestors
- AdCPBaseModel
- pydantic.main.BaseModel
Class variables
var context : ContextObject | Nonevar errors : list[Error]var ext : ExtensionObject | Nonevar model_config
Inherited members
class SyncCatalogsSubmitted (**data: Any)-
Expand source code
class SyncCatalogsSubmitted(AdCPBaseModel): model_config = ConfigDict( extra='allow', ) context: context_1.ContextObject | None = None ext: ext_1.ExtensionObject | None = NoneBase model for AdCP types with spec-compliant serialization.
Defaults to
extra='ignore'so that unknown fields from newer spec versions are silently dropped rather than causing validation errors. Generated types whose schemas setadditionalProperties: trueoverride this withextra='allow'in their ownmodel_config. Consumers who want strict validation can override withextra='forbid'.Create a new model by parsing and validating input data from keyword arguments.
Raises [
ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.selfis explicitly positional-only to allowselfas a field name.Ancestors
- AdCPBaseModel
- pydantic.main.BaseModel
Class variables
var context : ContextObject | Nonevar ext : ExtensionObject | Nonevar model_config
Inherited members
class SyncCatalogsWorking (**data: Any)-
Expand source code
class SyncCatalogsWorking(AdCPBaseModel): model_config = ConfigDict( extra='allow', ) catalogs_processed: Annotated[ int | None, Field(description='Number of catalogs processed so far', ge=0) ] = None catalogs_total: Annotated[ int | None, Field(description='Total number of catalogs to process', ge=0) ] = None context: context_1.ContextObject | None = None current_step: Annotated[ str | None, Field( description="Current step or phase of the operation (e.g., 'Fetching product feed', 'Validating items', 'Platform review')" ), ] = None ext: ext_1.ExtensionObject | None = None items_processed: Annotated[ int | None, Field(description='Total number of catalog items processed across all catalogs', ge=0), ] = None items_total: Annotated[ int | None, Field(description='Total number of catalog items to process across all catalogs', ge=0), ] = None percentage: Annotated[ float | None, Field(description='Completion percentage (0-100)', ge=0.0, le=100.0) ] = None step_number: Annotated[int | None, Field(description='Current step number', ge=1)] = None total_steps: Annotated[ int | None, Field(description='Total number of steps in the operation', ge=1) ] = NoneBase model for AdCP types with spec-compliant serialization.
Defaults to
extra='ignore'so that unknown fields from newer spec versions are silently dropped rather than causing validation errors. Generated types whose schemas setadditionalProperties: trueoverride this withextra='allow'in their ownmodel_config. Consumers who want strict validation can override withextra='forbid'.Create a new model by parsing and validating input data from keyword arguments.
Raises [
ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.selfis explicitly positional-only to allowselfas a field name.Ancestors
- AdCPBaseModel
- pydantic.main.BaseModel
Class variables
var catalogs_processed : int | Nonevar catalogs_total : int | Nonevar context : ContextObject | Nonevar current_step : str | Nonevar ext : ExtensionObject | Nonevar items_processed : int | Nonevar items_total : int | Nonevar model_configvar percentage : float | Nonevar step_number : int | Nonevar total_steps : int | None
Inherited members
class SyncCreativesRequest (**data: Any)-
Expand source code
class SyncCreativesRequest(AdCPBaseModel): model_config = ConfigDict( extra='allow', ) account: Annotated[ account_ref.AccountReference, Field(description='Account that owns these creatives.') ] assignments: Annotated[ list[Assignment] | None, Field( description='Optional bulk assignment of creatives to packages. Each entry maps one creative to one package with optional weight and placement targeting. Standalone creative agents that do not manage media buys ignore this field.', min_length=1, ), ] = None context: context_1.ContextObject | None = None creative_ids: Annotated[ list[str] | None, Field( description='Optional filter to limit sync scope to specific creative IDs. When provided, only these creatives will be created/updated. Other creatives in the library are unaffected. Useful for partial updates and error recovery.', max_length=100, min_length=1, ), ] = None creatives: Annotated[ list[creative_asset.CreativeAsset], Field( description='Array of creative assets to sync (create or update)', max_length=100, min_length=1, ), ] delete_missing: Annotated[ bool | None, Field( description='When true, creatives not included in this sync will be archived. Use with caution for full library replacement. Invalid when creative_ids is provided — delete_missing applies to the entire library scope, not a filtered subset.' ), ] = False dry_run: Annotated[ bool | None, Field( description='When true, preview changes without applying them. Returns what would be created/updated/deleted.' ), ] = False ext: ext_1.ExtensionObject | None = None idempotency_key: Annotated[ str | None, Field( description='Client-generated idempotency key for safe retries. If a sync fails without a response, resending with the same idempotency_key guarantees at-most-once execution. MUST be unique per (seller, request) pair to prevent cross-seller correlation. Use a fresh UUID v4 for each request.', max_length=255, min_length=16, ), ] = None push_notification_config: Annotated[ push_notification_config_1.PushNotificationConfig | None, Field( description='Optional webhook configuration for async sync notifications. The agent will send a webhook when sync completes if the operation takes longer than immediate response time (typically for large bulk operations or manual approval/HITL).' ), ] = None validation_mode: Annotated[ validation_mode_1.ValidationMode | None, Field( description="Validation strictness. 'strict' fails entire sync on any validation error. 'lenient' processes valid creatives and reports errors." ), ] = validation_mode_1.ValidationMode.strictBase model for AdCP types with spec-compliant serialization.
Defaults to
extra='ignore'so that unknown fields from newer spec versions are silently dropped rather than causing validation errors. Generated types whose schemas setadditionalProperties: trueoverride this withextra='allow'in their ownmodel_config. Consumers who want strict validation can override withextra='forbid'.Create a new model by parsing and validating input data from keyword arguments.
Raises [
ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.selfis explicitly positional-only to allowselfas a field name.Ancestors
- AdCPBaseModel
- pydantic.main.BaseModel
Class variables
var account : AccountReferencevar assignments : list[Assignment] | Nonevar context : ContextObject | Nonevar creative_ids : list[str] | Nonevar creatives : list[CreativeAsset]var delete_missing : bool | Nonevar dry_run : bool | Nonevar ext : ExtensionObject | Nonevar idempotency_key : str | Nonevar model_configvar push_notification_config : PushNotificationConfig | Nonevar validation_mode : ValidationMode | None
Inherited members
class SyncCreativesSuccessResponse (**data: Any)-
Expand source code
class SyncCreativesResponse1(AdCPBaseModel): model_config = ConfigDict( extra='allow', ) context: context_1.ContextObject | None = None creatives: Annotated[ list[Creative], Field( description="Results for each creative processed. Items with action='failed' indicate per-item validation/processing failures, not operation-level failures." ), ] dry_run: Annotated[ bool | None, Field(description='Whether this was a dry run (no actual changes made)') ] = None ext: ext_1.ExtensionObject | None = None sandbox: Annotated[ bool | None, Field(description='When true, this response contains simulated data from sandbox mode.'), ] = NoneBase model for AdCP types with spec-compliant serialization.
Defaults to
extra='ignore'so that unknown fields from newer spec versions are silently dropped rather than causing validation errors. Generated types whose schemas setadditionalProperties: trueoverride this withextra='allow'in their ownmodel_config. Consumers who want strict validation can override withextra='forbid'.Create a new model by parsing and validating input data from keyword arguments.
Raises [
ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.selfis explicitly positional-only to allowselfas a field name.Ancestors
- AdCPBaseModel
- pydantic.main.BaseModel
Class variables
var context : ContextObject | Nonevar creatives : list[Creative]var dry_run : bool | Nonevar ext : ExtensionObject | Nonevar model_configvar sandbox : bool | None
Inherited members
class SyncCreativesErrorResponse (**data: Any)-
Expand source code
class SyncCreativesResponse2(AdCPBaseModel): model_config = ConfigDict( extra='allow', ) context: context_1.ContextObject | None = None errors: Annotated[ list[error.Error], Field( description='Operation-level errors that prevented processing any creatives (e.g., authentication failure, service unavailable, invalid request format)', min_length=1, ), ] ext: ext_1.ExtensionObject | None = NoneBase model for AdCP types with spec-compliant serialization.
Defaults to
extra='ignore'so that unknown fields from newer spec versions are silently dropped rather than causing validation errors. Generated types whose schemas setadditionalProperties: trueoverride this withextra='allow'in their ownmodel_config. Consumers who want strict validation can override withextra='forbid'.Create a new model by parsing and validating input data from keyword arguments.
Raises [
ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.selfis explicitly positional-only to allowselfas a field name.Ancestors
- AdCPBaseModel
- pydantic.main.BaseModel
Class variables
var context : ContextObject | Nonevar errors : list[Error]var ext : ExtensionObject | Nonevar model_config
Inherited members
class SyncEventSourcesRequest (**data: Any)-
Expand source code
class SyncEventSourcesRequest(AdCPBaseModel): model_config = ConfigDict( extra='allow', ) account: Annotated[ account_ref.AccountReference, Field(description='Account to configure event sources for.') ] context: context_1.ContextObject | None = None delete_missing: Annotated[ bool | None, Field(description='When true, event sources not included in this sync will be removed'), ] = False event_sources: Annotated[ list[EventSource] | None, Field( description='Event sources to sync (create or update). When omitted, the call is discovery-only and returns all existing event sources on the account without modification.', min_length=1, ), ] = None ext: ext_1.ExtensionObject | None = NoneBase model for AdCP types with spec-compliant serialization.
Defaults to
extra='ignore'so that unknown fields from newer spec versions are silently dropped rather than causing validation errors. Generated types whose schemas setadditionalProperties: trueoverride this withextra='allow'in their ownmodel_config. Consumers who want strict validation can override withextra='forbid'.Create a new model by parsing and validating input data from keyword arguments.
Raises [
ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.selfis explicitly positional-only to allowselfas a field name.Ancestors
- AdCPBaseModel
- pydantic.main.BaseModel
Class variables
var account : AccountReferencevar context : ContextObject | Nonevar delete_missing : bool | Nonevar event_sources : list[EventSource] | Nonevar ext : ExtensionObject | Nonevar model_config
Inherited members
class SyncEventSourcesSuccessResponse (**data: Any)-
Expand source code
class SyncEventSourcesResponse1(AdCPBaseModel): model_config = ConfigDict( extra='allow', ) context: context_1.ContextObject | None = None event_sources: Annotated[ list[EventSource], Field( description='Results for each event source, including both synced and seller-managed sources on the account' ), ] ext: ext_1.ExtensionObject | None = None sandbox: Annotated[ bool | None, Field(description='When true, this response contains simulated data from sandbox mode.'), ] = NoneBase model for AdCP types with spec-compliant serialization.
Defaults to
extra='ignore'so that unknown fields from newer spec versions are silently dropped rather than causing validation errors. Generated types whose schemas setadditionalProperties: trueoverride this withextra='allow'in their ownmodel_config. Consumers who want strict validation can override withextra='forbid'.Create a new model by parsing and validating input data from keyword arguments.
Raises [
ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.selfis explicitly positional-only to allowselfas a field name.Ancestors
- AdCPBaseModel
- pydantic.main.BaseModel
Class variables
var context : ContextObject | Nonevar event_sources : list[EventSource]var ext : ExtensionObject | Nonevar model_configvar sandbox : bool | None
Inherited members
class SyncEventSourcesErrorResponse (**data: Any)-
Expand source code
class SyncEventSourcesResponse2(AdCPBaseModel): model_config = ConfigDict( extra='allow', ) context: context_1.ContextObject | None = None errors: Annotated[ list[error.Error], Field(description='Operation-level errors that prevented processing', min_length=1), ] ext: ext_1.ExtensionObject | None = NoneBase model for AdCP types with spec-compliant serialization.
Defaults to
extra='ignore'so that unknown fields from newer spec versions are silently dropped rather than causing validation errors. Generated types whose schemas setadditionalProperties: trueoverride this withextra='allow'in their ownmodel_config. Consumers who want strict validation can override withextra='forbid'.Create a new model by parsing and validating input data from keyword arguments.
Raises [
ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.selfis explicitly positional-only to allowselfas a field name.Ancestors
- AdCPBaseModel
- pydantic.main.BaseModel
Class variables
var context : ContextObject | Nonevar errors : list[Error]var ext : ExtensionObject | Nonevar model_config
Inherited members
class SyncPlansRequest (**data: Any)-
Expand source code
class SyncPlansRequest(AdCPBaseModel): model_config = ConfigDict( extra='forbid', ) plans: Annotated[list[Plan], Field(description='One or more campaign plans to sync.')]Base model for AdCP types with spec-compliant serialization.
Defaults to
extra='ignore'so that unknown fields from newer spec versions are silently dropped rather than causing validation errors. Generated types whose schemas setadditionalProperties: trueoverride this withextra='allow'in their ownmodel_config. Consumers who want strict validation can override withextra='forbid'.Create a new model by parsing and validating input data from keyword arguments.
Raises [
ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.selfis explicitly positional-only to allowselfas a field name.Ancestors
- AdCPBaseModel
- pydantic.main.BaseModel
Class variables
var model_configvar plans : list[Plan]
Inherited members
class SyncPlansResponse (**data: Any)-
Expand source code
class SyncPlansResponse(AdCPBaseModel): model_config = ConfigDict( extra='forbid', ) plans: Annotated[list[Plan], Field(description='Status for each synced plan.')]Base model for AdCP types with spec-compliant serialization.
Defaults to
extra='ignore'so that unknown fields from newer spec versions are silently dropped rather than causing validation errors. Generated types whose schemas setadditionalProperties: trueoverride this withextra='allow'in their ownmodel_config. Consumers who want strict validation can override withextra='forbid'.Create a new model by parsing and validating input data from keyword arguments.
Raises [
ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.selfis explicitly positional-only to allowselfas a field name.Ancestors
- AdCPBaseModel
- pydantic.main.BaseModel
Class variables
var model_configvar plans : list[Plan]
Inherited members
class TaskResult (**data: Any)-
Expand source code
class TaskResult(BaseModel, Generic[T]): """Result from task execution.""" model_config = ConfigDict(arbitrary_types_allowed=True) status: TaskStatus data: T | None = None message: str | None = None # Human-readable message from agent (e.g., MCP content text) submitted: SubmittedInfo | None = None needs_input: NeedsInputInfo | None = None error: str | None = None success: bool = Field(default=True) metadata: dict[str, Any] | None = None debug_info: DebugInfo | None = NoneResult from task execution.
Create a new model by parsing and validating input data from keyword arguments.
Raises [
ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.selfis explicitly positional-only to allowselfas a field name.Ancestors
- pydantic.main.BaseModel
- typing.Generic
Subclasses
- adcp.types.core.TaskResult[AdcpAsyncResponseData]
- adcp.types.core.TaskResult[CheckGovernanceResponse]
- adcp.types.core.TaskResult[ContextMatchResponse]
- adcp.types.core.TaskResult[CreatePropertyListResponse]
- adcp.types.core.TaskResult[DeletePropertyListResponse]
- adcp.types.core.TaskResult[GetAdcpCapabilitiesResponse]
- adcp.types.core.TaskResult[GetCreativeDeliveryResponse]
- adcp.types.core.TaskResult[GetMediaBuyDeliveryResponse]
- adcp.types.core.TaskResult[GetMediaBuysResponse]
- adcp.types.core.TaskResult[GetPlanAuditLogsResponse]
- adcp.types.core.TaskResult[GetProductsResponse]
- adcp.types.core.TaskResult[GetPropertyListResponse]
- adcp.types.core.TaskResult[GetSignalsResponse]
- adcp.types.core.TaskResult[IdentityMatchResponse]
- adcp.types.core.TaskResult[ListAccountsResponse]
- adcp.types.core.TaskResult[ListCreativeFormatsResponse]
- adcp.types.core.TaskResult[ListCreativesResponse]
- adcp.types.core.TaskResult[ListPropertyListsResponse]
- adcp.types.core.TaskResult[ReportPlanOutcomeResponse]
- adcp.types.core.TaskResult[ReportUsageResponse]
- adcp.types.core.TaskResult[SiGetOfferingResponse]
- adcp.types.core.TaskResult[SiInitiateSessionResponse]
- adcp.types.core.TaskResult[SiSendMessageResponse]
- adcp.types.core.TaskResult[SiTerminateSessionResponse]
- adcp.types.core.TaskResult[SyncPlansResponse]
- adcp.types.core.TaskResult[Union[AcquireRightsResponse1, AcquireRightsResponse2, AcquireRightsResponse3, AcquireRightsResponse4]]
- adcp.types.core.TaskResult[Union[ActivateSignalResponse1, ActivateSignalResponse2]]
- adcp.types.core.TaskResult[Union[BuildCreativeResponse1, BuildCreativeResponse2, BuildCreativeResponse3]]
- adcp.types.core.TaskResult[Union[CalibrateContentResponse1, CalibrateContentResponse2]]
- adcp.types.core.TaskResult[Union[ComplyTestControllerResponse1, ComplyTestControllerResponse2, ComplyTestControllerResponse3, ComplyTestControllerResponse4]]
- adcp.types.core.TaskResult[Union[CreateContentStandardsResponse1, CreateContentStandardsResponse2]]
- adcp.types.core.TaskResult[Union[CreateMediaBuyResponse1, CreateMediaBuyResponse2]]
- adcp.types.core.TaskResult[Union[GetAccountFinancialsResponse1, GetAccountFinancialsResponse2]]
- adcp.types.core.TaskResult[Union[GetBrandIdentityResponse1, GetBrandIdentityResponse2]]
- adcp.types.core.TaskResult[Union[GetContentStandardsResponse1, GetContentStandardsResponse2]]
- adcp.types.core.TaskResult[Union[GetCreativeFeaturesResponse1, GetCreativeFeaturesResponse2]]
- adcp.types.core.TaskResult[Union[GetMediaBuyArtifactsResponse1, GetMediaBuyArtifactsResponse2]]
- adcp.types.core.TaskResult[Union[GetRightsResponse1, GetRightsResponse2]]
- adcp.types.core.TaskResult[Union[ListContentStandardsResponse1, ListContentStandardsResponse2]]
- adcp.types.core.TaskResult[Union[LogEventResponse1, LogEventResponse2]]
- adcp.types.core.TaskResult[Union[PreviewCreativeResponse1, PreviewCreativeResponse2, PreviewCreativeResponse3]]
- adcp.types.core.TaskResult[Union[ProvidePerformanceFeedbackResponse1, ProvidePerformanceFeedbackResponse2]]
- adcp.types.core.TaskResult[Union[SyncAccountsResponse1, SyncAccountsResponse2]]
- adcp.types.core.TaskResult[Union[SyncAudiencesResponse1, SyncAudiencesResponse2]]
- adcp.types.core.TaskResult[Union[SyncCatalogsResponse1, SyncCatalogsResponse2]]
- adcp.types.core.TaskResult[Union[SyncCreativesResponse1, SyncCreativesResponse2]]
- adcp.types.core.TaskResult[Union[SyncEventSourcesResponse1, SyncEventSourcesResponse2]]
- adcp.types.core.TaskResult[Union[UpdateContentStandardsResponse1, UpdateContentStandardsResponse2]]
- adcp.types.core.TaskResult[Union[UpdateMediaBuyResponse1, UpdateMediaBuyResponse2]]
- adcp.types.core.TaskResult[Union[ValidateContentDeliveryResponse1, ValidateContentDeliveryResponse2]]
- adcp.types.core.TaskResult[UpdatePropertyListResponse]
Class variables
var data : ~T | Nonevar debug_info : DebugInfo | Nonevar error : str | Nonevar message : str | Nonevar metadata : dict[str, typing.Any] | Nonevar model_configvar needs_input : NeedsInputInfo | Nonevar status : TaskStatusvar submitted : SubmittedInfo | Nonevar success : bool
class TaskStatus (*args, **kwds)-
Expand source code
class TaskStatus(str, Enum): """Task execution status.""" COMPLETED = "completed" SUBMITTED = "submitted" NEEDS_INPUT = "needs_input" FAILED = "failed" WORKING = "working"Task execution status.
Ancestors
- builtins.str
- enum.Enum
Class variables
var COMPLETEDvar FAILEDvar NEEDS_INPUTvar SUBMITTEDvar WORKING
class GeneratedTaskStatus (*args, **kwds)-
Expand source code
class TaskStatus(Enum): submitted = 'submitted' working = 'working' input_required = 'input-required' completed = 'completed' canceled = 'canceled' failed = 'failed' rejected = 'rejected' auth_required = 'auth-required' unknown = 'unknown'Create a collection of name/value pairs.
Example enumeration:
>>> class Color(Enum): ... RED = 1 ... BLUE = 2 ... GREEN = 3Access them by:
- attribute access::
>>> Color.RED <Color.RED: 1>- value lookup:
>>> Color(1) <Color.RED: 1>- name lookup:
>>> Color['RED'] <Color.RED: 1>Enumerations can be iterated over, and know how many members they have:
>>> len(Color) 3>>> list(Color) [<Color.RED: 1>, <Color.BLUE: 2>, <Color.GREEN: 3>]Methods can be added to enumerations, and members can have their own attributes – see the documentation for details.
Ancestors
- enum.Enum
Class variables
var auth_requiredvar canceledvar completedvar failedvar input_requiredvar rejectedvar submittedvar unknownvar working
class TimeBasedPricingOption (**data: Any)-
Expand source code
class TimeBasedPricingOption(AdCPBaseModel): model_config = ConfigDict( extra='allow', ) currency: Annotated[ str, Field( description='ISO 4217 currency code', examples=['USD', 'EUR', 'GBP', 'JPY'], pattern='^[A-Z]{3}$', ), ] eligible_adjustments: Annotated[ list[adjustment_kind.PriceAdjustmentKind] | None, Field( description='Adjustment kinds applicable to this pricing option. Tells buyer agents which adjustments are available before negotiation. When absent, no adjustments are pre-declared — the buyer should check price_breakdown if present.' ), ] = None fixed_price: Annotated[ float | None, Field( description='Cost per time unit. If present, this is fixed pricing. If absent, auction-based.', ge=0.0, ), ] = None floor_price: Annotated[ float | None, Field( description='Minimum acceptable bid per time unit for auction pricing (mutually exclusive with fixed_price). Bids below this value will be rejected.', ge=0.0, ), ] = None min_spend_per_package: Annotated[ float | None, Field( description='Minimum spend requirement per package using this pricing option, in the specified currency', ge=0.0, ), ] = None parameters: Annotated[Parameters, Field(description='Time-based pricing parameters')] price_breakdown: Annotated[ price_breakdown_1.PriceBreakdown | None, Field( description='Breakdown of how fixed_price was derived from the list (rate card) price. Only meaningful when fixed_price is present.' ), ] = None price_guidance: Annotated[ price_guidance_1.PriceGuidance | None, Field(description='Optional pricing guidance for auction-based bidding'), ] = None pricing_model: Annotated[ Literal['time'], Field(description='Cost per time unit - rate scales with campaign duration'), ] pricing_option_id: Annotated[ str, Field(description='Unique identifier for this pricing option within the product') ]Base model for AdCP types with spec-compliant serialization.
Defaults to
extra='ignore'so that unknown fields from newer spec versions are silently dropped rather than causing validation errors. Generated types whose schemas setadditionalProperties: trueoverride this withextra='allow'in their ownmodel_config. Consumers who want strict validation can override withextra='forbid'.Create a new model by parsing and validating input data from keyword arguments.
Raises [
ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.selfis explicitly positional-only to allowselfas a field name.Ancestors
- AdCPBaseModel
- pydantic.main.BaseModel
Class variables
var currency : strvar eligible_adjustments : list[PriceAdjustmentKind] | Nonevar fixed_price : float | Nonevar floor_price : float | Nonevar min_spend_per_package : float | Nonevar model_configvar parameters : Parametersvar price_breakdown : PriceBreakdown | Nonevar price_guidance : PriceGuidance | Nonevar pricing_model : Literal['time']var pricing_option_id : str
Inherited members
class TimeUnit (*args, **kwds)-
Expand source code
class TimeUnit(Enum): hour = 'hour' day = 'day' week = 'week' month = 'month'Create a collection of name/value pairs.
Example enumeration:
>>> class Color(Enum): ... RED = 1 ... BLUE = 2 ... GREEN = 3Access them by:
- attribute access::
>>> Color.RED <Color.RED: 1>- value lookup:
>>> Color(1) <Color.RED: 1>- name lookup:
>>> Color['RED'] <Color.RED: 1>Enumerations can be iterated over, and know how many members they have:
>>> len(Color) 3>>> list(Color) [<Color.RED: 1>, <Color.BLUE: 2>, <Color.GREEN: 3>]Methods can be added to enumerations, and members can have their own attributes – see the documentation for details.
Ancestors
- enum.Enum
Class variables
var dayvar hourvar monthvar week
class Transform (*args, **kwds)-
Expand source code
class Transform(Enum): date = 'date' divide = 'divide' boolean = 'boolean' split = 'split'Create a collection of name/value pairs.
Example enumeration:
>>> class Color(Enum): ... RED = 1 ... BLUE = 2 ... GREEN = 3Access them by:
- attribute access::
>>> Color.RED <Color.RED: 1>- value lookup:
>>> Color(1) <Color.RED: 1>- name lookup:
>>> Color['RED'] <Color.RED: 1>Enumerations can be iterated over, and know how many members they have:
>>> len(Color) 3>>> list(Color) [<Color.RED: 1>, <Color.BLUE: 2>, <Color.GREEN: 3>]Methods can be added to enumerations, and members can have their own attributes – see the documentation for details.
Ancestors
- enum.Enum
Class variables
var booleanvar datevar dividevar split
class UpdateContentStandardsSuccessResponse (**data: Any)-
Expand source code
class UpdateContentStandardsResponse1(AdCPBaseModel): model_config = ConfigDict( extra='allow', ) context: context_1.ContextObject | None = None ext: ext_1.ExtensionObject | None = None standards_id: Annotated[str, Field(description='ID of the updated standards configuration')] success: Annotated[ Literal[True], Field(description='Indicates the update was applied successfully') ]Base model for AdCP types with spec-compliant serialization.
Defaults to
extra='ignore'so that unknown fields from newer spec versions are silently dropped rather than causing validation errors. Generated types whose schemas setadditionalProperties: trueoverride this withextra='allow'in their ownmodel_config. Consumers who want strict validation can override withextra='forbid'.Create a new model by parsing and validating input data from keyword arguments.
Raises [
ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.selfis explicitly positional-only to allowselfas a field name.Ancestors
- AdCPBaseModel
- pydantic.main.BaseModel
Class variables
var context : ContextObject | Nonevar ext : ExtensionObject | Nonevar model_configvar standards_id : strvar success : Literal[True]
Inherited members
class UpdateContentStandardsErrorResponse (**data: Any)-
Expand source code
class UpdateContentStandardsResponse2(AdCPBaseModel): model_config = ConfigDict( extra='allow', ) conflicting_standards_id: Annotated[ str | None, Field( description='If scope change conflicts with another configuration, the ID of the conflicting standards' ), ] = None context: context_1.ContextObject | None = None errors: Annotated[ list[error.Error], Field(description='Errors that occurred during the update', min_length=1) ] ext: ext_1.ExtensionObject | None = None success: Annotated[Literal[False], Field(description='Indicates the update failed')]Base model for AdCP types with spec-compliant serialization.
Defaults to
extra='ignore'so that unknown fields from newer spec versions are silently dropped rather than causing validation errors. Generated types whose schemas setadditionalProperties: trueoverride this withextra='allow'in their ownmodel_config. Consumers who want strict validation can override withextra='forbid'.Create a new model by parsing and validating input data from keyword arguments.
Raises [
ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.selfis explicitly positional-only to allowselfas a field name.Ancestors
- AdCPBaseModel
- pydantic.main.BaseModel
Class variables
var conflicting_standards_id : str | Nonevar context : ContextObject | Nonevar errors : list[Error]var ext : ExtensionObject | Nonevar model_configvar success : Literal[False]
Inherited members
class UpdateFrequency (*args, **kwds)-
Expand source code
class UpdateFrequency(Enum): realtime = 'realtime' hourly = 'hourly' daily = 'daily' weekly = 'weekly'Create a collection of name/value pairs.
Example enumeration:
>>> class Color(Enum): ... RED = 1 ... BLUE = 2 ... GREEN = 3Access them by:
- attribute access::
>>> Color.RED <Color.RED: 1>- value lookup:
>>> Color(1) <Color.RED: 1>- name lookup:
>>> Color['RED'] <Color.RED: 1>Enumerations can be iterated over, and know how many members they have:
>>> len(Color) 3>>> list(Color) [<Color.RED: 1>, <Color.BLUE: 2>, <Color.GREEN: 3>]Methods can be added to enumerations, and members can have their own attributes – see the documentation for details.
Ancestors
- enum.Enum
Class variables
var dailyvar hourlyvar realtimevar weekly
class UpdateMediaBuyRequest (**data: Any)-
Expand source code
class UpdateMediaBuyRequest(AdCPBaseModel): model_config = ConfigDict( extra='allow', ) canceled: Annotated[ Literal[True], Field( description='Cancel the entire media buy. Cancellation is irreversible — canceled media buys cannot be reactivated. Sellers MAY reject with NOT_CANCELLABLE if the media buy cannot be canceled in its current state.' ), ] = True cancellation_reason: Annotated[ str | None, Field( description='Reason for cancellation. Sellers SHOULD store this and return it in subsequent get_media_buys responses.', max_length=500, ), ] = None context: context_1.ContextObject | None = None end_time: Annotated[ AwareDatetime | None, Field(description='New end date/time in ISO 8601 format') ] = None ext: ext_1.ExtensionObject | None = None idempotency_key: Annotated[ str | None, Field( description='Client-generated idempotency key for safe retries. If an update fails without a response, resending with the same idempotency_key guarantees the update is applied at most once. MUST be unique per (seller, request) pair to prevent cross-seller correlation. Use a fresh UUID v4 for each request.', max_length=255, min_length=16, ), ] = None invoice_recipient: Annotated[ business_entity.BusinessEntity | None, Field( description="Update who receives the invoice for this buy. When provided, the seller invoices this entity instead of the account's default billing_entity. The seller MUST validate the invoice recipient is authorized for this account. When governance_agents are configured, the seller MUST include invoice_recipient in the check_governance request." ), ] = None media_buy_id: Annotated[str, Field(description="Seller's ID of the media buy to update")] new_packages: Annotated[ list[package_request.PackageRequest] | None, Field( description='New packages to add to this media buy. Uses the same schema as create_media_buy packages. Sellers that support mid-flight package additions advertise add_packages in valid_actions. Sellers that do not support this MUST reject with UNSUPPORTED_FEATURE.', min_length=1, ), ] = None packages: Annotated[ list[package_update.PackageUpdate] | None, Field(description='Package-specific updates for existing packages', min_length=1), ] = None paused: Annotated[ bool | None, Field(description='Pause/resume the entire media buy (true = paused, false = active)'), ] = None push_notification_config: Annotated[ push_notification_config_1.PushNotificationConfig | None, Field( description='Optional webhook configuration for async update notifications. Publisher will send webhook when update completes if operation takes longer than immediate response time. This is separate from reporting_webhook which configures ongoing campaign reporting.' ), ] = None reporting_webhook: Annotated[ reporting_webhook_1.ReportingWebhook | None, Field( description='Optional webhook configuration for automated reporting delivery. Updates the reporting configuration for this media buy.' ), ] = None revision: Annotated[ int | None, Field( description="Expected current revision for optimistic concurrency. When provided, sellers MUST reject the update with CONFLICT if the media buy's current revision does not match. Obtain from get_media_buys or the most recent update response.", ge=1, ), ] = None start_time: start_timing.StartTiming | None = NoneBase model for AdCP types with spec-compliant serialization.
Defaults to
extra='ignore'so that unknown fields from newer spec versions are silently dropped rather than causing validation errors. Generated types whose schemas setadditionalProperties: trueoverride this withextra='allow'in their ownmodel_config. Consumers who want strict validation can override withextra='forbid'.Create a new model by parsing and validating input data from keyword arguments.
Raises [
ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.selfis explicitly positional-only to allowselfas a field name.Ancestors
- AdCPBaseModel
- pydantic.main.BaseModel
Class variables
var canceled : Literal[True]var cancellation_reason : str | Nonevar context : ContextObject | Nonevar end_time : pydantic.types.AwareDatetime | Nonevar ext : ExtensionObject | Nonevar idempotency_key : str | Nonevar invoice_recipient : BusinessEntity | Nonevar media_buy_id : strvar model_configvar new_packages : list[PackageRequest] | Nonevar packages : list[PackageUpdate] | Nonevar paused : bool | Nonevar push_notification_config : PushNotificationConfig | Nonevar reporting_webhook : ReportingWebhook | Nonevar revision : int | Nonevar start_time : StartTiming | None
class UpdateMediaBuyPackagesRequest (**data: Any)-
Expand source code
class UpdateMediaBuyRequest(AdCPBaseModel): model_config = ConfigDict( extra='allow', ) canceled: Annotated[ Literal[True], Field( description='Cancel the entire media buy. Cancellation is irreversible — canceled media buys cannot be reactivated. Sellers MAY reject with NOT_CANCELLABLE if the media buy cannot be canceled in its current state.' ), ] = True cancellation_reason: Annotated[ str | None, Field( description='Reason for cancellation. Sellers SHOULD store this and return it in subsequent get_media_buys responses.', max_length=500, ), ] = None context: context_1.ContextObject | None = None end_time: Annotated[ AwareDatetime | None, Field(description='New end date/time in ISO 8601 format') ] = None ext: ext_1.ExtensionObject | None = None idempotency_key: Annotated[ str | None, Field( description='Client-generated idempotency key for safe retries. If an update fails without a response, resending with the same idempotency_key guarantees the update is applied at most once. MUST be unique per (seller, request) pair to prevent cross-seller correlation. Use a fresh UUID v4 for each request.', max_length=255, min_length=16, ), ] = None invoice_recipient: Annotated[ business_entity.BusinessEntity | None, Field( description="Update who receives the invoice for this buy. When provided, the seller invoices this entity instead of the account's default billing_entity. The seller MUST validate the invoice recipient is authorized for this account. When governance_agents are configured, the seller MUST include invoice_recipient in the check_governance request." ), ] = None media_buy_id: Annotated[str, Field(description="Seller's ID of the media buy to update")] new_packages: Annotated[ list[package_request.PackageRequest] | None, Field( description='New packages to add to this media buy. Uses the same schema as create_media_buy packages. Sellers that support mid-flight package additions advertise add_packages in valid_actions. Sellers that do not support this MUST reject with UNSUPPORTED_FEATURE.', min_length=1, ), ] = None packages: Annotated[ list[package_update.PackageUpdate] | None, Field(description='Package-specific updates for existing packages', min_length=1), ] = None paused: Annotated[ bool | None, Field(description='Pause/resume the entire media buy (true = paused, false = active)'), ] = None push_notification_config: Annotated[ push_notification_config_1.PushNotificationConfig | None, Field( description='Optional webhook configuration for async update notifications. Publisher will send webhook when update completes if operation takes longer than immediate response time. This is separate from reporting_webhook which configures ongoing campaign reporting.' ), ] = None reporting_webhook: Annotated[ reporting_webhook_1.ReportingWebhook | None, Field( description='Optional webhook configuration for automated reporting delivery. Updates the reporting configuration for this media buy.' ), ] = None revision: Annotated[ int | None, Field( description="Expected current revision for optimistic concurrency. When provided, sellers MUST reject the update with CONFLICT if the media buy's current revision does not match. Obtain from get_media_buys or the most recent update response.", ge=1, ), ] = None start_time: start_timing.StartTiming | None = NoneBase model for AdCP types with spec-compliant serialization.
Defaults to
extra='ignore'so that unknown fields from newer spec versions are silently dropped rather than causing validation errors. Generated types whose schemas setadditionalProperties: trueoverride this withextra='allow'in their ownmodel_config. Consumers who want strict validation can override withextra='forbid'.Create a new model by parsing and validating input data from keyword arguments.
Raises [
ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.selfis explicitly positional-only to allowselfas a field name.Ancestors
- AdCPBaseModel
- pydantic.main.BaseModel
Class variables
var canceled : Literal[True]var cancellation_reason : str | Nonevar context : ContextObject | Nonevar end_time : pydantic.types.AwareDatetime | Nonevar ext : ExtensionObject | Nonevar idempotency_key : str | Nonevar invoice_recipient : BusinessEntity | Nonevar media_buy_id : strvar model_configvar new_packages : list[PackageRequest] | Nonevar packages : list[PackageUpdate] | Nonevar paused : bool | Nonevar push_notification_config : PushNotificationConfig | Nonevar reporting_webhook : ReportingWebhook | Nonevar revision : int | Nonevar start_time : StartTiming | None
class UpdateMediaBuyPropertiesRequest (**data: Any)-
Expand source code
class UpdateMediaBuyRequest(AdCPBaseModel): model_config = ConfigDict( extra='allow', ) canceled: Annotated[ Literal[True], Field( description='Cancel the entire media buy. Cancellation is irreversible — canceled media buys cannot be reactivated. Sellers MAY reject with NOT_CANCELLABLE if the media buy cannot be canceled in its current state.' ), ] = True cancellation_reason: Annotated[ str | None, Field( description='Reason for cancellation. Sellers SHOULD store this and return it in subsequent get_media_buys responses.', max_length=500, ), ] = None context: context_1.ContextObject | None = None end_time: Annotated[ AwareDatetime | None, Field(description='New end date/time in ISO 8601 format') ] = None ext: ext_1.ExtensionObject | None = None idempotency_key: Annotated[ str | None, Field( description='Client-generated idempotency key for safe retries. If an update fails without a response, resending with the same idempotency_key guarantees the update is applied at most once. MUST be unique per (seller, request) pair to prevent cross-seller correlation. Use a fresh UUID v4 for each request.', max_length=255, min_length=16, ), ] = None invoice_recipient: Annotated[ business_entity.BusinessEntity | None, Field( description="Update who receives the invoice for this buy. When provided, the seller invoices this entity instead of the account's default billing_entity. The seller MUST validate the invoice recipient is authorized for this account. When governance_agents are configured, the seller MUST include invoice_recipient in the check_governance request." ), ] = None media_buy_id: Annotated[str, Field(description="Seller's ID of the media buy to update")] new_packages: Annotated[ list[package_request.PackageRequest] | None, Field( description='New packages to add to this media buy. Uses the same schema as create_media_buy packages. Sellers that support mid-flight package additions advertise add_packages in valid_actions. Sellers that do not support this MUST reject with UNSUPPORTED_FEATURE.', min_length=1, ), ] = None packages: Annotated[ list[package_update.PackageUpdate] | None, Field(description='Package-specific updates for existing packages', min_length=1), ] = None paused: Annotated[ bool | None, Field(description='Pause/resume the entire media buy (true = paused, false = active)'), ] = None push_notification_config: Annotated[ push_notification_config_1.PushNotificationConfig | None, Field( description='Optional webhook configuration for async update notifications. Publisher will send webhook when update completes if operation takes longer than immediate response time. This is separate from reporting_webhook which configures ongoing campaign reporting.' ), ] = None reporting_webhook: Annotated[ reporting_webhook_1.ReportingWebhook | None, Field( description='Optional webhook configuration for automated reporting delivery. Updates the reporting configuration for this media buy.' ), ] = None revision: Annotated[ int | None, Field( description="Expected current revision for optimistic concurrency. When provided, sellers MUST reject the update with CONFLICT if the media buy's current revision does not match. Obtain from get_media_buys or the most recent update response.", ge=1, ), ] = None start_time: start_timing.StartTiming | None = NoneBase model for AdCP types with spec-compliant serialization.
Defaults to
extra='ignore'so that unknown fields from newer spec versions are silently dropped rather than causing validation errors. Generated types whose schemas setadditionalProperties: trueoverride this withextra='allow'in their ownmodel_config. Consumers who want strict validation can override withextra='forbid'.Create a new model by parsing and validating input data from keyword arguments.
Raises [
ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.selfis explicitly positional-only to allowselfas a field name.Ancestors
- AdCPBaseModel
- pydantic.main.BaseModel
Class variables
var canceled : Literal[True]var cancellation_reason : str | Nonevar context : ContextObject | Nonevar end_time : pydantic.types.AwareDatetime | Nonevar ext : ExtensionObject | Nonevar idempotency_key : str | Nonevar invoice_recipient : BusinessEntity | Nonevar media_buy_id : strvar model_configvar new_packages : list[PackageRequest] | Nonevar packages : list[PackageUpdate] | Nonevar paused : bool | Nonevar push_notification_config : PushNotificationConfig | Nonevar reporting_webhook : ReportingWebhook | Nonevar revision : int | Nonevar start_time : StartTiming | None
Inherited members
class UpdateMediaBuySuccessResponse (**data: Any)-
Expand source code
class UpdateMediaBuyResponse1(AdCPBaseModel): model_config = ConfigDict( extra='allow', ) affected_packages: Annotated[ list[package.Package] | None, Field(description='Array of packages that were modified with complete state information'), ] = None context: context_1.ContextObject | None = None ext: ext_1.ExtensionObject | None = None implementation_date: Annotated[ AwareDatetime | None, Field(description='ISO 8601 timestamp when changes take effect (null if pending approval)'), ] = None invoice_recipient: Annotated[ business_entity.BusinessEntity | None, Field( description='Updated invoice recipient, echoed from the request when provided. Confirms the seller accepted the billing override. Bank details are omitted (write-only).' ), ] = None media_buy_id: Annotated[str, Field(description="Seller's identifier for the media buy")] revision: Annotated[ int | None, Field( description='Revision number after this update. Use this value in subsequent update_media_buy requests for optimistic concurrency.', ge=1, ), ] = None sandbox: Annotated[ bool | None, Field(description='When true, this response contains simulated data from sandbox mode.'), ] = None status: Annotated[ media_buy_status.MediaBuyStatus | None, Field( description="Media buy status after the update. Present when the update changes the media buy's status (e.g., cancellation transitions to 'canceled', pause transitions to 'paused')." ), ] = None valid_actions: Annotated[ list[ValidAction] | None, Field( description='Actions the buyer can perform after this update. Saves a round-trip to get_media_buys.' ), ] = NoneBase model for AdCP types with spec-compliant serialization.
Defaults to
extra='ignore'so that unknown fields from newer spec versions are silently dropped rather than causing validation errors. Generated types whose schemas setadditionalProperties: trueoverride this withextra='allow'in their ownmodel_config. Consumers who want strict validation can override withextra='forbid'.Create a new model by parsing and validating input data from keyword arguments.
Raises [
ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.selfis explicitly positional-only to allowselfas a field name.Ancestors
- AdCPBaseModel
- pydantic.main.BaseModel
Class variables
var affected_packages : list[Package] | Nonevar context : ContextObject | Nonevar ext : ExtensionObject | Nonevar implementation_date : pydantic.types.AwareDatetime | Nonevar invoice_recipient : BusinessEntity | Nonevar media_buy_id : strvar model_configvar revision : int | Nonevar sandbox : bool | Nonevar status : MediaBuyStatus | Nonevar valid_actions : list[ValidAction] | None
Inherited members
class UpdateMediaBuyErrorResponse (**data: Any)-
Expand source code
class UpdateMediaBuyResponse2(AdCPBaseModel): model_config = ConfigDict( extra='allow', ) context: context_1.ContextObject | None = None errors: Annotated[ list[error.Error], Field(description='Array of errors explaining why the operation failed', min_length=1), ] ext: ext_1.ExtensionObject | None = NoneBase model for AdCP types with spec-compliant serialization.
Defaults to
extra='ignore'so that unknown fields from newer spec versions are silently dropped rather than causing validation errors. Generated types whose schemas setadditionalProperties: trueoverride this withextra='allow'in their ownmodel_config. Consumers who want strict validation can override withextra='forbid'.Create a new model by parsing and validating input data from keyword arguments.
Raises [
ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.selfis explicitly positional-only to allowselfas a field name.Ancestors
- AdCPBaseModel
- pydantic.main.BaseModel
Class variables
var context : ContextObject | Nonevar errors : list[Error]var ext : ExtensionObject | Nonevar model_config
Inherited members
class ValidateContentDeliverySuccessResponse (**data: Any)-
Expand source code
class ValidateContentDeliveryResponse1(AdCPBaseModel): context: context_1.ContextObject | None = None ext: ext_1.ExtensionObject | None = None results: Annotated[list[Result], Field(description='Per-record evaluation results')] summary: Annotated[Summary, Field(description='Summary counts across all records')]Base model for AdCP types with spec-compliant serialization.
Defaults to
extra='ignore'so that unknown fields from newer spec versions are silently dropped rather than causing validation errors. Generated types whose schemas setadditionalProperties: trueoverride this withextra='allow'in their ownmodel_config. Consumers who want strict validation can override withextra='forbid'.Create a new model by parsing and validating input data from keyword arguments.
Raises [
ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.selfis explicitly positional-only to allowselfas a field name.Ancestors
- AdCPBaseModel
- pydantic.main.BaseModel
Class variables
var context : ContextObject | Nonevar ext : ExtensionObject | Nonevar model_configvar results : list[Result]var summary : Summary
Inherited members
class ValidateContentDeliveryErrorResponse (**data: Any)-
Expand source code
class ValidateContentDeliveryResponse2(AdCPBaseModel): context: context_1.ContextObject | None = None errors: list[error.Error] ext: ext_1.ExtensionObject | None = NoneBase model for AdCP types with spec-compliant serialization.
Defaults to
extra='ignore'so that unknown fields from newer spec versions are silently dropped rather than causing validation errors. Generated types whose schemas setadditionalProperties: trueoverride this withextra='allow'in their ownmodel_config. Consumers who want strict validation can override withextra='forbid'.Create a new model by parsing and validating input data from keyword arguments.
Raises [
ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.selfis explicitly positional-only to allowselfas a field name.Ancestors
- AdCPBaseModel
- pydantic.main.BaseModel
Class variables
var context : ContextObject | Nonevar errors : list[Error]var ext : ExtensionObject | Nonevar model_config
Inherited members
class ValidationError (*args, **kwargs)-
Expand source code
class ValidationError(ValueError): """Raised when runtime validation fails.""" passRaised when runtime validation fails.
Ancestors
- builtins.ValueError
- builtins.Exception
- builtins.BaseException
class ValidationResult (**data: Any)-
Expand source code
class ValidationResult(RegistryBaseModel): valid: bool domain: str | None = None url: str | None = None errors: list[str | dict[str, Any]] | None = None warnings: list[str | dict[str, Any]] | None = None status_code: int | None = None raw_data: dict[str, Any] | None = NoneBase model for registry API types.
Uses
extra='allow'so that new fields from the registry API are preserved rather than dropped. This differs from AdCPBaseModel which defaults toextra='ignore'for protocol types.Create a new model by parsing and validating input data from keyword arguments.
Raises [
ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.selfis explicitly positional-only to allowselfas a field name.Ancestors
- RegistryBaseModel
- pydantic.main.BaseModel
Class variables
var domain : str | Nonevar errors : list[str | dict[str, typing.Any]] | Nonevar model_configvar raw_data : dict[str, typing.Any] | Nonevar status_code : int | Nonevar url : str | Nonevar valid : boolvar warnings : list[str | dict[str, typing.Any]] | None
class UrlVastAsset (**data: Any)-
Expand source code
class VastAsset1(AdCPBaseModel): model_config = ConfigDict( extra='allow', ) audio_description_url: Annotated[ AnyUrl | None, Field(description='URL to audio description track for visually impaired users'), ] = None captions_url: Annotated[ AnyUrl | None, Field(description='URL to captions file (WebVTT, SRT, etc.)') ] = None delivery_type: Annotated[ Literal['url'], Field(description='Discriminator indicating VAST is delivered via URL endpoint'), ] duration_ms: Annotated[ int | None, Field(description='Expected video duration in milliseconds (if known)', ge=0) ] = None provenance: Annotated[ provenance_1.Provenance | None, Field( description='Provenance metadata for this asset, overrides manifest-level provenance' ), ] = None tracking_events: Annotated[ list[vast_tracking_event.VastTrackingEvent] | None, Field(description='Tracking events supported by this VAST tag'), ] = None url: Annotated[AnyUrl, Field(description='URL endpoint that returns VAST XML')] vast_version: Annotated[ vast_version_1.VastVersion | None, Field(description='VAST specification version') ] = None vpaid_enabled: Annotated[ bool | None, Field(description='Whether VPAID (Video Player-Ad Interface Definition) is supported'), ] = NoneBase model for AdCP types with spec-compliant serialization.
Defaults to
extra='ignore'so that unknown fields from newer spec versions are silently dropped rather than causing validation errors. Generated types whose schemas setadditionalProperties: trueoverride this withextra='allow'in their ownmodel_config. Consumers who want strict validation can override withextra='forbid'.Create a new model by parsing and validating input data from keyword arguments.
Raises [
ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.selfis explicitly positional-only to allowselfas a field name.Ancestors
- AdCPBaseModel
- pydantic.main.BaseModel
Class variables
var audio_description_url : pydantic.networks.AnyUrl | Nonevar captions_url : pydantic.networks.AnyUrl | Nonevar delivery_type : Literal['url']var duration_ms : int | Nonevar model_configvar provenance : Provenance | Nonevar tracking_events : list[VastTrackingEvent] | Nonevar url : pydantic.networks.AnyUrlvar vast_version : VastVersion | Nonevar vpaid_enabled : bool | None
Inherited members
class InlineVastAsset (**data: Any)-
Expand source code
class VastAsset2(AdCPBaseModel): model_config = ConfigDict( extra='allow', ) audio_description_url: Annotated[ AnyUrl | None, Field(description='URL to audio description track for visually impaired users'), ] = None captions_url: Annotated[ AnyUrl | None, Field(description='URL to captions file (WebVTT, SRT, etc.)') ] = None content: Annotated[str, Field(description='Inline VAST XML content')] delivery_type: Annotated[ Literal['inline'], Field(description='Discriminator indicating VAST is delivered as inline XML content'), ] duration_ms: Annotated[ int | None, Field(description='Expected video duration in milliseconds (if known)', ge=0) ] = None provenance: Annotated[ provenance_1.Provenance | None, Field( description='Provenance metadata for this asset, overrides manifest-level provenance' ), ] = None tracking_events: Annotated[ list[vast_tracking_event.VastTrackingEvent] | None, Field(description='Tracking events supported by this VAST tag'), ] = None vast_version: Annotated[ vast_version_1.VastVersion | None, Field(description='VAST specification version') ] = None vpaid_enabled: Annotated[ bool | None, Field(description='Whether VPAID (Video Player-Ad Interface Definition) is supported'), ] = NoneBase model for AdCP types with spec-compliant serialization.
Defaults to
extra='ignore'so that unknown fields from newer spec versions are silently dropped rather than causing validation errors. Generated types whose schemas setadditionalProperties: trueoverride this withextra='allow'in their ownmodel_config. Consumers who want strict validation can override withextra='forbid'.Create a new model by parsing and validating input data from keyword arguments.
Raises [
ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.selfis explicitly positional-only to allowselfas a field name.Ancestors
- AdCPBaseModel
- pydantic.main.BaseModel
Class variables
var audio_description_url : pydantic.networks.AnyUrl | Nonevar captions_url : pydantic.networks.AnyUrl | Nonevar content : strvar delivery_type : Literal['inline']var duration_ms : int | Nonevar model_configvar provenance : Provenance | Nonevar tracking_events : list[VastTrackingEvent] | Nonevar vast_version : VastVersion | Nonevar vpaid_enabled : bool | None
Inherited members
class VcpmPricingOption (**data: Any)-
Expand source code
class VcpmPricingOption(AdCPBaseModel): model_config = ConfigDict( extra='allow', ) currency: Annotated[ str, Field( description='ISO 4217 currency code', examples=['USD', 'EUR', 'GBP', 'JPY'], pattern='^[A-Z]{3}$', ), ] eligible_adjustments: Annotated[ list[adjustment_kind.PriceAdjustmentKind] | None, Field( description='Adjustment kinds applicable to this pricing option. Tells buyer agents which adjustments are available before negotiation. When absent, no adjustments are pre-declared — the buyer should check price_breakdown if present.' ), ] = None fixed_price: Annotated[ float | None, Field( description='Fixed price per unit. If present, this is fixed pricing. If absent, auction-based.', ge=0.0, ), ] = None floor_price: Annotated[ float | None, Field( description='Minimum acceptable bid for auction pricing (mutually exclusive with fixed_price). Bids below this value will be rejected.', ge=0.0, ), ] = None max_bid: Annotated[ bool | None, Field( description="When true, bid_price is interpreted as the buyer's maximum willingness to pay (ceiling) rather than an exact price. Sellers may optimize actual clearing prices between floor_price and bid_price based on delivery pacing. When false or absent, bid_price (if provided) is the exact bid/price to honor." ), ] = False min_spend_per_package: Annotated[ float | None, Field( description='Minimum spend requirement per package using this pricing option, in the specified currency', ge=0.0, ), ] = None price_breakdown: Annotated[ price_breakdown_1.PriceBreakdown | None, Field( description='Breakdown of how fixed_price was derived from the list (rate card) price. Only meaningful when fixed_price is present.' ), ] = None price_guidance: Annotated[ price_guidance_1.PriceGuidance | None, Field(description='Optional pricing guidance for auction-based bidding'), ] = None pricing_model: Annotated[ Literal['vcpm'], Field(description='Cost per 1,000 viewable impressions (MRC standard)') ] pricing_option_id: Annotated[ str, Field(description='Unique identifier for this pricing option within the product') ]Base model for AdCP types with spec-compliant serialization.
Defaults to
extra='ignore'so that unknown fields from newer spec versions are silently dropped rather than causing validation errors. Generated types whose schemas setadditionalProperties: trueoverride this withextra='allow'in their ownmodel_config. Consumers who want strict validation can override withextra='forbid'.Create a new model by parsing and validating input data from keyword arguments.
Raises [
ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.selfis explicitly positional-only to allowselfas a field name.Ancestors
- AdCPBaseModel
- pydantic.main.BaseModel
Class variables
var currency : strvar eligible_adjustments : list[PriceAdjustmentKind] | Nonevar fixed_price : float | Nonevar floor_price : float | Nonevar max_bid : bool | Nonevar min_spend_per_package : float | Nonevar model_configvar price_breakdown : PriceBreakdown | Nonevar price_guidance : PriceGuidance | Nonevar pricing_model : Literal['vcpm']var pricing_option_id : str
class VcpmAuctionPricingOption (**data: Any)-
Expand source code
class VcpmPricingOption(AdCPBaseModel): model_config = ConfigDict( extra='allow', ) currency: Annotated[ str, Field( description='ISO 4217 currency code', examples=['USD', 'EUR', 'GBP', 'JPY'], pattern='^[A-Z]{3}$', ), ] eligible_adjustments: Annotated[ list[adjustment_kind.PriceAdjustmentKind] | None, Field( description='Adjustment kinds applicable to this pricing option. Tells buyer agents which adjustments are available before negotiation. When absent, no adjustments are pre-declared — the buyer should check price_breakdown if present.' ), ] = None fixed_price: Annotated[ float | None, Field( description='Fixed price per unit. If present, this is fixed pricing. If absent, auction-based.', ge=0.0, ), ] = None floor_price: Annotated[ float | None, Field( description='Minimum acceptable bid for auction pricing (mutually exclusive with fixed_price). Bids below this value will be rejected.', ge=0.0, ), ] = None max_bid: Annotated[ bool | None, Field( description="When true, bid_price is interpreted as the buyer's maximum willingness to pay (ceiling) rather than an exact price. Sellers may optimize actual clearing prices between floor_price and bid_price based on delivery pacing. When false or absent, bid_price (if provided) is the exact bid/price to honor." ), ] = False min_spend_per_package: Annotated[ float | None, Field( description='Minimum spend requirement per package using this pricing option, in the specified currency', ge=0.0, ), ] = None price_breakdown: Annotated[ price_breakdown_1.PriceBreakdown | None, Field( description='Breakdown of how fixed_price was derived from the list (rate card) price. Only meaningful when fixed_price is present.' ), ] = None price_guidance: Annotated[ price_guidance_1.PriceGuidance | None, Field(description='Optional pricing guidance for auction-based bidding'), ] = None pricing_model: Annotated[ Literal['vcpm'], Field(description='Cost per 1,000 viewable impressions (MRC standard)') ] pricing_option_id: Annotated[ str, Field(description='Unique identifier for this pricing option within the product') ]Base model for AdCP types with spec-compliant serialization.
Defaults to
extra='ignore'so that unknown fields from newer spec versions are silently dropped rather than causing validation errors. Generated types whose schemas setadditionalProperties: trueoverride this withextra='allow'in their ownmodel_config. Consumers who want strict validation can override withextra='forbid'.Create a new model by parsing and validating input data from keyword arguments.
Raises [
ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.selfis explicitly positional-only to allowselfas a field name.Ancestors
- AdCPBaseModel
- pydantic.main.BaseModel
Class variables
var currency : strvar eligible_adjustments : list[PriceAdjustmentKind] | Nonevar fixed_price : float | Nonevar floor_price : float | Nonevar max_bid : bool | Nonevar min_spend_per_package : float | Nonevar model_configvar price_breakdown : PriceBreakdown | Nonevar price_guidance : PriceGuidance | Nonevar pricing_model : Literal['vcpm']var pricing_option_id : str
class VcpmFixedRatePricingOption (**data: Any)-
Expand source code
class VcpmPricingOption(AdCPBaseModel): model_config = ConfigDict( extra='allow', ) currency: Annotated[ str, Field( description='ISO 4217 currency code', examples=['USD', 'EUR', 'GBP', 'JPY'], pattern='^[A-Z]{3}$', ), ] eligible_adjustments: Annotated[ list[adjustment_kind.PriceAdjustmentKind] | None, Field( description='Adjustment kinds applicable to this pricing option. Tells buyer agents which adjustments are available before negotiation. When absent, no adjustments are pre-declared — the buyer should check price_breakdown if present.' ), ] = None fixed_price: Annotated[ float | None, Field( description='Fixed price per unit. If present, this is fixed pricing. If absent, auction-based.', ge=0.0, ), ] = None floor_price: Annotated[ float | None, Field( description='Minimum acceptable bid for auction pricing (mutually exclusive with fixed_price). Bids below this value will be rejected.', ge=0.0, ), ] = None max_bid: Annotated[ bool | None, Field( description="When true, bid_price is interpreted as the buyer's maximum willingness to pay (ceiling) rather than an exact price. Sellers may optimize actual clearing prices between floor_price and bid_price based on delivery pacing. When false or absent, bid_price (if provided) is the exact bid/price to honor." ), ] = False min_spend_per_package: Annotated[ float | None, Field( description='Minimum spend requirement per package using this pricing option, in the specified currency', ge=0.0, ), ] = None price_breakdown: Annotated[ price_breakdown_1.PriceBreakdown | None, Field( description='Breakdown of how fixed_price was derived from the list (rate card) price. Only meaningful when fixed_price is present.' ), ] = None price_guidance: Annotated[ price_guidance_1.PriceGuidance | None, Field(description='Optional pricing guidance for auction-based bidding'), ] = None pricing_model: Annotated[ Literal['vcpm'], Field(description='Cost per 1,000 viewable impressions (MRC standard)') ] pricing_option_id: Annotated[ str, Field(description='Unique identifier for this pricing option within the product') ]Base model for AdCP types with spec-compliant serialization.
Defaults to
extra='ignore'so that unknown fields from newer spec versions are silently dropped rather than causing validation errors. Generated types whose schemas setadditionalProperties: trueoverride this withextra='allow'in their ownmodel_config. Consumers who want strict validation can override withextra='forbid'.Create a new model by parsing and validating input data from keyword arguments.
Raises [
ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.selfis explicitly positional-only to allowselfas a field name.Ancestors
- AdCPBaseModel
- pydantic.main.BaseModel
Class variables
var currency : strvar eligible_adjustments : list[PriceAdjustmentKind] | Nonevar fixed_price : float | Nonevar floor_price : float | Nonevar max_bid : bool | Nonevar min_spend_per_package : float | Nonevar model_configvar price_breakdown : PriceBreakdown | Nonevar price_guidance : PriceGuidance | Nonevar pricing_model : Literal['vcpm']var pricing_option_id : str
Inherited members
class WcagLevel (*args, **kwds)-
Expand source code
class WcagLevel(Enum): A = 'A' AA = 'AA' AAA = 'AAA'Create a collection of name/value pairs.
Example enumeration:
>>> class Color(Enum): ... RED = 1 ... BLUE = 2 ... GREEN = 3Access them by:
- attribute access::
>>> Color.RED <Color.RED: 1>- value lookup:
>>> Color(1) <Color.RED: 1>- name lookup:
>>> Color['RED'] <Color.RED: 1>Enumerations can be iterated over, and know how many members they have:
>>> len(Color) 3>>> list(Color) [<Color.RED: 1>, <Color.BLUE: 2>, <Color.GREEN: 3>]Methods can be added to enumerations, and members can have their own attributes – see the documentation for details.
Ancestors
- enum.Enum
Class variables
var Avar AAvar AAA
class WebhookMetadata (**data: Any)-
Expand source code
class WebhookMetadata(BaseModel): """Metadata passed to webhook handlers.""" operation_id: str agent_id: str task_type: str status: TaskStatus sequence_number: int | None = None notification_type: Literal["scheduled", "final", "delayed"] | None = None timestamp: strMetadata passed to webhook handlers.
Create a new model by parsing and validating input data from keyword arguments.
Raises [
ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.selfis explicitly positional-only to allowselfas a field name.Ancestors
- pydantic.main.BaseModel
Class variables
var agent_id : strvar model_configvar notification_type : Literal['scheduled', 'final', 'delayed'] | Nonevar operation_id : strvar sequence_number : int | Nonevar status : TaskStatusvar task_type : strvar timestamp : str