diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 2c08fc8..2df9e1d 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -47,6 +47,9 @@ jobs: - name: Run smoke tests run: uv run pytest tests/smoke/ -v --no-cov -m smoke + - name: Run schema compliance tests + run: uv run pytest tests/schema_compliance/ -v --no-cov + - name: Run all tests with coverage run: uv run pytest --cov=src/creative_agent --cov-fail-under=10 --cov-report=term-missing diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 707853f..e155211 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -17,6 +17,9 @@ repos: pass_filenames: false stages: [manual] + # Schema compliance runs in CI only (requires uv + full test environment) + # See .github/workflows/ci.yml for schema compliance validation + - repo: https://github.com/pre-commit/pre-commit-hooks rev: v6.0.0 hooks: diff --git a/scripts/generate_schemas.py b/scripts/generate_schemas.py index 39b3f66..4f07966 100755 --- a/scripts/generate_schemas.py +++ b/scripts/generate_schemas.py @@ -160,8 +160,8 @@ def generate_schemas_from_json(schema_dir: Path, output_file: Path): temp_dir.mkdir(exist_ok=True) try: - # Process each JSON schema file - schema_files = list(schema_dir.glob("*.json")) + # Process each JSON schema file in sorted order for deterministic output + schema_files = sorted(schema_dir.glob("*.json")) print(f"šŸ“ Found {len(schema_files)} schema files") # Skip these non-schema files @@ -208,6 +208,7 @@ def generate_schemas_from_json(schema_dir: Path, output_file: Path): "--target-python-version", "3.12", "--disable-timestamp", + "--reuse-model", # Reuse models with same content for deterministic class names ] result = subprocess.run(cmd, capture_output=True, text=True, check=False) diff --git a/scripts/update_schemas.py b/scripts/update_schemas.py new file mode 100644 index 0000000..052c36c --- /dev/null +++ b/scripts/update_schemas.py @@ -0,0 +1,246 @@ +#!/usr/bin/env python3 +""" +Update local schema cache from AdCP website. + +This script downloads all AdCP JSON schemas from adcontextprotocol.org +and updates the local cache in tests/schemas/v1/. + +Usage: + python scripts/update_schemas.py [--dry-run] +""" + +import argparse +import json +import sys +from pathlib import Path + +import httpx + + +def filename_to_ref(filename: str) -> str: + """Convert our flattened filename format to a $ref path.""" + # _schemas_v1_core_format_json.json -> /schemas/v1/core/format.json + name = filename.replace(".json", "").replace("_json", ".json").replace("_", "/", 1) + return name + + +def ref_to_filename(ref: str) -> str: + """Convert $ref path to our flattened filename format.""" + # /schemas/v1/core/format.json -> _schemas_v1_core_format_json.json + return ref.replace("/", "_").replace(".", "_") + ".json" + + +def download_schema(ref: str, base_url: str = "https://adcontextprotocol.org") -> dict | None: + """ + Download a schema from AdCP website. + + Returns schema dict if successful, None if not found or error. + """ + schema_url = f"{base_url}{ref}" + + try: + print(f" Fetching: {ref}") + response = httpx.get(schema_url, timeout=10.0, follow_redirects=True) + response.raise_for_status() + + # Check if we got JSON (not HTML) + content_type = response.headers.get("content-type", "") + if "json" not in content_type.lower(): + print(f" āš ļø Skipping {ref}: Got {content_type} instead of JSON") + return None + + schema = response.json() + return schema + + except httpx.HTTPStatusError as e: + if e.response.status_code == 404: + print(f" āš ļø Not found: {ref}") + else: + print(f" āŒ HTTP {e.response.status_code}: {ref}") + return None + except Exception as e: + print(f" āŒ Error downloading {ref}: {e}") + return None + + +def is_creative_agent_schema(ref: str) -> bool: + """ + Check if a schema is relevant for a Creative Agent. + + Creative agents only need schemas related to creative formats, assets, + and creative agent tools - not media buy, signals, or other protocol areas. + """ + creative_patterns = [ + "/schemas/v1/core/assets/", # All asset types + "/schemas/v1/core/creative-", # Creative-specific schemas + "/schemas/v1/core/format", # Format and format-id + "/schemas/v1/core/brand-manifest", # Brand manifest schemas + "/schemas/v1/creative/", # Creative agent tool schemas + "/schemas/v1/enums/", # Shared enums (needed by assets and formats) + "/schemas/v1/standard-formats/", # Standard format definitions + "/schemas/v1/adagents.json", # Agent capabilities + "/schemas/v1/core/response.json", # Protocol response wrapper + "/schemas/v1/core/error.json", # Error schema + "/schemas/v1/core/sub-asset.json", # Sub-asset for carousels + ] + + return any(pattern in ref for pattern in creative_patterns) + + +def discover_schemas(schema_dir: Path, creative_only: bool = True) -> list[str]: + """ + Discover all schema $refs from existing cache. + + Args: + schema_dir: Directory containing cached schemas + creative_only: If True, only return creative-agent-relevant schemas + + Returns list of unique $ref paths found in existing schemas. + """ + refs = set() + + for schema_file in schema_dir.glob("*.json"): + try: + with open(schema_file) as f: + schema = json.load(f) + + # Extract $ref from this schema + if "$id" in schema: + schema_ref = schema["$id"] + if not creative_only or is_creative_agent_schema(schema_ref): + refs.add(schema_ref) + + # Recursively find all $refs in the schema + all_refs = find_refs_in_schema(schema) + if creative_only: + all_refs = {r for r in all_refs if is_creative_agent_schema(r)} + refs.update(all_refs) + + except Exception as e: + print(f" āš ļø Error reading {schema_file.name}: {e}") + + return sorted(refs) + + +def find_refs_in_schema(obj: dict | list) -> set[str]: + """Recursively find all $ref values in a schema.""" + refs = set() + + if isinstance(obj, dict): + if "$ref" in obj: + refs.add(obj["$ref"]) + for value in obj.values(): + refs.update(find_refs_in_schema(value)) + elif isinstance(obj, list): + for item in obj: + refs.update(find_refs_in_schema(item)) + + return refs + + +def update_schemas(schema_dir: Path, dry_run: bool = False, creative_only: bool = True): + """ + Update schemas from AdCP website. + + Discovers schema refs from existing cache, downloads latest versions, + and updates local files. + + Args: + schema_dir: Directory containing cached schemas + dry_run: If True, show what would change without modifying files + creative_only: If True, only update creative-agent-relevant schemas + """ + print(f"šŸ“‚ Schema directory: {schema_dir}") + if creative_only: + print("šŸŽØ Filtering to creative-agent-relevant schemas only") + + if not schema_dir.exists(): + print(f"āŒ Directory not found: {schema_dir}") + sys.exit(1) + + # Discover all schema refs + print("\nšŸ” Discovering schemas from existing cache...") + refs = discover_schemas(schema_dir, creative_only=creative_only) + print(f" Found {len(refs)} unique schema refs") + + # Download and update each schema + print("\nšŸ“„ Downloading latest schemas...") + updated = 0 + unchanged = 0 + failed = 0 + + for ref in refs: + # Validate ref + if not ref.startswith("/schemas/v1/"): + print(f" āš ļø Skipping invalid ref: {ref}") + continue + + # Download latest version + latest_schema = download_schema(ref) + if latest_schema is None: + failed += 1 + continue + + # Compare with local version + filename = ref_to_filename(ref) + local_path = schema_dir / filename + + if local_path.exists(): + with open(local_path) as f: + local_schema = json.load(f) + + if local_schema == latest_schema: + print(f" āœ“ No changes: {filename}") + unchanged += 1 + continue + + # Update local file + if dry_run: + print(f" šŸ”„ Would update: {filename}") + updated += 1 + else: + with open(local_path, "w") as f: + json.dump(latest_schema, f, indent=2) + f.write("\n") # Add trailing newline + print(f" āœ… Updated: {filename}") + updated += 1 + + # Summary + print(f"\nšŸ“Š Summary:") + print(f" Updated: {updated}") + print(f" Unchanged: {unchanged}") + print(f" Failed: {failed}") + + if dry_run: + print("\n (Dry run - no files were modified)") + + if updated > 0 and not dry_run: + print("\nšŸ’” Next steps:") + print(" 1. Review changes: git diff tests/schemas/v1/") + print(" 2. Regenerate Python models: python scripts/generate_schemas.py") + print(" 3. Run tests: pytest") + + +def main(): + parser = argparse.ArgumentParser( + description="Update AdCP schemas from website (creative-agent-relevant schemas only by default)" + ) + parser.add_argument("--dry-run", action="store_true", help="Show what would be updated without making changes") + parser.add_argument( + "--schema-dir", + type=Path, + default=Path("tests/schemas/v1"), + help="Directory containing JSON schemas (default: tests/schemas/v1)", + ) + parser.add_argument( + "--all-schemas", + action="store_true", + help="Include all AdCP schemas (media buy, signals, etc.), not just creative-agent schemas", + ) + args = parser.parse_args() + + update_schemas(args.schema_dir, dry_run=args.dry_run, creative_only=not args.all_schemas) + + +if __name__ == "__main__": + main() diff --git a/src/creative_agent/schemas/__init__.py b/src/creative_agent/schemas/__init__.py index e19c6f9..6ce8dbc 100644 --- a/src/creative_agent/schemas/__init__.py +++ b/src/creative_agent/schemas/__init__.py @@ -27,8 +27,8 @@ # Format schemas from ..schemas_generated._schemas_v1_core_format_json import Format as CreativeFormat -from ..schemas_generated._schemas_v1_media_buy_list_creative_formats_response_json import ( - ListCreativeFormatsResponse, +from ..schemas_generated._schemas_v1_creative_list_creative_formats_response_json import ( + ListCreativeFormatsResponseCreativeAgent as ListCreativeFormatsResponse, ) # Build schemas (agent-specific, not part of AdCP) diff --git a/src/creative_agent/schemas_generated/_schemas_v1_core_brand_manifest_json.py b/src/creative_agent/schemas_generated/_schemas_v1_core_brand_manifest_json.py index e6700f3..db500f3 100644 --- a/src/creative_agent/schemas_generated/_schemas_v1_core_brand_manifest_json.py +++ b/src/creative_agent/schemas_generated/_schemas_v1_core_brand_manifest_json.py @@ -251,68 +251,10 @@ class BrandManifest1(BaseModel): ] = None -class Asset3(BaseModel): - model_config = ConfigDict( - extra="forbid", - ) - asset_id: Annotated[str, Field(description="Unique identifier for this asset")] - asset_type: Annotated[AssetType, Field(description="Type of asset")] - url: Annotated[AnyUrl, Field(description="URL to CDN-hosted asset file")] - tags: Annotated[ - Optional[list[str]], - Field( - description="Tags for asset discovery (e.g., 'holiday', 'lifestyle', 'product_shot')" - ), - ] = None - name: Annotated[Optional[str], Field(description="Human-readable asset name")] = ( - None - ) - description: Annotated[ - Optional[str], Field(description="Asset description or usage notes") - ] = None - width: Annotated[ - Optional[int], Field(description="Image/video width in pixels") - ] = None - height: Annotated[ - Optional[int], Field(description="Image/video height in pixels") - ] = None - duration_seconds: Annotated[ - Optional[float], Field(description="Video/audio duration in seconds") - ] = None - file_size_bytes: Annotated[ - Optional[int], Field(description="File size in bytes") - ] = None - format: Annotated[ - Optional[str], Field(description="File format (e.g., 'jpg', 'mp4', 'mp3')") - ] = None - metadata: Annotated[ - Optional[dict[str, Any]], - Field(description="Additional asset-specific metadata"), - ] = None +Asset3 = Asset -class ProductCatalog3(BaseModel): - model_config = ConfigDict( - extra="forbid", - ) - feed_url: Annotated[AnyUrl, Field(description="URL to product catalog feed")] - feed_format: Annotated[ - Optional[FeedFormat], Field(description="Format of the product feed") - ] = "google_merchant_center" - categories: Annotated[ - Optional[list[str]], - Field( - description="Product categories available in the catalog (for filtering)" - ), - ] = None - last_updated: Annotated[ - Optional[AwareDatetime], - Field(description="When the product catalog was last updated"), - ] = None - update_frequency: Annotated[ - Optional[UpdateFrequency], - Field(description="How frequently the product catalog is updated"), - ] = None +ProductCatalog3 = ProductCatalog class BrandManifest2(BaseModel): diff --git a/src/creative_agent/schemas_generated/_schemas_v1_core_brand_manifest_ref_json.py b/src/creative_agent/schemas_generated/_schemas_v1_core_brand_manifest_ref_json.py index cf100d7..7ebba19 100644 --- a/src/creative_agent/schemas_generated/_schemas_v1_core_brand_manifest_ref_json.py +++ b/src/creative_agent/schemas_generated/_schemas_v1_core_brand_manifest_ref_json.py @@ -251,68 +251,10 @@ class BrandManifestReference1(BaseModel): ] = None -class Asset1(BaseModel): - model_config = ConfigDict( - extra="forbid", - ) - asset_id: Annotated[str, Field(description="Unique identifier for this asset")] - asset_type: Annotated[AssetType, Field(description="Type of asset")] - url: Annotated[AnyUrl, Field(description="URL to CDN-hosted asset file")] - tags: Annotated[ - Optional[list[str]], - Field( - description="Tags for asset discovery (e.g., 'holiday', 'lifestyle', 'product_shot')" - ), - ] = None - name: Annotated[Optional[str], Field(description="Human-readable asset name")] = ( - None - ) - description: Annotated[ - Optional[str], Field(description="Asset description or usage notes") - ] = None - width: Annotated[ - Optional[int], Field(description="Image/video width in pixels") - ] = None - height: Annotated[ - Optional[int], Field(description="Image/video height in pixels") - ] = None - duration_seconds: Annotated[ - Optional[float], Field(description="Video/audio duration in seconds") - ] = None - file_size_bytes: Annotated[ - Optional[int], Field(description="File size in bytes") - ] = None - format: Annotated[ - Optional[str], Field(description="File format (e.g., 'jpg', 'mp4', 'mp3')") - ] = None - metadata: Annotated[ - Optional[dict[str, Any]], - Field(description="Additional asset-specific metadata"), - ] = None +Asset1 = Asset -class ProductCatalog1(BaseModel): - model_config = ConfigDict( - extra="forbid", - ) - feed_url: Annotated[AnyUrl, Field(description="URL to product catalog feed")] - feed_format: Annotated[ - Optional[FeedFormat], Field(description="Format of the product feed") - ] = "google_merchant_center" - categories: Annotated[ - Optional[list[str]], - Field( - description="Product categories available in the catalog (for filtering)" - ), - ] = None - last_updated: Annotated[ - Optional[AwareDatetime], - Field(description="When the product catalog was last updated"), - ] = None - update_frequency: Annotated[ - Optional[UpdateFrequency], - Field(description="How frequently the product catalog is updated"), - ] = None +ProductCatalog1 = ProductCatalog class BrandManifestReference2(BaseModel): diff --git a/src/creative_agent/schemas_generated/_schemas_v1_core_budget_json.py b/src/creative_agent/schemas_generated/_schemas_v1_core_budget_json.py deleted file mode 100644 index b869a19..0000000 --- a/src/creative_agent/schemas_generated/_schemas_v1_core_budget_json.py +++ /dev/null @@ -1,33 +0,0 @@ -# generated by datamodel-codegen: -# filename: _schemas_v1_core_budget_json.json - -from __future__ import annotations - -from enum import Enum -from typing import Annotated, Optional - -from pydantic import BaseModel, ConfigDict, Field - - -class Pacing(Enum): - even = "even" - asap = "asap" - front_loaded = "front_loaded" - - -class Budget(BaseModel): - model_config = ConfigDict( - extra="forbid", - ) - total: Annotated[float, Field(description="Total budget amount", ge=0.0)] - currency: Annotated[ - str, - Field( - description="ISO 4217 currency code", - examples=["USD", "EUR", "GBP"], - pattern="^[A-Z]{3}$", - ), - ] - pacing: Annotated[ - Optional[Pacing], Field(description="Budget pacing strategy", title="Pacing") - ] = None diff --git a/src/creative_agent/schemas_generated/_schemas_v1_core_creative_manifest_json.py b/src/creative_agent/schemas_generated/_schemas_v1_core_creative_manifest_json.py new file mode 100644 index 0000000..cd16b5e --- /dev/null +++ b/src/creative_agent/schemas_generated/_schemas_v1_core_creative_manifest_json.py @@ -0,0 +1,358 @@ +# generated by datamodel-codegen: +# filename: _schemas_v1_core_creative-manifest_json.json + +from __future__ import annotations + +from enum import Enum +from typing import Annotated, Literal, Optional, Union + +from pydantic import AnyUrl, BaseModel, ConfigDict, Field + + +class FormatId(BaseModel): + model_config = ConfigDict( + extra="forbid", + ) + 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)" + ), + ] + id: Annotated[ + str, + Field( + description="Format identifier within the agent's namespace (e.g., 'display_300x250', 'video_standard_30s')", + pattern="^[a-zA-Z0-9_-]+$", + ), + ] + + +class Format(Enum): + jpg = "jpg" + jpeg = "jpeg" + png = "png" + gif = "gif" + webp = "webp" + svg = "svg" + + +class Assets(BaseModel): + model_config = ConfigDict( + extra="forbid", + ) + asset_type: Literal["image"] + url: Annotated[AnyUrl, Field(description="URL to hosted image asset")] + width: Annotated[int, Field(description="Image width in pixels", ge=1)] + height: Annotated[int, Field(description="Image height in pixels", ge=1)] + format: Annotated[Optional[Format], Field(description="Image file format")] = None + file_size: Annotated[ + Optional[int], Field(description="File size in bytes", ge=0) + ] = None + alt: Annotated[ + Optional[str], Field(description="Alternative text for accessibility") + ] = None + + +class Format1(Enum): + mp4 = "mp4" + webm = "webm" + mov = "mov" + + +class Codec(Enum): + h264 = "h264" + h265 = "h265" + vp8 = "vp8" + vp9 = "vp9" + av1 = "av1" + + +class Assets12(BaseModel): + model_config = ConfigDict( + extra="forbid", + ) + asset_type: Literal["video"] + url: Annotated[AnyUrl, Field(description="URL to hosted video asset")] + width: Annotated[int, Field(description="Video width in pixels", ge=1)] + height: Annotated[int, Field(description="Video height in pixels", ge=1)] + duration_seconds: Annotated[ + float, Field(description="Video duration in seconds", ge=0.0) + ] + format: Annotated[ + Optional[Format1], Field(description="Video container format") + ] = None + codec: Annotated[Optional[Codec], Field(description="Video codec")] = None + bitrate_mbps: Annotated[ + Optional[float], Field(description="Video bitrate in Mbps", ge=0.0) + ] = None + file_size: Annotated[ + Optional[int], Field(description="File size in bytes", ge=0) + ] = None + aspect_ratio: Annotated[ + Optional[str], + Field(description="Aspect ratio (e.g., '16:9', '9:16')", pattern="^\\d+:\\d+$"), + ] = None + + +class Format2(Enum): + mp3 = "mp3" + aac = "aac" + m4a = "m4a" + wav = "wav" + ogg = "ogg" + + +class Codec1(Enum): + mp3 = "mp3" + aac = "aac" + opus = "opus" + vorbis = "vorbis" + + +class SampleRateHz(Enum): + integer_22050 = 22050 + integer_44100 = 44100 + integer_48000 = 48000 + integer_96000 = 96000 + + +class Channels(Enum): + mono = "mono" + stereo = "stereo" + field_5_1 = "5.1" + field_7_1 = "7.1" + + +class Assets13(BaseModel): + model_config = ConfigDict( + extra="forbid", + ) + asset_type: Literal["audio"] + url: Annotated[AnyUrl, Field(description="URL to hosted audio asset")] + duration_seconds: Annotated[ + float, Field(description="Audio duration in seconds", ge=0.0) + ] + format: Annotated[Optional[Format2], Field(description="Audio file format")] = None + codec: Annotated[Optional[Codec1], Field(description="Audio codec")] = None + bitrate_kbps: Annotated[ + Optional[float], Field(description="Audio bitrate in Kbps", ge=0.0) + ] = None + sample_rate_hz: Annotated[ + Optional[SampleRateHz], Field(description="Sample rate in Hz") + ] = None + channels: Annotated[ + Optional[Channels], Field(description="Audio channel configuration") + ] = None + file_size: Annotated[ + Optional[int], Field(description="File size in bytes", ge=0) + ] = None + + +class VastVersion(Enum): + field_2_0 = "2.0" + field_3_0 = "3.0" + field_4_0 = "4.0" + field_4_1 = "4.1" + field_4_2 = "4.2" + + +class Assets14(BaseModel): + model_config = ConfigDict( + extra="forbid", + ) + asset_type: Literal["vast_tag"] + content: Annotated[str, Field(description="Complete VAST XML content")] + vast_version: Annotated[ + VastVersion, Field(description="VAST specification version") + ] + vpaid_enabled: Annotated[ + Optional[bool], Field(description="Whether VPAID is used") + ] = None + duration_seconds: Annotated[ + Optional[float], Field(description="Expected video duration in seconds", ge=0.0) + ] = None + + +class Format3(Enum): + plain = "plain" + html = "html" + markdown = "markdown" + + +class Assets15(BaseModel): + model_config = ConfigDict( + extra="forbid", + ) + asset_type: Literal["text"] + content: Annotated[str, Field(description="Text content")] + length: Annotated[Optional[int], Field(description="Character count", ge=0)] = None + format: Annotated[Optional[Format3], Field(description="Text format")] = "plain" + + +class Purpose(Enum): + clickthrough = "clickthrough" + landing_page = "landing_page" + tracking_pixel = "tracking_pixel" + impression_tracker = "impression_tracker" + + +class Assets16(BaseModel): + model_config = ConfigDict( + extra="forbid", + ) + asset_type: Literal["url"] + url: Annotated[AnyUrl, Field(description="The URL")] + purpose: Annotated[Optional[Purpose], Field(description="Purpose of this URL")] = ( + None + ) + + +class Method(Enum): + get = "GET" + post = "POST" + + +class ResponseType(Enum): + html = "html" + json = "json" + xml = "xml" + javascript = "javascript" + + +class Method1(Enum): + hmac_sha256 = "hmac_sha256" + api_key = "api_key" + none = "none" + + +class Security(BaseModel): + method: Method1 + hmac_header: Optional[str] = None + api_key_header: Optional[str] = None + + +class Assets17(BaseModel): + model_config = ConfigDict( + extra="forbid", + ) + asset_type: Literal["webhook"] + url: Annotated[AnyUrl, Field(description="Webhook URL to call for dynamic content")] + method: Optional[Method] = "POST" + timeout_ms: Annotated[Optional[int], Field(ge=10, le=5000)] = 500 + supported_macros: Annotated[ + Optional[list[str]], + Field(description="Universal macros that can be passed to webhook"), + ] = None + required_macros: Annotated[ + Optional[list[str]], Field(description="Universal macros that must be provided") + ] = None + response_type: ResponseType + security: Security + fallback_required: Optional[bool] = True + + +class Assets18(BaseModel): + model_config = ConfigDict( + extra="forbid", + ) + asset_type: Literal["html"] + content: Annotated[str, Field(description="Complete HTML content")] + url: Annotated[ + Optional[AnyUrl], Field(description="URL to externally hosted HTML file") + ] = None + width: Annotated[Optional[int], Field(description="Ad width in pixels", ge=1)] = ( + None + ) + height: Annotated[Optional[int], Field(description="Ad height in pixels", ge=1)] = ( + None + ) + file_size: Annotated[ + Optional[int], Field(description="Total file size in bytes", ge=0) + ] = None + + +class Assets19(BaseModel): + model_config = ConfigDict( + extra="forbid", + ) + asset_type: Literal["html"] + content: Annotated[Optional[str], Field(description="Complete HTML content")] = None + url: Annotated[AnyUrl, Field(description="URL to externally hosted HTML file")] + width: Annotated[Optional[int], Field(description="Ad width in pixels", ge=1)] = ( + None + ) + height: Annotated[Optional[int], Field(description="Ad height in pixels", ge=1)] = ( + None + ) + file_size: Annotated[ + Optional[int], Field(description="Total file size in bytes", ge=0) + ] = None + + +class Assets20(BaseModel): + model_config = ConfigDict( + extra="forbid", + ) + asset_type: Literal["javascript"] + content: Annotated[str, Field(description="JavaScript code content")] + url: Annotated[ + Optional[AnyUrl], Field(description="URL to external JavaScript file") + ] = None + inline: Annotated[ + Optional[bool], + Field(description="Whether code should be inlined vs external script tag"), + ] = None + + +class Assets21(BaseModel): + model_config = ConfigDict( + extra="forbid", + ) + asset_type: Literal["javascript"] + content: Annotated[Optional[str], Field(description="JavaScript code content")] = ( + None + ) + url: Annotated[AnyUrl, Field(description="URL to external JavaScript file")] + inline: Annotated[ + Optional[bool], + Field(description="Whether code should be inlined vs external script tag"), + ] = None + + +class CreativeManifest(BaseModel): + model_config = ConfigDict( + extra="forbid", + ) + format_id: Annotated[ + FormatId, + Field( + description="Structured format identifier with agent URL and format name", + title="Format ID", + ), + ] + promoted_offering: Annotated[ + Optional[str], + Field( + description="Product name or offering being advertised. Maps to promoted_offerings in create_media_buy request to associate creative with the product being promoted." + ), + ] = None + assets: Annotated[ + dict[ + str, + Union[ + Assets, + Assets12, + Assets13, + Assets14, + Assets15, + Assets16, + Assets17, + Union[Assets18, Assets19], + Union[Assets20, Assets21], + ], + ], + Field( + description="Map of asset roles (from format spec) to actual asset content. Each key is an asset_role defined by the format (e.g., 'hero_image', 'logo', 'headline', 'video_file', 'vast_tag')." + ), + ] diff --git a/src/creative_agent/schemas_generated/_schemas_v1_core_delivery_metrics_json.py b/src/creative_agent/schemas_generated/_schemas_v1_core_delivery_metrics_json.py deleted file mode 100644 index 27b6dec..0000000 --- a/src/creative_agent/schemas_generated/_schemas_v1_core_delivery_metrics_json.py +++ /dev/null @@ -1,147 +0,0 @@ -# generated by datamodel-codegen: -# filename: _schemas_v1_core_delivery-metrics_json.json - -from __future__ import annotations - -from typing import Annotated, Optional - -from pydantic import BaseModel, ConfigDict, Field - - -class QuartileData(BaseModel): - q1_views: Annotated[ - Optional[float], Field(description="25% completion views", ge=0.0) - ] = None - q2_views: Annotated[ - Optional[float], Field(description="50% completion views", ge=0.0) - ] = None - q3_views: Annotated[ - Optional[float], Field(description="75% completion views", ge=0.0) - ] = None - q4_views: Annotated[ - Optional[float], Field(description="100% completion views", ge=0.0) - ] = None - - -class VenueBreakdownItem(BaseModel): - model_config = ConfigDict( - extra="forbid", - ) - venue_id: Annotated[str, Field(description="Venue identifier")] - venue_name: Annotated[ - Optional[str], Field(description="Human-readable venue name") - ] = None - venue_type: Annotated[ - Optional[str], - Field( - description="Venue type (e.g., 'airport', 'transit', 'retail', 'billboard')" - ), - ] = None - impressions: Annotated[ - int, Field(description="Impressions delivered at this venue", ge=0) - ] - loop_plays: Annotated[ - Optional[int], Field(description="Loop plays at this venue", ge=0) - ] = None - screens_used: Annotated[ - Optional[int], Field(description="Number of screens used at this venue", ge=0) - ] = None - - -class DoohMetrics(BaseModel): - model_config = ConfigDict( - extra="forbid", - ) - loop_plays: Annotated[ - Optional[int], Field(description="Number of times ad played in rotation", ge=0) - ] = None - screens_used: Annotated[ - Optional[int], - Field(description="Number of unique screens displaying the ad", ge=0), - ] = None - screen_time_seconds: Annotated[ - Optional[int], Field(description="Total display time in seconds", ge=0) - ] = None - sov_achieved: Annotated[ - Optional[float], - Field( - description="Actual share of voice delivered (0.0 to 1.0)", ge=0.0, le=1.0 - ), - ] = None - calculation_notes: Annotated[ - Optional[str], - Field(description="Explanation of how DOOH impressions were calculated"), - ] = None - venue_breakdown: Annotated[ - Optional[list[VenueBreakdownItem]], - Field(description="Per-venue performance breakdown"), - ] = None - - -class DeliveryMetrics(BaseModel): - model_config = ConfigDict( - extra="allow", - ) - impressions: Annotated[ - Optional[float], Field(description="Impressions delivered", ge=0.0) - ] = None - spend: Annotated[Optional[float], Field(description="Amount spent", ge=0.0)] = None - clicks: Annotated[Optional[float], Field(description="Total clicks", ge=0.0)] = None - ctr: Annotated[ - Optional[float], - Field(description="Click-through rate (clicks/impressions)", ge=0.0, le=1.0), - ] = None - views: Annotated[ - Optional[float], Field(description="Views at threshold (for CPV)", ge=0.0) - ] = None - completed_views: Annotated[ - Optional[float], Field(description="100% completions (for CPCV)", ge=0.0) - ] = None - video_completions: Annotated[ - Optional[float], - Field(description="DEPRECATED: Use completed_views instead", ge=0.0), - ] = None - completion_rate: Annotated[ - Optional[float], - Field( - description="Completion rate (completed_views/impressions)", ge=0.0, le=1.0 - ), - ] = None - conversions: Annotated[ - Optional[float], - Field( - description="Conversions (reserved for future CPA pricing support)", ge=0.0 - ), - ] = None - leads: Annotated[ - Optional[float], - Field( - description="Leads generated (reserved for future CPL pricing support)", - ge=0.0, - ), - ] = None - grps: Annotated[ - Optional[float], - Field(description="Gross Rating Points delivered (for CPP)", ge=0.0), - ] = None - reach: Annotated[ - Optional[float], - Field( - description="Unique reach - units depend on measurement provider (e.g., individuals, households, devices, cookies). See delivery_measurement.provider for methodology.", - ge=0.0, - ), - ] = None - frequency: Annotated[ - Optional[float], - Field( - description="Average frequency per individual (typically measured over campaign duration, but can vary by measurement provider)", - ge=0.0, - ), - ] = None - quartile_data: Annotated[ - Optional[QuartileData], Field(description="Video quartile completion data") - ] = None - dooh_metrics: Annotated[ - Optional[DoohMetrics], - Field(description="DOOH-specific metrics (only included for DOOH campaigns)"), - ] = None diff --git a/src/creative_agent/schemas_generated/_schemas_v1_core_frequency_cap_json.py b/src/creative_agent/schemas_generated/_schemas_v1_core_frequency_cap_json.py deleted file mode 100644 index 18ffdd3..0000000 --- a/src/creative_agent/schemas_generated/_schemas_v1_core_frequency_cap_json.py +++ /dev/null @@ -1,17 +0,0 @@ -# generated by datamodel-codegen: -# filename: _schemas_v1_core_frequency-cap_json.json - -from __future__ import annotations - -from typing import Annotated - -from pydantic import BaseModel, ConfigDict, Field - - -class FrequencyCap(BaseModel): - model_config = ConfigDict( - extra="forbid", - ) - suppress_minutes: Annotated[ - float, Field(description="Minutes to suppress after impression", ge=0.0) - ] diff --git a/src/creative_agent/schemas_generated/_schemas_v1_core_measurement_json.py b/src/creative_agent/schemas_generated/_schemas_v1_core_measurement_json.py deleted file mode 100644 index b592a84..0000000 --- a/src/creative_agent/schemas_generated/_schemas_v1_core_measurement_json.py +++ /dev/null @@ -1,39 +0,0 @@ -# generated by datamodel-codegen: -# filename: _schemas_v1_core_measurement_json.json - -from __future__ import annotations - -from typing import Annotated, Optional - -from pydantic import BaseModel, ConfigDict, Field - - -class Measurement(BaseModel): - model_config = ConfigDict( - extra="forbid", - ) - type: Annotated[ - str, - Field( - description="Type of measurement", - examples=["incremental_sales_lift", "brand_lift", "foot_traffic"], - ), - ] - attribution: Annotated[ - str, - Field( - description="Attribution methodology", - examples=["deterministic_purchase", "probabilistic"], - ), - ] - window: Annotated[ - Optional[str], - Field(description="Attribution window", examples=["30_days", "7_days"]), - ] = None - reporting: Annotated[ - str, - Field( - description="Reporting frequency and format", - examples=["weekly_dashboard", "real_time_api"], - ), - ] diff --git a/src/creative_agent/schemas_generated/_schemas_v1_core_media_buy_json.py b/src/creative_agent/schemas_generated/_schemas_v1_core_media_buy_json.py deleted file mode 100644 index 14e509f..0000000 --- a/src/creative_agent/schemas_generated/_schemas_v1_core_media_buy_json.py +++ /dev/null @@ -1,163 +0,0 @@ -# generated by datamodel-codegen: -# filename: _schemas_v1_core_media-buy_json.json - -from __future__ import annotations - -from enum import Enum -from typing import Annotated, Optional - -from pydantic import AwareDatetime, BaseModel, ConfigDict, Field, RootModel - - -class Status(Enum): - pending_activation = "pending_activation" - active = "active" - paused = "paused" - completed = "completed" - - -class GeoCountryAnyOfItem(RootModel[str]): - root: Annotated[str, Field(pattern="^[A-Z]{2}$")] - - -class FrequencyCap(BaseModel): - model_config = ConfigDict( - extra="forbid", - ) - suppress_minutes: Annotated[ - float, Field(description="Minutes to suppress after impression", ge=0.0) - ] - - -class TargetingOverlay(BaseModel): - model_config = ConfigDict( - extra="forbid", - ) - geo_country_any_of: Annotated[ - Optional[list[GeoCountryAnyOfItem]], - Field( - description="Restrict delivery to specific countries (ISO codes). Use for regulatory compliance or RCT testing." - ), - ] = None - geo_region_any_of: Annotated[ - Optional[list[str]], - Field( - description="Restrict delivery to specific regions/states. Use for regulatory compliance or RCT testing." - ), - ] = None - geo_metro_any_of: Annotated[ - Optional[list[str]], - Field( - description="Restrict delivery to specific metro areas (DMA codes). Use for regulatory compliance or RCT testing." - ), - ] = None - geo_postal_code_any_of: Annotated[ - Optional[list[str]], - Field( - description="Restrict delivery to specific postal/ZIP codes. Use for regulatory compliance or RCT testing." - ), - ] = None - frequency_cap: Annotated[ - Optional[FrequencyCap], - Field( - description="Frequency capping settings for package-level application", - title="Frequency Cap", - ), - ] = None - - -class CreativeAssignment(BaseModel): - model_config = ConfigDict( - extra="forbid", - ) - creative_id: Annotated[str, Field(description="Unique identifier for the creative")] - weight: Annotated[ - Optional[float], - Field(description="Delivery weight for this creative", ge=0.0, le=100.0), - ] = None - - -class Status3(Enum): - draft = "draft" - active = "active" - paused = "paused" - completed = "completed" - - -class Package(BaseModel): - model_config = ConfigDict( - extra="forbid", - ) - package_id: Annotated[ - str, Field(description="Publisher's unique identifier for the package") - ] - buyer_ref: Annotated[ - Optional[str], - Field(description="Buyer's reference identifier for this package"), - ] = None - product_id: Annotated[ - Optional[str], Field(description="ID of the product this package is based on") - ] = None - budget: Annotated[ - Optional[float], - Field( - description="Budget allocation for this package in the currency specified by the pricing option", - ge=0.0, - ), - ] = None - impressions: Annotated[ - Optional[float], Field(description="Impression goal for this package", ge=0.0) - ] = None - targeting_overlay: Annotated[ - Optional[TargetingOverlay], - Field( - description="Optional geographic refinements for media buys. Most targeting should be expressed in the brief and handled by the publisher. These fields are primarily for geographic restrictions (RCT testing, regulatory compliance).", - title="Targeting Overlay", - ), - ] = None - creative_assignments: Annotated[ - Optional[list[CreativeAssignment]], - Field(description="Creative assets assigned to this package"), - ] = None - formats_to_provide: Annotated[ - Optional[list[str]], - Field( - description="Format IDs that creative assets will be provided for this package" - ), - ] = None - status: Annotated[ - Status3, Field(description="Status of a package", title="Package Status") - ] - - -class MediaBuy(BaseModel): - model_config = ConfigDict( - extra="forbid", - ) - media_buy_id: Annotated[ - str, Field(description="Publisher's unique identifier for the media buy") - ] - buyer_ref: Annotated[ - Optional[str], - Field(description="Buyer's reference identifier for this media buy"), - ] = None - status: Annotated[ - Status, Field(description="Status of a media buy", title="Media Buy Status") - ] - promoted_offering: Annotated[ - str, Field(description="Description of advertiser and what is being promoted") - ] - total_budget: Annotated[float, Field(description="Total budget amount", ge=0.0)] - packages: Annotated[ - list[Package], Field(description="Array of packages within this media buy") - ] - creative_deadline: Annotated[ - Optional[AwareDatetime], - Field(description="ISO 8601 timestamp for creative upload deadline"), - ] = None - created_at: Annotated[ - Optional[AwareDatetime], Field(description="Creation timestamp") - ] = None - updated_at: Annotated[ - Optional[AwareDatetime], Field(description="Last update timestamp") - ] = None diff --git a/src/creative_agent/schemas_generated/_schemas_v1_core_package_json.py b/src/creative_agent/schemas_generated/_schemas_v1_core_package_json.py deleted file mode 100644 index 1da01a4..0000000 --- a/src/creative_agent/schemas_generated/_schemas_v1_core_package_json.py +++ /dev/null @@ -1,123 +0,0 @@ -# generated by datamodel-codegen: -# filename: _schemas_v1_core_package_json.json - -from __future__ import annotations - -from enum import Enum -from typing import Annotated, Optional - -from pydantic import BaseModel, ConfigDict, Field, RootModel - - -class GeoCountryAnyOfItem(RootModel[str]): - root: Annotated[str, Field(pattern="^[A-Z]{2}$")] - - -class FrequencyCap(BaseModel): - model_config = ConfigDict( - extra="forbid", - ) - suppress_minutes: Annotated[ - float, Field(description="Minutes to suppress after impression", ge=0.0) - ] - - -class TargetingOverlay(BaseModel): - model_config = ConfigDict( - extra="forbid", - ) - geo_country_any_of: Annotated[ - Optional[list[GeoCountryAnyOfItem]], - Field( - description="Restrict delivery to specific countries (ISO codes). Use for regulatory compliance or RCT testing." - ), - ] = None - geo_region_any_of: Annotated[ - Optional[list[str]], - Field( - description="Restrict delivery to specific regions/states. Use for regulatory compliance or RCT testing." - ), - ] = None - geo_metro_any_of: Annotated[ - Optional[list[str]], - Field( - description="Restrict delivery to specific metro areas (DMA codes). Use for regulatory compliance or RCT testing." - ), - ] = None - geo_postal_code_any_of: Annotated[ - Optional[list[str]], - Field( - description="Restrict delivery to specific postal/ZIP codes. Use for regulatory compliance or RCT testing." - ), - ] = None - frequency_cap: Annotated[ - Optional[FrequencyCap], - Field( - description="Frequency capping settings for package-level application", - title="Frequency Cap", - ), - ] = None - - -class CreativeAssignment(BaseModel): - model_config = ConfigDict( - extra="forbid", - ) - creative_id: Annotated[str, Field(description="Unique identifier for the creative")] - weight: Annotated[ - Optional[float], - Field(description="Delivery weight for this creative", ge=0.0, le=100.0), - ] = None - - -class Status(Enum): - draft = "draft" - active = "active" - paused = "paused" - completed = "completed" - - -class Package(BaseModel): - model_config = ConfigDict( - extra="forbid", - ) - package_id: Annotated[ - str, Field(description="Publisher's unique identifier for the package") - ] - buyer_ref: Annotated[ - Optional[str], - Field(description="Buyer's reference identifier for this package"), - ] = None - product_id: Annotated[ - Optional[str], Field(description="ID of the product this package is based on") - ] = None - budget: Annotated[ - Optional[float], - Field( - description="Budget allocation for this package in the currency specified by the pricing option", - ge=0.0, - ), - ] = None - impressions: Annotated[ - Optional[float], Field(description="Impression goal for this package", ge=0.0) - ] = None - targeting_overlay: Annotated[ - Optional[TargetingOverlay], - Field( - description="Optional geographic refinements for media buys. Most targeting should be expressed in the brief and handled by the publisher. These fields are primarily for geographic restrictions (RCT testing, regulatory compliance).", - title="Targeting Overlay", - ), - ] = None - creative_assignments: Annotated[ - Optional[list[CreativeAssignment]], - Field(description="Creative assets assigned to this package"), - ] = None - formats_to_provide: Annotated[ - Optional[list[str]], - Field( - description="Format IDs that creative assets will be provided for this package" - ), - ] = None - status: Annotated[ - Status, Field(description="Status of a package", title="Package Status") - ] diff --git a/src/creative_agent/schemas_generated/_schemas_v1_core_pricing_option_json.py b/src/creative_agent/schemas_generated/_schemas_v1_core_pricing_option_json.py deleted file mode 100644 index 4921d54..0000000 --- a/src/creative_agent/schemas_generated/_schemas_v1_core_pricing_option_json.py +++ /dev/null @@ -1,404 +0,0 @@ -# generated by datamodel-codegen: -# filename: _schemas_v1_core_pricing-option_json.json - -from __future__ import annotations - -from typing import Annotated, Literal, Optional, Union - -from pydantic import BaseModel, ConfigDict, Field, RootModel - - -class PricingOption1(BaseModel): - model_config = ConfigDict( - extra="forbid", - ) - pricing_option_id: Annotated[ - str, - Field( - description="Unique identifier for this pricing option within the product (e.g., 'cpm_usd_guaranteed')" - ), - ] - pricing_model: Annotated[ - Literal["cpm"], Field(description="Cost per 1,000 impressions") - ] - rate: Annotated[ - float, Field(description="Fixed CPM rate (cost per 1,000 impressions)", ge=0.0) - ] - currency: Annotated[ - str, - Field( - description="ISO 4217 currency code", - examples=["USD", "EUR", "GBP", "JPY"], - pattern="^[A-Z]{3}$", - ), - ] - min_spend_per_package: Annotated[ - Optional[float], - Field( - description="Minimum spend requirement per package using this pricing option, in the specified currency", - ge=0.0, - ), - ] = None - - -class PriceGuidance(BaseModel): - floor: Annotated[ - float, - Field( - description="Minimum bid price - publisher will reject bids under this value", - ge=0.0, - ), - ] - p25: Annotated[ - Optional[float], Field(description="25th percentile winning price", ge=0.0) - ] = None - p50: Annotated[ - Optional[float], Field(description="Median winning price", ge=0.0) - ] = None - p75: Annotated[ - Optional[float], Field(description="75th percentile winning price", ge=0.0) - ] = None - p90: Annotated[ - Optional[float], Field(description="90th percentile winning price", ge=0.0) - ] = None - - -class PricingOption2(BaseModel): - model_config = ConfigDict( - extra="forbid", - ) - pricing_option_id: Annotated[ - str, - Field( - description="Unique identifier for this pricing option within the product (e.g., 'cpm_usd_auction')" - ), - ] - pricing_model: Annotated[ - Literal["cpm"], Field(description="Cost per 1,000 impressions") - ] - currency: Annotated[ - str, - Field( - description="ISO 4217 currency code", - examples=["USD", "EUR", "GBP", "JPY"], - pattern="^[A-Z]{3}$", - ), - ] - price_guidance: Annotated[ - PriceGuidance, - Field(description="Pricing guidance for auction-based CPM bidding"), - ] - min_spend_per_package: Annotated[ - Optional[float], - Field( - description="Minimum spend requirement per package using this pricing option, in the specified currency", - ge=0.0, - ), - ] = None - - -class PricingOption3(BaseModel): - model_config = ConfigDict( - extra="forbid", - ) - pricing_option_id: Annotated[ - str, - Field( - description="Unique identifier for this pricing option within the product (e.g., 'cpc_usd_fixed')" - ), - ] - pricing_model: Annotated[Literal["cpc"], Field(description="Cost per click")] - rate: Annotated[float, Field(description="Fixed CPC rate (cost per click)", ge=0.0)] - currency: Annotated[ - str, - Field( - description="ISO 4217 currency code", - examples=["USD", "EUR", "GBP", "JPY"], - pattern="^[A-Z]{3}$", - ), - ] - min_spend_per_package: Annotated[ - Optional[float], - Field( - description="Minimum spend requirement per package using this pricing option, in the specified currency", - ge=0.0, - ), - ] = None - - -class PricingOption4(BaseModel): - model_config = ConfigDict( - extra="forbid", - ) - pricing_option_id: Annotated[ - str, - Field( - description="Unique identifier for this pricing option within the product (e.g., 'cpcv_usd_guaranteed')" - ), - ] - pricing_model: Annotated[ - Literal["cpcv"], Field(description="Cost per completed view (100% completion)") - ] - rate: Annotated[ - float, Field(description="Fixed CPCV rate (cost per 100% completion)", ge=0.0) - ] - currency: Annotated[ - str, - Field( - description="ISO 4217 currency code", - examples=["USD", "EUR", "GBP", "JPY"], - pattern="^[A-Z]{3}$", - ), - ] - min_spend_per_package: Annotated[ - Optional[float], - Field( - description="Minimum spend requirement per package using this pricing option, in the specified currency", - ge=0.0, - ), - ] = None - - -class ViewThreshold(RootModel[float]): - root: Annotated[ - float, - Field( - description="Percentage completion threshold for CPV pricing (0.0 to 1.0, e.g., 0.5 = 50% completion)", - ge=0.0, - le=1.0, - ), - ] - - -class ViewThreshold1(BaseModel): - model_config = ConfigDict( - extra="forbid", - ) - duration_seconds: Annotated[ - int, - Field( - description="Seconds of viewing required (e.g., 30 for YouTube-style '30 seconds = view')", - ge=1, - ), - ] - - -class Parameters(BaseModel): - model_config = ConfigDict( - extra="forbid", - ) - view_threshold: Union[ViewThreshold, ViewThreshold1] - - -class PricingOption5(BaseModel): - model_config = ConfigDict( - extra="forbid", - ) - pricing_option_id: Annotated[ - str, - Field( - description="Unique identifier for this pricing option within the product (e.g., 'cpv_usd_50pct')" - ), - ] - pricing_model: Annotated[ - Literal["cpv"], Field(description="Cost per view at threshold") - ] - rate: Annotated[float, Field(description="Fixed CPV rate (cost per view)", ge=0.0)] - currency: Annotated[ - str, - Field( - description="ISO 4217 currency code", - examples=["USD", "EUR", "GBP", "JPY"], - pattern="^[A-Z]{3}$", - ), - ] - parameters: Annotated[ - Parameters, - Field(description="CPV-specific parameters defining the view threshold"), - ] - min_spend_per_package: Annotated[ - Optional[float], - Field( - description="Minimum spend requirement per package using this pricing option, in the specified currency", - ge=0.0, - ), - ] = None - - -class Parameters1(BaseModel): - model_config = ConfigDict( - extra="forbid", - ) - demographic: Annotated[ - str, - Field( - description="Target demographic in Nielsen format: P/M/W/A/C + age range. Examples: P18-49 (Persons 18-49), M25-54 (Men 25-54), W35+ (Women 35+), A18-34 (Adults 18-34), C2-11 (Children 2-11)", - pattern="^[PMWAC][0-9]{2}(-[0-9]{2}|\\+)$", - ), - ] - min_points: Annotated[ - Optional[float], - Field(description="Minimum GRPs/TRPs required for this pricing option", ge=0.0), - ] = None - - -class PricingOption6(BaseModel): - model_config = ConfigDict( - extra="forbid", - ) - pricing_option_id: Annotated[ - str, - Field( - description="Unique identifier for this pricing option within the product (e.g., 'cpp_usd_p18-49')" - ), - ] - pricing_model: Annotated[ - Literal["cpp"], Field(description="Cost per Gross Rating Point") - ] - rate: Annotated[ - float, Field(description="Fixed CPP rate (cost per rating point)", ge=0.0) - ] - currency: Annotated[ - str, - Field( - description="ISO 4217 currency code", - examples=["USD", "EUR", "GBP", "JPY"], - pattern="^[A-Z]{3}$", - ), - ] - parameters: Annotated[ - Parameters1, - Field( - description="CPP-specific parameters for demographic targeting and GRP requirements" - ), - ] - min_spend_per_package: Annotated[ - Optional[float], - Field( - description="Minimum spend requirement per package using this pricing option, in the specified currency", - ge=0.0, - ), - ] = None - - -class Parameters2(BaseModel): - model_config = ConfigDict( - extra="forbid", - ) - duration_hours: Annotated[ - Optional[float], - Field( - description="Duration in hours for time-based flat rate pricing (DOOH)", - ge=0.0, - ), - ] = None - sov_percentage: Annotated[ - Optional[float], - Field( - description="Guaranteed share of voice as percentage (DOOH, 0-100)", - ge=0.0, - le=100.0, - ), - ] = None - loop_duration_seconds: Annotated[ - Optional[int], - Field(description="Duration of ad loop rotation in seconds (DOOH)", ge=1), - ] = None - min_plays_per_hour: Annotated[ - Optional[int], - Field( - description="Minimum number of times ad plays per hour (DOOH frequency guarantee)", - ge=0, - ), - ] = None - venue_package: Annotated[ - Optional[str], - Field( - description="Named venue package identifier for DOOH (e.g., 'times_square_network', 'airport_terminals')" - ), - ] = None - estimated_impressions: Annotated[ - Optional[int], - Field( - description="Estimated impressions for this flat rate option (informational, commonly used with SOV or time-based DOOH)", - ge=0, - ), - ] = None - daypart: Annotated[ - Optional[str], - Field( - description="Specific daypart for time-based pricing (e.g., 'morning_commute', 'evening_prime', 'overnight')" - ), - ] = None - - -class PricingOption7(BaseModel): - model_config = ConfigDict( - extra="forbid", - ) - pricing_option_id: Annotated[ - str, - Field( - description="Unique identifier for this pricing option within the product (e.g., 'flat_rate_usd_24h_takeover')" - ), - ] - pricing_model: Annotated[ - Literal["flat_rate"], - Field(description="Fixed cost regardless of delivery volume"), - ] - rate: Annotated[float, Field(description="Flat rate cost", ge=0.0)] - currency: Annotated[ - str, - Field( - description="ISO 4217 currency code", - examples=["USD", "EUR", "GBP", "JPY"], - pattern="^[A-Z]{3}$", - ), - ] - is_fixed: Annotated[ - Literal[True], - Field( - description="Whether this is a fixed rate (true) or auction-based (false)" - ), - ] - parameters: Annotated[ - Optional[Parameters2], - Field(description="Flat rate parameters for DOOH and time-based campaigns"), - ] = None - min_spend_per_package: Annotated[ - Optional[float], - Field( - description="Minimum spend requirement per package using this pricing option, in the specified currency", - ge=0.0, - ), - ] = None - - -class PricingOption( - RootModel[ - Union[ - PricingOption1, - PricingOption2, - PricingOption3, - PricingOption4, - PricingOption5, - PricingOption6, - PricingOption7, - ] - ] -): - root: Annotated[ - Union[ - PricingOption1, - PricingOption2, - PricingOption3, - PricingOption4, - PricingOption5, - PricingOption6, - PricingOption7, - ], - Field( - description="A pricing model option offered by a publisher for a product. Each pricing model has its own schema with model-specific requirements.", - title="Pricing Option", - ), - ] diff --git a/src/creative_agent/schemas_generated/_schemas_v1_core_product_json.py b/src/creative_agent/schemas_generated/_schemas_v1_core_product_json.py deleted file mode 100644 index 4f86e60..0000000 --- a/src/creative_agent/schemas_generated/_schemas_v1_core_product_json.py +++ /dev/null @@ -1,1213 +0,0 @@ -# generated by datamodel-codegen: -# filename: _schemas_v1_core_product_json.json - -from __future__ import annotations - -from enum import Enum -from typing import Annotated, Literal, Optional, Union - -from pydantic import AwareDatetime, BaseModel, ConfigDict, Field, RootModel - - -class PropertyType(Enum): - website = "website" - mobile_app = "mobile_app" - ctv_app = "ctv_app" - dooh = "dooh" - podcast = "podcast" - radio = "radio" - streaming_audio = "streaming_audio" - - -class Identifier(BaseModel): - model_config = ConfigDict( - extra="forbid", - ) - type: Annotated[ - str, - Field( - description="Type of identifier (e.g., 'domain', 'bundle_id', 'roku_store_id', 'podcast_guid')" - ), - ] - value: Annotated[ - str, - Field( - description="The identifier value. For domain type: 'example.com' matches www.example.com and m.example.com only; 'subdomain.example.com' matches that specific subdomain; '*.example.com' matches all subdomains" - ), - ] - - -class Tag(RootModel[str]): - root: Annotated[ - str, - Field( - description="Lowercase tag with underscores (e.g., 'conde_nast_network', 'premium_content')", - pattern="^[a-z0-9_]+$", - ), - ] - - -class Property(BaseModel): - model_config = ConfigDict( - extra="forbid", - ) - property_type: Annotated[ - PropertyType, Field(description="Type of advertising property") - ] - name: Annotated[str, Field(description="Human-readable property name")] - identifiers: Annotated[ - list[Identifier], - Field(description="Array of identifiers for this property", min_length=1), - ] - tags: Annotated[ - Optional[list[Tag]], - Field( - description="Tags for categorization and grouping (e.g., network membership, content categories)" - ), - ] = None - publisher_domain: Annotated[ - str, - Field( - description="Domain where adagents.json should be checked for authorization validation" - ), - ] - - -class PropertyTag(RootModel[str]): - root: Annotated[ - str, - Field( - description="Lowercase tag with underscores (e.g., 'local_radio', 'premium_content')", - pattern="^[a-z0-9_]+$", - ), - ] - - -class DeliveryType(Enum): - guaranteed = "guaranteed" - non_guaranteed = "non_guaranteed" - - -class PricingOptions(BaseModel): - model_config = ConfigDict( - extra="forbid", - ) - pricing_option_id: Annotated[ - str, - Field( - description="Unique identifier for this pricing option within the product (e.g., 'cpm_usd_guaranteed')" - ), - ] - pricing_model: Annotated[ - Literal["cpm"], Field(description="Cost per 1,000 impressions") - ] - rate: Annotated[ - float, Field(description="Fixed CPM rate (cost per 1,000 impressions)", ge=0.0) - ] - currency: Annotated[ - str, - Field( - description="ISO 4217 currency code", - examples=["USD", "EUR", "GBP", "JPY"], - pattern="^[A-Z]{3}$", - ), - ] - min_spend_per_package: Annotated[ - Optional[float], - Field( - description="Minimum spend requirement per package using this pricing option, in the specified currency", - ge=0.0, - ), - ] = None - - -class PriceGuidance(BaseModel): - floor: Annotated[ - float, - Field( - description="Minimum bid price - publisher will reject bids under this value", - ge=0.0, - ), - ] - p25: Annotated[ - Optional[float], Field(description="25th percentile winning price", ge=0.0) - ] = None - p50: Annotated[ - Optional[float], Field(description="Median winning price", ge=0.0) - ] = None - p75: Annotated[ - Optional[float], Field(description="75th percentile winning price", ge=0.0) - ] = None - p90: Annotated[ - Optional[float], Field(description="90th percentile winning price", ge=0.0) - ] = None - - -class PricingOptions1(BaseModel): - model_config = ConfigDict( - extra="forbid", - ) - pricing_option_id: Annotated[ - str, - Field( - description="Unique identifier for this pricing option within the product (e.g., 'cpm_usd_auction')" - ), - ] - pricing_model: Annotated[ - Literal["cpm"], Field(description="Cost per 1,000 impressions") - ] - currency: Annotated[ - str, - Field( - description="ISO 4217 currency code", - examples=["USD", "EUR", "GBP", "JPY"], - pattern="^[A-Z]{3}$", - ), - ] - price_guidance: Annotated[ - PriceGuidance, - Field(description="Pricing guidance for auction-based CPM bidding"), - ] - min_spend_per_package: Annotated[ - Optional[float], - Field( - description="Minimum spend requirement per package using this pricing option, in the specified currency", - ge=0.0, - ), - ] = None - - -class PricingOptions2(BaseModel): - model_config = ConfigDict( - extra="forbid", - ) - pricing_option_id: Annotated[ - str, - Field( - description="Unique identifier for this pricing option within the product (e.g., 'cpc_usd_fixed')" - ), - ] - pricing_model: Annotated[Literal["cpc"], Field(description="Cost per click")] - rate: Annotated[float, Field(description="Fixed CPC rate (cost per click)", ge=0.0)] - currency: Annotated[ - str, - Field( - description="ISO 4217 currency code", - examples=["USD", "EUR", "GBP", "JPY"], - pattern="^[A-Z]{3}$", - ), - ] - min_spend_per_package: Annotated[ - Optional[float], - Field( - description="Minimum spend requirement per package using this pricing option, in the specified currency", - ge=0.0, - ), - ] = None - - -class PricingOptions3(BaseModel): - model_config = ConfigDict( - extra="forbid", - ) - pricing_option_id: Annotated[ - str, - Field( - description="Unique identifier for this pricing option within the product (e.g., 'cpcv_usd_guaranteed')" - ), - ] - pricing_model: Annotated[ - Literal["cpcv"], Field(description="Cost per completed view (100% completion)") - ] - rate: Annotated[ - float, Field(description="Fixed CPCV rate (cost per 100% completion)", ge=0.0) - ] - currency: Annotated[ - str, - Field( - description="ISO 4217 currency code", - examples=["USD", "EUR", "GBP", "JPY"], - pattern="^[A-Z]{3}$", - ), - ] - min_spend_per_package: Annotated[ - Optional[float], - Field( - description="Minimum spend requirement per package using this pricing option, in the specified currency", - ge=0.0, - ), - ] = None - - -class ViewThreshold(RootModel[float]): - root: Annotated[ - float, - Field( - description="Percentage completion threshold for CPV pricing (0.0 to 1.0, e.g., 0.5 = 50% completion)", - ge=0.0, - le=1.0, - ), - ] - - -class ViewThreshold3(BaseModel): - model_config = ConfigDict( - extra="forbid", - ) - duration_seconds: Annotated[ - int, - Field( - description="Seconds of viewing required (e.g., 30 for YouTube-style '30 seconds = view')", - ge=1, - ), - ] - - -class Parameters(BaseModel): - model_config = ConfigDict( - extra="forbid", - ) - view_threshold: Union[ViewThreshold, ViewThreshold3] - - -class PricingOptions4(BaseModel): - model_config = ConfigDict( - extra="forbid", - ) - pricing_option_id: Annotated[ - str, - Field( - description="Unique identifier for this pricing option within the product (e.g., 'cpv_usd_50pct')" - ), - ] - pricing_model: Annotated[ - Literal["cpv"], Field(description="Cost per view at threshold") - ] - rate: Annotated[float, Field(description="Fixed CPV rate (cost per view)", ge=0.0)] - currency: Annotated[ - str, - Field( - description="ISO 4217 currency code", - examples=["USD", "EUR", "GBP", "JPY"], - pattern="^[A-Z]{3}$", - ), - ] - parameters: Annotated[ - Parameters, - Field(description="CPV-specific parameters defining the view threshold"), - ] - min_spend_per_package: Annotated[ - Optional[float], - Field( - description="Minimum spend requirement per package using this pricing option, in the specified currency", - ge=0.0, - ), - ] = None - - -class Parameters4(BaseModel): - model_config = ConfigDict( - extra="forbid", - ) - demographic: Annotated[ - str, - Field( - description="Target demographic in Nielsen format: P/M/W/A/C + age range. Examples: P18-49 (Persons 18-49), M25-54 (Men 25-54), W35+ (Women 35+), A18-34 (Adults 18-34), C2-11 (Children 2-11)", - pattern="^[PMWAC][0-9]{2}(-[0-9]{2}|\\+)$", - ), - ] - min_points: Annotated[ - Optional[float], - Field(description="Minimum GRPs/TRPs required for this pricing option", ge=0.0), - ] = None - - -class PricingOptions5(BaseModel): - model_config = ConfigDict( - extra="forbid", - ) - pricing_option_id: Annotated[ - str, - Field( - description="Unique identifier for this pricing option within the product (e.g., 'cpp_usd_p18-49')" - ), - ] - pricing_model: Annotated[ - Literal["cpp"], Field(description="Cost per Gross Rating Point") - ] - rate: Annotated[ - float, Field(description="Fixed CPP rate (cost per rating point)", ge=0.0) - ] - currency: Annotated[ - str, - Field( - description="ISO 4217 currency code", - examples=["USD", "EUR", "GBP", "JPY"], - pattern="^[A-Z]{3}$", - ), - ] - parameters: Annotated[ - Parameters4, - Field( - description="CPP-specific parameters for demographic targeting and GRP requirements" - ), - ] - min_spend_per_package: Annotated[ - Optional[float], - Field( - description="Minimum spend requirement per package using this pricing option, in the specified currency", - ge=0.0, - ), - ] = None - - -class Parameters5(BaseModel): - model_config = ConfigDict( - extra="forbid", - ) - duration_hours: Annotated[ - Optional[float], - Field( - description="Duration in hours for time-based flat rate pricing (DOOH)", - ge=0.0, - ), - ] = None - sov_percentage: Annotated[ - Optional[float], - Field( - description="Guaranteed share of voice as percentage (DOOH, 0-100)", - ge=0.0, - le=100.0, - ), - ] = None - loop_duration_seconds: Annotated[ - Optional[int], - Field(description="Duration of ad loop rotation in seconds (DOOH)", ge=1), - ] = None - min_plays_per_hour: Annotated[ - Optional[int], - Field( - description="Minimum number of times ad plays per hour (DOOH frequency guarantee)", - ge=0, - ), - ] = None - venue_package: Annotated[ - Optional[str], - Field( - description="Named venue package identifier for DOOH (e.g., 'times_square_network', 'airport_terminals')" - ), - ] = None - estimated_impressions: Annotated[ - Optional[int], - Field( - description="Estimated impressions for this flat rate option (informational, commonly used with SOV or time-based DOOH)", - ge=0, - ), - ] = None - daypart: Annotated[ - Optional[str], - Field( - description="Specific daypart for time-based pricing (e.g., 'morning_commute', 'evening_prime', 'overnight')" - ), - ] = None - - -class PricingOptions6(BaseModel): - model_config = ConfigDict( - extra="forbid", - ) - pricing_option_id: Annotated[ - str, - Field( - description="Unique identifier for this pricing option within the product (e.g., 'flat_rate_usd_24h_takeover')" - ), - ] - pricing_model: Annotated[ - Literal["flat_rate"], - Field(description="Fixed cost regardless of delivery volume"), - ] - rate: Annotated[float, Field(description="Flat rate cost", ge=0.0)] - currency: Annotated[ - str, - Field( - description="ISO 4217 currency code", - examples=["USD", "EUR", "GBP", "JPY"], - pattern="^[A-Z]{3}$", - ), - ] - is_fixed: Annotated[ - Literal[True], - Field( - description="Whether this is a fixed rate (true) or auction-based (false)" - ), - ] - parameters: Annotated[ - Optional[Parameters5], - Field(description="Flat rate parameters for DOOH and time-based campaigns"), - ] = None - min_spend_per_package: Annotated[ - Optional[float], - Field( - description="Minimum spend requirement per package using this pricing option, in the specified currency", - ge=0.0, - ), - ] = None - - -class Measurement(BaseModel): - model_config = ConfigDict( - extra="forbid", - ) - type: Annotated[ - str, - Field( - description="Type of measurement", - examples=["incremental_sales_lift", "brand_lift", "foot_traffic"], - ), - ] - attribution: Annotated[ - str, - Field( - description="Attribution methodology", - examples=["deterministic_purchase", "probabilistic"], - ), - ] - window: Annotated[ - Optional[str], - Field(description="Attribution window", examples=["30_days", "7_days"]), - ] = None - reporting: Annotated[ - str, - Field( - description="Reporting frequency and format", - examples=["weekly_dashboard", "real_time_api"], - ), - ] - - -class DeliveryMeasurement(BaseModel): - provider: Annotated[ - str, - Field( - description="Measurement provider(s) used for this product (e.g., 'Google Ad Manager with IAS viewability', 'Nielsen DAR', 'Geopath for DOOH impressions')" - ), - ] - notes: Annotated[ - Optional[str], - Field( - description="Additional details about measurement methodology in plain language (e.g., 'MRC-accredited viewability. 50% in-view for 1s display / 2s video', 'Panel-based demographic measurement updated monthly')" - ), - ] = None - - -class AvailableReportingFrequency(Enum): - hourly = "hourly" - daily = "daily" - monthly = "monthly" - - -class AvailableMetric(Enum): - impressions = "impressions" - spend = "spend" - clicks = "clicks" - ctr = "ctr" - video_completions = "video_completions" - completion_rate = "completion_rate" - conversions = "conversions" - viewability = "viewability" - engagement_rate = "engagement_rate" - - -class ReportingCapabilities(BaseModel): - model_config = ConfigDict( - extra="forbid", - ) - available_reporting_frequencies: Annotated[ - list[AvailableReportingFrequency], - Field(description="Supported reporting frequency options", min_length=1), - ] - expected_delay_minutes: Annotated[ - int, - Field( - description="Expected delay in minutes before reporting data becomes available (e.g., 240 for 4-hour delay)", - examples=[240, 300, 1440], - ge=0, - ), - ] - timezone: Annotated[ - str, - Field( - description="Timezone for reporting periods. Use 'UTC' or IANA timezone (e.g., 'America/New_York'). Critical for daily/monthly frequency alignment.", - examples=[ - "UTC", - "America/New_York", - "Europe/London", - "America/Los_Angeles", - ], - ), - ] - supports_webhooks: Annotated[ - bool, - Field( - description="Whether this product supports webhook-based reporting notifications" - ), - ] - available_metrics: Annotated[ - list[AvailableMetric], - Field( - description="Metrics available in reporting. Impressions and spend are always implicitly included.", - examples=[ - ["impressions", "spend", "clicks", "video_completions"], - ["impressions", "spend", "conversions"], - ], - ), - ] - - -class CoBranding(Enum): - required = "required" - optional = "optional" - none = "none" - - -class LandingPage(Enum): - any = "any" - retailer_site_only = "retailer_site_only" - must_include_retailer = "must_include_retailer" - - -class CreativePolicy(BaseModel): - model_config = ConfigDict( - extra="forbid", - ) - co_branding: Annotated[CoBranding, Field(description="Co-branding requirement")] - landing_page: Annotated[LandingPage, Field(description="Landing page requirements")] - templates_available: Annotated[ - bool, Field(description="Whether creative templates are provided") - ] - - -class Product1(BaseModel): - model_config = ConfigDict( - extra="forbid", - ) - product_id: Annotated[str, Field(description="Unique identifier for the product")] - name: Annotated[str, Field(description="Human-readable product name")] - description: Annotated[ - str, Field(description="Detailed description of the product and its inventory") - ] - properties: Annotated[ - list[Property], - Field( - description="Array of advertising properties covered by this product for adagents.json validation", - min_length=1, - ), - ] - property_tags: Annotated[ - Optional[list[PropertyTag]], - Field( - description="Tags identifying groups of properties covered by this product (use list_authorized_properties to get full property details)", - min_length=1, - ), - ] = None - format_ids: Annotated[ - list[str], - Field( - description="Array of supported creative format IDs - use list_creative_formats to get full format details" - ), - ] - delivery_type: Annotated[ - DeliveryType, - Field(description="Type of inventory delivery", title="Delivery Type"), - ] - pricing_options: Annotated[ - list[ - Union[ - PricingOptions, - PricingOptions1, - PricingOptions2, - PricingOptions3, - PricingOptions4, - PricingOptions5, - PricingOptions6, - ] - ], - Field(description="Available pricing models for this product", min_length=1), - ] - estimated_exposures: Annotated[ - Optional[int], - Field( - description="Estimated exposures/impressions for guaranteed products", ge=0 - ), - ] = None - measurement: Annotated[ - Optional[Measurement], - Field( - description="Measurement capabilities included with a product", - title="Measurement", - ), - ] = None - delivery_measurement: Annotated[ - DeliveryMeasurement, - Field( - description="Measurement provider and methodology for delivery metrics. The buyer accepts the declared provider as the source of truth for the buy. REQUIRED for all products." - ), - ] - reporting_capabilities: Annotated[ - Optional[ReportingCapabilities], - Field( - description="Reporting capabilities available for a product", - title="Reporting Capabilities", - ), - ] = None - creative_policy: Annotated[ - Optional[CreativePolicy], - Field( - description="Creative requirements and restrictions for a product", - title="Creative Policy", - ), - ] = None - is_custom: Annotated[ - Optional[bool], Field(description="Whether this is a custom product") - ] = None - brief_relevance: Annotated[ - Optional[str], - Field( - description="Explanation of why this product matches the brief (only included when brief is provided)" - ), - ] = None - expires_at: Annotated[ - Optional[AwareDatetime], - Field(description="Expiration timestamp for custom products"), - ] = None - - -class Property1(BaseModel): - model_config = ConfigDict( - extra="forbid", - ) - property_type: Annotated[ - PropertyType, Field(description="Type of advertising property") - ] - name: Annotated[str, Field(description="Human-readable property name")] - identifiers: Annotated[ - list[Identifier], - Field(description="Array of identifiers for this property", min_length=1), - ] - tags: Annotated[ - Optional[list[Tag]], - Field( - description="Tags for categorization and grouping (e.g., network membership, content categories)" - ), - ] = None - publisher_domain: Annotated[ - str, - Field( - description="Domain where adagents.json should be checked for authorization validation" - ), - ] - - -class PricingOptions7(BaseModel): - model_config = ConfigDict( - extra="forbid", - ) - pricing_option_id: Annotated[ - str, - Field( - description="Unique identifier for this pricing option within the product (e.g., 'cpm_usd_guaranteed')" - ), - ] - pricing_model: Annotated[ - Literal["cpm"], Field(description="Cost per 1,000 impressions") - ] - rate: Annotated[ - float, Field(description="Fixed CPM rate (cost per 1,000 impressions)", ge=0.0) - ] - currency: Annotated[ - str, - Field( - description="ISO 4217 currency code", - examples=["USD", "EUR", "GBP", "JPY"], - pattern="^[A-Z]{3}$", - ), - ] - min_spend_per_package: Annotated[ - Optional[float], - Field( - description="Minimum spend requirement per package using this pricing option, in the specified currency", - ge=0.0, - ), - ] = None - - -class PricingOptions8(BaseModel): - model_config = ConfigDict( - extra="forbid", - ) - pricing_option_id: Annotated[ - str, - Field( - description="Unique identifier for this pricing option within the product (e.g., 'cpm_usd_auction')" - ), - ] - pricing_model: Annotated[ - Literal["cpm"], Field(description="Cost per 1,000 impressions") - ] - currency: Annotated[ - str, - Field( - description="ISO 4217 currency code", - examples=["USD", "EUR", "GBP", "JPY"], - pattern="^[A-Z]{3}$", - ), - ] - price_guidance: Annotated[ - PriceGuidance, - Field(description="Pricing guidance for auction-based CPM bidding"), - ] - min_spend_per_package: Annotated[ - Optional[float], - Field( - description="Minimum spend requirement per package using this pricing option, in the specified currency", - ge=0.0, - ), - ] = None - - -class PricingOptions9(BaseModel): - model_config = ConfigDict( - extra="forbid", - ) - pricing_option_id: Annotated[ - str, - Field( - description="Unique identifier for this pricing option within the product (e.g., 'cpc_usd_fixed')" - ), - ] - pricing_model: Annotated[Literal["cpc"], Field(description="Cost per click")] - rate: Annotated[float, Field(description="Fixed CPC rate (cost per click)", ge=0.0)] - currency: Annotated[ - str, - Field( - description="ISO 4217 currency code", - examples=["USD", "EUR", "GBP", "JPY"], - pattern="^[A-Z]{3}$", - ), - ] - min_spend_per_package: Annotated[ - Optional[float], - Field( - description="Minimum spend requirement per package using this pricing option, in the specified currency", - ge=0.0, - ), - ] = None - - -class PricingOptions10(BaseModel): - model_config = ConfigDict( - extra="forbid", - ) - pricing_option_id: Annotated[ - str, - Field( - description="Unique identifier for this pricing option within the product (e.g., 'cpcv_usd_guaranteed')" - ), - ] - pricing_model: Annotated[ - Literal["cpcv"], Field(description="Cost per completed view (100% completion)") - ] - rate: Annotated[ - float, Field(description="Fixed CPCV rate (cost per 100% completion)", ge=0.0) - ] - currency: Annotated[ - str, - Field( - description="ISO 4217 currency code", - examples=["USD", "EUR", "GBP", "JPY"], - pattern="^[A-Z]{3}$", - ), - ] - min_spend_per_package: Annotated[ - Optional[float], - Field( - description="Minimum spend requirement per package using this pricing option, in the specified currency", - ge=0.0, - ), - ] = None - - -class ViewThreshold4(RootModel[float]): - root: Annotated[ - float, - Field( - description="Percentage completion threshold for CPV pricing (0.0 to 1.0, e.g., 0.5 = 50% completion)", - ge=0.0, - le=1.0, - ), - ] - - -class ViewThreshold5(BaseModel): - model_config = ConfigDict( - extra="forbid", - ) - duration_seconds: Annotated[ - int, - Field( - description="Seconds of viewing required (e.g., 30 for YouTube-style '30 seconds = view')", - ge=1, - ), - ] - - -class Parameters6(BaseModel): - model_config = ConfigDict( - extra="forbid", - ) - view_threshold: Union[ViewThreshold4, ViewThreshold5] - - -class PricingOptions11(BaseModel): - model_config = ConfigDict( - extra="forbid", - ) - pricing_option_id: Annotated[ - str, - Field( - description="Unique identifier for this pricing option within the product (e.g., 'cpv_usd_50pct')" - ), - ] - pricing_model: Annotated[ - Literal["cpv"], Field(description="Cost per view at threshold") - ] - rate: Annotated[float, Field(description="Fixed CPV rate (cost per view)", ge=0.0)] - currency: Annotated[ - str, - Field( - description="ISO 4217 currency code", - examples=["USD", "EUR", "GBP", "JPY"], - pattern="^[A-Z]{3}$", - ), - ] - parameters: Annotated[ - Parameters6, - Field(description="CPV-specific parameters defining the view threshold"), - ] - min_spend_per_package: Annotated[ - Optional[float], - Field( - description="Minimum spend requirement per package using this pricing option, in the specified currency", - ge=0.0, - ), - ] = None - - -class Parameters7(BaseModel): - model_config = ConfigDict( - extra="forbid", - ) - demographic: Annotated[ - str, - Field( - description="Target demographic in Nielsen format: P/M/W/A/C + age range. Examples: P18-49 (Persons 18-49), M25-54 (Men 25-54), W35+ (Women 35+), A18-34 (Adults 18-34), C2-11 (Children 2-11)", - pattern="^[PMWAC][0-9]{2}(-[0-9]{2}|\\+)$", - ), - ] - min_points: Annotated[ - Optional[float], - Field(description="Minimum GRPs/TRPs required for this pricing option", ge=0.0), - ] = None - - -class PricingOptions12(BaseModel): - model_config = ConfigDict( - extra="forbid", - ) - pricing_option_id: Annotated[ - str, - Field( - description="Unique identifier for this pricing option within the product (e.g., 'cpp_usd_p18-49')" - ), - ] - pricing_model: Annotated[ - Literal["cpp"], Field(description="Cost per Gross Rating Point") - ] - rate: Annotated[ - float, Field(description="Fixed CPP rate (cost per rating point)", ge=0.0) - ] - currency: Annotated[ - str, - Field( - description="ISO 4217 currency code", - examples=["USD", "EUR", "GBP", "JPY"], - pattern="^[A-Z]{3}$", - ), - ] - parameters: Annotated[ - Parameters7, - Field( - description="CPP-specific parameters for demographic targeting and GRP requirements" - ), - ] - min_spend_per_package: Annotated[ - Optional[float], - Field( - description="Minimum spend requirement per package using this pricing option, in the specified currency", - ge=0.0, - ), - ] = None - - -class Parameters8(BaseModel): - model_config = ConfigDict( - extra="forbid", - ) - duration_hours: Annotated[ - Optional[float], - Field( - description="Duration in hours for time-based flat rate pricing (DOOH)", - ge=0.0, - ), - ] = None - sov_percentage: Annotated[ - Optional[float], - Field( - description="Guaranteed share of voice as percentage (DOOH, 0-100)", - ge=0.0, - le=100.0, - ), - ] = None - loop_duration_seconds: Annotated[ - Optional[int], - Field(description="Duration of ad loop rotation in seconds (DOOH)", ge=1), - ] = None - min_plays_per_hour: Annotated[ - Optional[int], - Field( - description="Minimum number of times ad plays per hour (DOOH frequency guarantee)", - ge=0, - ), - ] = None - venue_package: Annotated[ - Optional[str], - Field( - description="Named venue package identifier for DOOH (e.g., 'times_square_network', 'airport_terminals')" - ), - ] = None - estimated_impressions: Annotated[ - Optional[int], - Field( - description="Estimated impressions for this flat rate option (informational, commonly used with SOV or time-based DOOH)", - ge=0, - ), - ] = None - daypart: Annotated[ - Optional[str], - Field( - description="Specific daypart for time-based pricing (e.g., 'morning_commute', 'evening_prime', 'overnight')" - ), - ] = None - - -class PricingOptions13(BaseModel): - model_config = ConfigDict( - extra="forbid", - ) - pricing_option_id: Annotated[ - str, - Field( - description="Unique identifier for this pricing option within the product (e.g., 'flat_rate_usd_24h_takeover')" - ), - ] - pricing_model: Annotated[ - Literal["flat_rate"], - Field(description="Fixed cost regardless of delivery volume"), - ] - rate: Annotated[float, Field(description="Flat rate cost", ge=0.0)] - currency: Annotated[ - str, - Field( - description="ISO 4217 currency code", - examples=["USD", "EUR", "GBP", "JPY"], - pattern="^[A-Z]{3}$", - ), - ] - is_fixed: Annotated[ - Literal[True], - Field( - description="Whether this is a fixed rate (true) or auction-based (false)" - ), - ] - parameters: Annotated[ - Optional[Parameters8], - Field(description="Flat rate parameters for DOOH and time-based campaigns"), - ] = None - min_spend_per_package: Annotated[ - Optional[float], - Field( - description="Minimum spend requirement per package using this pricing option, in the specified currency", - ge=0.0, - ), - ] = None - - -class ReportingCapabilities1(BaseModel): - model_config = ConfigDict( - extra="forbid", - ) - available_reporting_frequencies: Annotated[ - list[AvailableReportingFrequency], - Field(description="Supported reporting frequency options", min_length=1), - ] - expected_delay_minutes: Annotated[ - int, - Field( - description="Expected delay in minutes before reporting data becomes available (e.g., 240 for 4-hour delay)", - examples=[240, 300, 1440], - ge=0, - ), - ] - timezone: Annotated[ - str, - Field( - description="Timezone for reporting periods. Use 'UTC' or IANA timezone (e.g., 'America/New_York'). Critical for daily/monthly frequency alignment.", - examples=[ - "UTC", - "America/New_York", - "Europe/London", - "America/Los_Angeles", - ], - ), - ] - supports_webhooks: Annotated[ - bool, - Field( - description="Whether this product supports webhook-based reporting notifications" - ), - ] - available_metrics: Annotated[ - list[AvailableMetric], - Field( - description="Metrics available in reporting. Impressions and spend are always implicitly included.", - examples=[ - ["impressions", "spend", "clicks", "video_completions"], - ["impressions", "spend", "conversions"], - ], - ), - ] - - -class CreativePolicy2(BaseModel): - model_config = ConfigDict( - extra="forbid", - ) - co_branding: Annotated[CoBranding, Field(description="Co-branding requirement")] - landing_page: Annotated[LandingPage, Field(description="Landing page requirements")] - templates_available: Annotated[ - bool, Field(description="Whether creative templates are provided") - ] - - -class Product2(BaseModel): - model_config = ConfigDict( - extra="forbid", - ) - product_id: Annotated[str, Field(description="Unique identifier for the product")] - name: Annotated[str, Field(description="Human-readable product name")] - description: Annotated[ - str, Field(description="Detailed description of the product and its inventory") - ] - properties: Annotated[ - Optional[list[Property1]], - Field( - description="Array of advertising properties covered by this product for adagents.json validation", - min_length=1, - ), - ] = None - property_tags: Annotated[ - list[PropertyTag], - Field( - description="Tags identifying groups of properties covered by this product (use list_authorized_properties to get full property details)", - min_length=1, - ), - ] - format_ids: Annotated[ - list[str], - Field( - description="Array of supported creative format IDs - use list_creative_formats to get full format details" - ), - ] - delivery_type: Annotated[ - DeliveryType, - Field(description="Type of inventory delivery", title="Delivery Type"), - ] - pricing_options: Annotated[ - list[ - Union[ - PricingOptions7, - PricingOptions8, - PricingOptions9, - PricingOptions10, - PricingOptions11, - PricingOptions12, - PricingOptions13, - ] - ], - Field(description="Available pricing models for this product", min_length=1), - ] - estimated_exposures: Annotated[ - Optional[int], - Field( - description="Estimated exposures/impressions for guaranteed products", ge=0 - ), - ] = None - measurement: Annotated[ - Optional[Measurement], - Field( - description="Measurement capabilities included with a product", - title="Measurement", - ), - ] = None - delivery_measurement: Annotated[ - DeliveryMeasurement, - Field( - description="Measurement provider and methodology for delivery metrics. The buyer accepts the declared provider as the source of truth for the buy. REQUIRED for all products." - ), - ] - reporting_capabilities: Annotated[ - Optional[ReportingCapabilities1], - Field( - description="Reporting capabilities available for a product", - title="Reporting Capabilities", - ), - ] = None - creative_policy: Annotated[ - Optional[CreativePolicy2], - Field( - description="Creative requirements and restrictions for a product", - title="Creative Policy", - ), - ] = None - is_custom: Annotated[ - Optional[bool], Field(description="Whether this is a custom product") - ] = None - brief_relevance: Annotated[ - Optional[str], - Field( - description="Explanation of why this product matches the brief (only included when brief is provided)" - ), - ] = None - expires_at: Annotated[ - Optional[AwareDatetime], - Field(description="Expiration timestamp for custom products"), - ] = None - - -class Product(RootModel[Union[Product1, Product2]]): - root: Annotated[ - Union[Product1, Product2], - Field( - description="Represents available advertising inventory", title="Product" - ), - ] diff --git a/src/creative_agent/schemas_generated/_schemas_v1_core_promoted_offerings_json.py b/src/creative_agent/schemas_generated/_schemas_v1_core_promoted_offerings_json.py new file mode 100644 index 0000000..4cf8ae9 --- /dev/null +++ b/src/creative_agent/schemas_generated/_schemas_v1_core_promoted_offerings_json.py @@ -0,0 +1,457 @@ +# generated by datamodel-codegen: +# filename: _schemas_v1_core_promoted-offerings_json.json + +from __future__ import annotations + +from enum import Enum +from typing import Annotated, Any, Optional, Union + +from pydantic import AnyUrl, AwareDatetime, BaseModel, ConfigDict, EmailStr, Field + + +class Logo(BaseModel): + url: Annotated[AnyUrl, Field(description="URL to the logo asset")] + tags: Annotated[ + Optional[list[str]], + Field( + description="Semantic tags describing the logo variant (e.g., 'dark', 'light', 'square', 'horizontal', 'icon')" + ), + ] = None + width: Annotated[Optional[int], Field(description="Logo width in pixels")] = None + height: Annotated[Optional[int], Field(description="Logo height in pixels")] = None + + +class Colors(BaseModel): + primary: Annotated[ + Optional[str], + Field( + description="Primary brand color (hex format)", pattern="^#[0-9A-Fa-f]{6}$" + ), + ] = None + secondary: Annotated[ + Optional[str], + Field( + description="Secondary brand color (hex format)", + pattern="^#[0-9A-Fa-f]{6}$", + ), + ] = None + accent: Annotated[ + Optional[str], + Field(description="Accent color (hex format)", pattern="^#[0-9A-Fa-f]{6}$"), + ] = None + background: Annotated[ + Optional[str], + Field(description="Background color (hex format)", pattern="^#[0-9A-Fa-f]{6}$"), + ] = None + text: Annotated[ + Optional[str], + Field(description="Text color (hex format)", pattern="^#[0-9A-Fa-f]{6}$"), + ] = None + + +class Fonts(BaseModel): + primary: Annotated[Optional[str], Field(description="Primary font family name")] = ( + None + ) + secondary: Annotated[ + Optional[str], Field(description="Secondary font family name") + ] = None + font_urls: Annotated[ + Optional[list[AnyUrl]], + Field(description="URLs to web font files if using custom fonts"), + ] = None + + +class AssetType(Enum): + image = "image" + video = "video" + audio = "audio" + text = "text" + + +class Asset(BaseModel): + model_config = ConfigDict( + extra="forbid", + ) + asset_id: Annotated[str, Field(description="Unique identifier for this asset")] + asset_type: Annotated[AssetType, Field(description="Type of asset")] + url: Annotated[AnyUrl, Field(description="URL to CDN-hosted asset file")] + tags: Annotated[ + Optional[list[str]], + Field( + description="Tags for asset discovery (e.g., 'holiday', 'lifestyle', 'product_shot')" + ), + ] = None + name: Annotated[Optional[str], Field(description="Human-readable asset name")] = ( + None + ) + description: Annotated[ + Optional[str], Field(description="Asset description or usage notes") + ] = None + width: Annotated[ + Optional[int], Field(description="Image/video width in pixels") + ] = None + height: Annotated[ + Optional[int], Field(description="Image/video height in pixels") + ] = None + duration_seconds: Annotated[ + Optional[float], Field(description="Video/audio duration in seconds") + ] = None + file_size_bytes: Annotated[ + Optional[int], Field(description="File size in bytes") + ] = None + format: Annotated[ + Optional[str], Field(description="File format (e.g., 'jpg', 'mp4', 'mp3')") + ] = None + metadata: Annotated[ + Optional[dict[str, Any]], + Field(description="Additional asset-specific metadata"), + ] = None + + +class FeedFormat(Enum): + google_merchant_center = "google_merchant_center" + facebook_catalog = "facebook_catalog" + custom = "custom" + + +class UpdateFrequency(Enum): + realtime = "realtime" + hourly = "hourly" + daily = "daily" + weekly = "weekly" + + +class ProductCatalog(BaseModel): + model_config = ConfigDict( + extra="forbid", + ) + feed_url: Annotated[AnyUrl, Field(description="URL to product catalog feed")] + feed_format: Annotated[ + Optional[FeedFormat], Field(description="Format of the product feed") + ] = "google_merchant_center" + categories: Annotated[ + Optional[list[str]], + Field( + description="Product categories available in the catalog (for filtering)" + ), + ] = None + last_updated: Annotated[ + Optional[AwareDatetime], + Field(description="When the product catalog was last updated"), + ] = None + update_frequency: Annotated[ + Optional[UpdateFrequency], + Field(description="How frequently the product catalog is updated"), + ] = None + + +class Disclaimer(BaseModel): + text: Annotated[str, Field(description="Disclaimer text")] + context: Annotated[ + Optional[str], + Field( + description="When this disclaimer applies (e.g., 'financial_products', 'health_claims', 'all')" + ), + ] = None + required: Annotated[ + Optional[bool], Field(description="Whether this disclaimer must appear") + ] = True + + +class Contact(BaseModel): + email: Annotated[Optional[EmailStr], Field(description="Contact email")] = None + phone: Annotated[Optional[str], Field(description="Contact phone number")] = None + + +class Metadata(BaseModel): + created_date: Annotated[ + Optional[AwareDatetime], + Field(description="When this brand manifest was created"), + ] = None + updated_date: Annotated[ + Optional[AwareDatetime], + Field(description="When this brand manifest was last updated"), + ] = None + version: Annotated[ + Optional[str], Field(description="Brand card version number") + ] = None + + +class BrandManifest(BaseModel): + model_config = ConfigDict( + extra="forbid", + ) + url: Annotated[ + AnyUrl, + Field( + description="Primary brand URL for context and asset discovery. Creative agents can infer brand information from this URL." + ), + ] + name: Annotated[Optional[str], Field(description="Brand or business name")] = None + logos: Annotated[ + Optional[list[Logo]], + Field( + description="Brand logo assets with semantic tags for different use cases" + ), + ] = None + colors: Annotated[Optional[Colors], Field(description="Brand color palette")] = None + fonts: Annotated[ + Optional[Fonts], Field(description="Brand typography guidelines") + ] = None + tone: Annotated[ + Optional[str], + Field( + description="Brand voice and messaging tone (e.g., 'professional', 'casual', 'humorous', 'trustworthy', 'innovative')" + ), + ] = None + tagline: Annotated[Optional[str], Field(description="Brand tagline or slogan")] = ( + None + ) + assets: Annotated[ + Optional[list[Asset]], + Field( + description="Brand asset library with explicit assets and tags. Assets are referenced inline with URLs pointing to CDN-hosted files." + ), + ] = None + product_catalog: Annotated[ + Optional[ProductCatalog], + Field( + description="Product catalog information for e-commerce advertisers. Enables SKU-level creative generation and product selection." + ), + ] = None + disclaimers: Annotated[ + Optional[list[Disclaimer]], + Field( + description="Legal disclaimers or required text that must appear in creatives" + ), + ] = None + industry: Annotated[ + Optional[str], + Field( + description="Industry or vertical (e.g., 'retail', 'automotive', 'finance', 'healthcare')" + ), + ] = None + target_audience: Annotated[ + Optional[str], Field(description="Primary target audience description") + ] = None + contact: Annotated[ + Optional[Contact], Field(description="Brand contact information") + ] = None + metadata: Annotated[ + Optional[Metadata], Field(description="Additional brand metadata") + ] = None + + +Asset6 = Asset + + +ProductCatalog5 = ProductCatalog + + +class BrandManifest4(BaseModel): + model_config = ConfigDict( + extra="forbid", + ) + url: Annotated[ + Optional[AnyUrl], + Field( + description="Primary brand URL for context and asset discovery. Creative agents can infer brand information from this URL." + ), + ] = None + name: Annotated[str, Field(description="Brand or business name")] + logos: Annotated[ + Optional[list[Logo]], + Field( + description="Brand logo assets with semantic tags for different use cases" + ), + ] = None + colors: Annotated[Optional[Colors], Field(description="Brand color palette")] = None + fonts: Annotated[ + Optional[Fonts], Field(description="Brand typography guidelines") + ] = None + tone: Annotated[ + Optional[str], + Field( + description="Brand voice and messaging tone (e.g., 'professional', 'casual', 'humorous', 'trustworthy', 'innovative')" + ), + ] = None + tagline: Annotated[Optional[str], Field(description="Brand tagline or slogan")] = ( + None + ) + assets: Annotated[ + Optional[list[Asset6]], + Field( + description="Brand asset library with explicit assets and tags. Assets are referenced inline with URLs pointing to CDN-hosted files." + ), + ] = None + product_catalog: Annotated[ + Optional[ProductCatalog5], + Field( + description="Product catalog information for e-commerce advertisers. Enables SKU-level creative generation and product selection." + ), + ] = None + disclaimers: Annotated[ + Optional[list[Disclaimer]], + Field( + description="Legal disclaimers or required text that must appear in creatives" + ), + ] = None + industry: Annotated[ + Optional[str], + Field( + description="Industry or vertical (e.g., 'retail', 'automotive', 'finance', 'healthcare')" + ), + ] = None + target_audience: Annotated[ + Optional[str], Field(description="Primary target audience description") + ] = None + contact: Annotated[ + Optional[Contact], Field(description="Brand contact information") + ] = None + metadata: Annotated[ + Optional[Metadata], Field(description="Additional brand metadata") + ] = None + + +class ProductSelectors(BaseModel): + model_config = ConfigDict( + extra="forbid", + ) + manifest_skus: Annotated[ + Optional[list[str]], + Field( + description="Direct product SKU references from the brand manifest product catalog" + ), + ] = None + manifest_tags: Annotated[ + Optional[list[str]], + Field( + description="Select products by tags from the brand manifest product catalog (e.g., 'organic', 'sauces', 'holiday')" + ), + ] = None + manifest_category: Annotated[ + Optional[str], + Field( + description="Select products from a specific category in the brand manifest product catalog (e.g., 'beverages/soft-drinks', 'food/sauces')" + ), + ] = None + manifest_query: Annotated[ + Optional[str], + Field( + description="Natural language query to select products from the brand manifest (e.g., 'all Kraft Heinz pasta sauces', 'organic products under $20')" + ), + ] = None + + +class Offering(BaseModel): + model_config = ConfigDict( + extra="forbid", + ) + name: Annotated[ + str, + Field(description="Offering name (e.g., 'Winter Sale', 'New Product Launch')"), + ] + description: Annotated[ + Optional[str], Field(description="Description of what's being offered") + ] = None + assets: Annotated[ + Optional[list[dict[str, Any]]], + Field(description="Assets specific to this offering"), + ] = None + + +class AssetType8(Enum): + image = "image" + video = "video" + audio = "audio" + text = "text" + html = "html" + css = "css" + javascript = "javascript" + + +class AssetSelectors(BaseModel): + model_config = ConfigDict( + extra="forbid", + ) + tags: Annotated[ + Optional[list[str]], + Field( + description="Select assets with specific tags (e.g., ['holiday', 'premium'])" + ), + ] = None + asset_types: Annotated[ + Optional[list[AssetType8]], + Field(description="Filter by asset type (e.g., ['image', 'video'])"), + ] = None + exclude_tags: Annotated[ + Optional[list[str]], Field(description="Exclude assets with these tags") + ] = None + + +class PromotedOfferings(BaseModel): + model_config = ConfigDict( + extra="forbid", + ) + brand_manifest: Annotated[ + Union[Union[BrandManifest, BrandManifest4], AnyUrl], + Field( + description="Brand manifest provided either as an inline object or a URL string pointing to a hosted manifest", + examples=[ + { + "description": "Inline brand manifest", + "data": { + "url": "https://acmecorp.com", + "name": "ACME Corporation", + "colors": {"primary": "#FF6B35"}, + }, + }, + { + "description": "URL string reference to hosted manifest", + "data": "https://cdn.acmecorp.com/brand-manifest.json", + }, + ], + title="Brand Manifest Reference", + ), + ] + product_selectors: Annotated[ + Optional[ProductSelectors], + Field( + description="Specification of products or offerings being promoted in a campaign. Supports multiple selection methods from the brand manifest that can be combined using UNION (OR) logic. When multiple selection methods are provided, products matching ANY of the criteria are selected (logical OR, not AND).", + examples=[ + { + "description": "Direct SKU selection for specific products from brand manifest", + "data": {"manifest_skus": ["SKU-12345", "SKU-67890"]}, + }, + { + "description": "UNION selection: products tagged 'organic' OR 'sauces' OR in 'food/condiments' category from brand manifest", + "data": { + "manifest_tags": ["organic", "sauces"], + "manifest_category": "food/condiments", + }, + }, + { + "description": "Natural language product selection from brand manifest", + "data": {"manifest_query": "all Kraft Heinz pasta sauces under $5"}, + }, + { + "description": "Select products by tags", + "data": {"manifest_tags": ["holiday"]}, + }, + ], + title="Promoted Products", + ), + ] = None + offerings: Annotated[ + Optional[list[Offering]], + Field( + description="Inline offerings for campaigns without a product catalog. Each offering has a name, description, and associated assets." + ), + ] = None + asset_selectors: Annotated[ + Optional[AssetSelectors], + Field( + description="Selectors to choose specific assets from the brand manifest" + ), + ] = None diff --git a/src/creative_agent/schemas_generated/_schemas_v1_core_promoted_products_json.py b/src/creative_agent/schemas_generated/_schemas_v1_core_promoted_products_json.py new file mode 100644 index 0000000..0742f30 --- /dev/null +++ b/src/creative_agent/schemas_generated/_schemas_v1_core_promoted_products_json.py @@ -0,0 +1,38 @@ +# generated by datamodel-codegen: +# filename: _schemas_v1_core_promoted-products_json.json + +from __future__ import annotations + +from typing import Annotated, Optional + +from pydantic import BaseModel, ConfigDict, Field + + +class PromotedProducts(BaseModel): + model_config = ConfigDict( + extra="forbid", + ) + manifest_skus: Annotated[ + Optional[list[str]], + Field( + description="Direct product SKU references from the brand manifest product catalog" + ), + ] = None + manifest_tags: Annotated[ + Optional[list[str]], + Field( + description="Select products by tags from the brand manifest product catalog (e.g., 'organic', 'sauces', 'holiday')" + ), + ] = None + manifest_category: Annotated[ + Optional[str], + Field( + description="Select products from a specific category in the brand manifest product catalog (e.g., 'beverages/soft-drinks', 'food/sauces')" + ), + ] = None + manifest_query: Annotated[ + Optional[str], + Field( + description="Natural language query to select products from the brand manifest (e.g., 'all Kraft Heinz pasta sauces', 'organic products under $20')" + ), + ] = None diff --git a/src/creative_agent/schemas_generated/_schemas_v1_core_property_json.py b/src/creative_agent/schemas_generated/_schemas_v1_core_property_json.py deleted file mode 100644 index 7eb2d61..0000000 --- a/src/creative_agent/schemas_generated/_schemas_v1_core_property_json.py +++ /dev/null @@ -1,73 +0,0 @@ -# generated by datamodel-codegen: -# filename: _schemas_v1_core_property_json.json - -from __future__ import annotations - -from enum import Enum -from typing import Annotated, Optional - -from pydantic import BaseModel, ConfigDict, Field, RootModel - - -class PropertyType(Enum): - website = "website" - mobile_app = "mobile_app" - ctv_app = "ctv_app" - dooh = "dooh" - podcast = "podcast" - radio = "radio" - streaming_audio = "streaming_audio" - - -class Identifier(BaseModel): - model_config = ConfigDict( - extra="forbid", - ) - type: Annotated[ - str, - Field( - description="Type of identifier (e.g., 'domain', 'bundle_id', 'roku_store_id', 'podcast_guid')" - ), - ] - value: Annotated[ - str, - Field( - description="The identifier value. For domain type: 'example.com' matches www.example.com and m.example.com only; 'subdomain.example.com' matches that specific subdomain; '*.example.com' matches all subdomains" - ), - ] - - -class Tag(RootModel[str]): - root: Annotated[ - str, - Field( - description="Lowercase tag with underscores (e.g., 'conde_nast_network', 'premium_content')", - pattern="^[a-z0-9_]+$", - ), - ] - - -class Property(BaseModel): - model_config = ConfigDict( - extra="forbid", - ) - property_type: Annotated[ - PropertyType, Field(description="Type of advertising property") - ] - name: Annotated[str, Field(description="Human-readable property name")] - identifiers: Annotated[ - list[Identifier], - Field(description="Array of identifiers for this property", min_length=1), - ] - tags: Annotated[ - Optional[list[Tag]], - Field( - description="Tags for categorization and grouping (e.g., network membership, content categories)" - ), - ] = None - publisher_domain: Annotated[ - str, - Field( - description="Domain where adagents.json should be checked for authorization validation" - ), - ] diff --git a/src/creative_agent/schemas_generated/_schemas_v1_core_push_notification_config_json.py b/src/creative_agent/schemas_generated/_schemas_v1_core_push_notification_config_json.py deleted file mode 100644 index 99fbd85..0000000 --- a/src/creative_agent/schemas_generated/_schemas_v1_core_push_notification_config_json.py +++ /dev/null @@ -1,57 +0,0 @@ -# generated by datamodel-codegen: -# filename: _schemas_v1_core_push-notification-config_json.json - -from __future__ import annotations - -from enum import Enum -from typing import Annotated, Optional - -from pydantic import AnyUrl, BaseModel, ConfigDict, Field - - -class Scheme(Enum): - bearer = "Bearer" - hmac_sha256 = "HMAC-SHA256" - - -class Authentication(BaseModel): - model_config = ConfigDict( - extra="forbid", - ) - schemes: Annotated[ - list[Scheme], - Field( - description="Array of authentication schemes. Supported: ['Bearer'] for simple token auth, ['HMAC-SHA256'] for signature verification (recommended for production)", - max_length=1, - min_length=1, - ), - ] - credentials: Annotated[ - str, - Field( - description="Credentials for authentication. For Bearer: token sent in Authorization header. For HMAC-SHA256: shared secret used to generate signature. Minimum 32 characters. Exchanged out-of-band during onboarding.", - min_length=32, - ), - ] - - -class PushNotificationConfig(BaseModel): - model_config = ConfigDict( - extra="forbid", - ) - url: Annotated[ - AnyUrl, Field(description="Webhook endpoint URL for task status notifications") - ] - token: Annotated[ - Optional[str], - Field( - description="Optional client-provided token for webhook validation. Echoed back in webhook payload to validate request authenticity.", - min_length=16, - ), - ] = None - authentication: Annotated[ - Authentication, - Field( - description="Authentication configuration for webhook delivery (A2A-compatible)" - ), - ] diff --git a/src/creative_agent/schemas_generated/_schemas_v1_core_reporting_capabilities_json.py b/src/creative_agent/schemas_generated/_schemas_v1_core_reporting_capabilities_json.py deleted file mode 100644 index 19367e6..0000000 --- a/src/creative_agent/schemas_generated/_schemas_v1_core_reporting_capabilities_json.py +++ /dev/null @@ -1,73 +0,0 @@ -# generated by datamodel-codegen: -# filename: _schemas_v1_core_reporting-capabilities_json.json - -from __future__ import annotations - -from enum import Enum -from typing import Annotated - -from pydantic import BaseModel, ConfigDict, Field - - -class AvailableReportingFrequency(Enum): - hourly = "hourly" - daily = "daily" - monthly = "monthly" - - -class AvailableMetric(Enum): - impressions = "impressions" - spend = "spend" - clicks = "clicks" - ctr = "ctr" - video_completions = "video_completions" - completion_rate = "completion_rate" - conversions = "conversions" - viewability = "viewability" - engagement_rate = "engagement_rate" - - -class ReportingCapabilities(BaseModel): - model_config = ConfigDict( - extra="forbid", - ) - available_reporting_frequencies: Annotated[ - list[AvailableReportingFrequency], - Field(description="Supported reporting frequency options", min_length=1), - ] - expected_delay_minutes: Annotated[ - int, - Field( - description="Expected delay in minutes before reporting data becomes available (e.g., 240 for 4-hour delay)", - examples=[240, 300, 1440], - ge=0, - ), - ] - timezone: Annotated[ - str, - Field( - description="Timezone for reporting periods. Use 'UTC' or IANA timezone (e.g., 'America/New_York'). Critical for daily/monthly frequency alignment.", - examples=[ - "UTC", - "America/New_York", - "Europe/London", - "America/Los_Angeles", - ], - ), - ] - supports_webhooks: Annotated[ - bool, - Field( - description="Whether this product supports webhook-based reporting notifications" - ), - ] - available_metrics: Annotated[ - list[AvailableMetric], - Field( - description="Metrics available in reporting. Impressions and spend are always implicitly included.", - examples=[ - ["impressions", "spend", "clicks", "video_completions"], - ["impressions", "spend", "conversions"], - ], - ), - ] diff --git a/src/creative_agent/schemas_generated/_schemas_v1_core_start_timing_json.py b/src/creative_agent/schemas_generated/_schemas_v1_core_start_timing_json.py deleted file mode 100644 index 3d8e36d..0000000 --- a/src/creative_agent/schemas_generated/_schemas_v1_core_start_timing_json.py +++ /dev/null @@ -1,18 +0,0 @@ -# generated by datamodel-codegen: -# filename: _schemas_v1_core_start-timing_json.json - -from __future__ import annotations - -from typing import Annotated, Union - -from pydantic import AwareDatetime, Field, RootModel - - -class StartTiming(RootModel[Union[str, AwareDatetime]]): - root: Annotated[ - Union[str, AwareDatetime], - Field( - description="Campaign start timing: 'asap' or ISO 8601 date-time", - title="Start Timing", - ), - ] diff --git a/src/creative_agent/schemas_generated/_schemas_v1_core_targeting_json.py b/src/creative_agent/schemas_generated/_schemas_v1_core_targeting_json.py deleted file mode 100644 index 325f1c4..0000000 --- a/src/creative_agent/schemas_generated/_schemas_v1_core_targeting_json.py +++ /dev/null @@ -1,58 +0,0 @@ -# generated by datamodel-codegen: -# filename: _schemas_v1_core_targeting_json.json - -from __future__ import annotations - -from typing import Annotated, Optional - -from pydantic import BaseModel, ConfigDict, Field, RootModel - - -class GeoCountryAnyOfItem(RootModel[str]): - root: Annotated[str, Field(pattern="^[A-Z]{2}$")] - - -class FrequencyCap(BaseModel): - model_config = ConfigDict( - extra="forbid", - ) - suppress_minutes: Annotated[ - float, Field(description="Minutes to suppress after impression", ge=0.0) - ] - - -class TargetingOverlay(BaseModel): - model_config = ConfigDict( - extra="forbid", - ) - geo_country_any_of: Annotated[ - Optional[list[GeoCountryAnyOfItem]], - Field( - description="Restrict delivery to specific countries (ISO codes). Use for regulatory compliance or RCT testing." - ), - ] = None - geo_region_any_of: Annotated[ - Optional[list[str]], - Field( - description="Restrict delivery to specific regions/states. Use for regulatory compliance or RCT testing." - ), - ] = None - geo_metro_any_of: Annotated[ - Optional[list[str]], - Field( - description="Restrict delivery to specific metro areas (DMA codes). Use for regulatory compliance or RCT testing." - ), - ] = None - geo_postal_code_any_of: Annotated[ - Optional[list[str]], - Field( - description="Restrict delivery to specific postal/ZIP codes. Use for regulatory compliance or RCT testing." - ), - ] = None - frequency_cap: Annotated[ - Optional[FrequencyCap], - Field( - description="Frequency capping settings for package-level application", - title="Frequency Cap", - ), - ] = None diff --git a/src/creative_agent/schemas_generated/_schemas_v1_creative_asset_types_index_json.py b/src/creative_agent/schemas_generated/_schemas_v1_creative_asset_types_index_json.py new file mode 100644 index 0000000..1571114 --- /dev/null +++ b/src/creative_agent/schemas_generated/_schemas_v1_creative_asset_types_index_json.py @@ -0,0 +1,18 @@ +# generated by datamodel-codegen: +# filename: _schemas_v1_creative_asset-types_index_json.json + +from __future__ import annotations + +from typing import Annotated, Any + +from pydantic import Field, RootModel + + +class AdcpAssetTypeDefinitionsRegistry(RootModel[Any]): + root: Annotated[ + Any, + Field( + description="Standardized definitions for all asset types used in AdCP creative manifests. These asset types are used when providing actual creative content that fulfills format requirements.", + title="AdCP Asset Type Definitions Registry", + ), + ] diff --git a/src/creative_agent/schemas_generated/_schemas_v1_media_buy_list_creative_formats_request_json.py b/src/creative_agent/schemas_generated/_schemas_v1_creative_list_creative_formats_request_json.py similarity index 52% rename from src/creative_agent/schemas_generated/_schemas_v1_media_buy_list_creative_formats_request_json.py rename to src/creative_agent/schemas_generated/_schemas_v1_creative_list_creative_formats_request_json.py index 058b22a..9e51ef9 100644 --- a/src/creative_agent/schemas_generated/_schemas_v1_media_buy_list_creative_formats_request_json.py +++ b/src/creative_agent/schemas_generated/_schemas_v1_creative_list_creative_formats_request_json.py @@ -1,5 +1,5 @@ # generated by datamodel-codegen: -# filename: _schemas_v1_media-buy_list-creative-formats-request_json.json +# filename: _schemas_v1_creative_list-creative-formats-request_json.json from __future__ import annotations @@ -26,22 +26,12 @@ class AssetType(Enum): url = "url" -class ListCreativeFormatsRequest(BaseModel): +class ListCreativeFormatsRequestCreativeAgent(BaseModel): model_config = ConfigDict( extra="forbid", ) - adcp_version: Annotated[ - Optional[str], - Field( - description="AdCP schema version for this request", - pattern="^\\d+\\.\\d+\\.\\d+$", - ), - ] = "1.6.0" format_ids: Annotated[ - Optional[list[str]], - Field( - description="Return only these specific format IDs (e.g., from get_products response)" - ), + Optional[list[str]], Field(description="Return only these specific format IDs") ] = None type: Annotated[ Optional[Type], @@ -55,10 +45,34 @@ class ListCreativeFormatsRequest(BaseModel): 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." ), ] = None - dimensions: Annotated[ - Optional[str], + max_width: Annotated[ + Optional[int], + Field( + description="Maximum width in pixels (inclusive). Returns formats with width <= this value. Omit for responsive/fluid formats." + ), + ] = None + max_height: Annotated[ + Optional[int], + Field( + description="Maximum height in pixels (inclusive). Returns formats with height <= this value. Omit for responsive/fluid formats." + ), + ] = None + min_width: Annotated[ + Optional[int], + Field( + description="Minimum width in pixels (inclusive). Returns formats with width >= this value." + ), + ] = None + min_height: Annotated[ + Optional[int], + Field( + description="Minimum height in pixels (inclusive). Returns formats with height >= this value." + ), + ] = None + is_responsive: Annotated[ + Optional[bool], Field( - description="Filter to formats with specific dimensions (e.g., '300x250', '728x90'). Useful with asset_types to find specific sizes like '300x250 JavaScript'" + description="Filter for responsive formats that adapt to container size. When true, returns formats without fixed dimensions." ), ] = None name_search: Annotated[ diff --git a/src/creative_agent/schemas_generated/_schemas_v1_media_buy_list_creative_formats_response_json.py b/src/creative_agent/schemas_generated/_schemas_v1_creative_list_creative_formats_response_json.py similarity index 96% rename from src/creative_agent/schemas_generated/_schemas_v1_media_buy_list_creative_formats_response_json.py rename to src/creative_agent/schemas_generated/_schemas_v1_creative_list_creative_formats_response_json.py index 173aa67..675f3e2 100644 --- a/src/creative_agent/schemas_generated/_schemas_v1_media_buy_list_creative_formats_response_json.py +++ b/src/creative_agent/schemas_generated/_schemas_v1_creative_list_creative_formats_response_json.py @@ -1,5 +1,5 @@ # generated by datamodel-codegen: -# filename: _schemas_v1_media-buy_list-creative-formats-response_json.json +# filename: _schemas_v1_creative_list-creative-formats-response_json.json from __future__ import annotations @@ -240,7 +240,7 @@ class Error(BaseModel): ] = None -class ListCreativeFormatsResponse(BaseModel): +class ListCreativeFormatsResponseCreativeAgent(BaseModel): model_config = ConfigDict( extra="forbid", ) @@ -264,8 +264,5 @@ class ListCreativeFormatsResponse(BaseModel): ), ] = None errors: Annotated[ - Optional[list[Error]], - Field( - description="Task-specific errors and warnings (e.g., format availability issues)" - ), + Optional[list[Error]], Field(description="Task-specific errors and warnings") ] = None diff --git a/src/creative_agent/schemas_generated/_schemas_v1_creative_preview_creative_request_json.py b/src/creative_agent/schemas_generated/_schemas_v1_creative_preview_creative_request_json.py new file mode 100644 index 0000000..e1a3f00 --- /dev/null +++ b/src/creative_agent/schemas_generated/_schemas_v1_creative_preview_creative_request_json.py @@ -0,0 +1,873 @@ +# generated by datamodel-codegen: +# filename: _schemas_v1_creative_preview-creative-request_json.json + +from __future__ import annotations + +from enum import Enum +from typing import Annotated, Any, Literal, Optional, Union + +from pydantic import AnyUrl, AwareDatetime, BaseModel, ConfigDict, EmailStr, Field + + +class FormatId(BaseModel): + model_config = ConfigDict( + extra="forbid", + ) + 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)" + ), + ] + id: Annotated[ + str, + Field( + description="Format identifier within the agent's namespace (e.g., 'display_300x250', 'video_standard_30s')", + pattern="^[a-zA-Z0-9_-]+$", + ), + ] + + +class Format(Enum): + jpg = "jpg" + jpeg = "jpeg" + png = "png" + gif = "gif" + webp = "webp" + svg = "svg" + + +class Assets(BaseModel): + model_config = ConfigDict( + extra="forbid", + ) + asset_type: Literal["image"] + url: Annotated[AnyUrl, Field(description="URL to hosted image asset")] + width: Annotated[int, Field(description="Image width in pixels", ge=1)] + height: Annotated[int, Field(description="Image height in pixels", ge=1)] + format: Annotated[Optional[Format], Field(description="Image file format")] = None + file_size: Annotated[ + Optional[int], Field(description="File size in bytes", ge=0) + ] = None + alt: Annotated[ + Optional[str], Field(description="Alternative text for accessibility") + ] = None + + +class Format6(Enum): + mp4 = "mp4" + webm = "webm" + mov = "mov" + + +class Codec(Enum): + h264 = "h264" + h265 = "h265" + vp8 = "vp8" + vp9 = "vp9" + av1 = "av1" + + +class Assets23(BaseModel): + model_config = ConfigDict( + extra="forbid", + ) + asset_type: Literal["video"] + url: Annotated[AnyUrl, Field(description="URL to hosted video asset")] + width: Annotated[int, Field(description="Video width in pixels", ge=1)] + height: Annotated[int, Field(description="Video height in pixels", ge=1)] + duration_seconds: Annotated[ + float, Field(description="Video duration in seconds", ge=0.0) + ] + format: Annotated[ + Optional[Format6], Field(description="Video container format") + ] = None + codec: Annotated[Optional[Codec], Field(description="Video codec")] = None + bitrate_mbps: Annotated[ + Optional[float], Field(description="Video bitrate in Mbps", ge=0.0) + ] = None + file_size: Annotated[ + Optional[int], Field(description="File size in bytes", ge=0) + ] = None + aspect_ratio: Annotated[ + Optional[str], + Field(description="Aspect ratio (e.g., '16:9', '9:16')", pattern="^\\d+:\\d+$"), + ] = None + + +class Format7(Enum): + mp3 = "mp3" + aac = "aac" + m4a = "m4a" + wav = "wav" + ogg = "ogg" + + +class Codec3(Enum): + mp3 = "mp3" + aac = "aac" + opus = "opus" + vorbis = "vorbis" + + +class SampleRateHz(Enum): + integer_22050 = 22050 + integer_44100 = 44100 + integer_48000 = 48000 + integer_96000 = 96000 + + +class Channels(Enum): + mono = "mono" + stereo = "stereo" + field_5_1 = "5.1" + field_7_1 = "7.1" + + +class Assets24(BaseModel): + model_config = ConfigDict( + extra="forbid", + ) + asset_type: Literal["audio"] + url: Annotated[AnyUrl, Field(description="URL to hosted audio asset")] + duration_seconds: Annotated[ + float, Field(description="Audio duration in seconds", ge=0.0) + ] + format: Annotated[Optional[Format7], Field(description="Audio file format")] = None + codec: Annotated[Optional[Codec3], Field(description="Audio codec")] = None + bitrate_kbps: Annotated[ + Optional[float], Field(description="Audio bitrate in Kbps", ge=0.0) + ] = None + sample_rate_hz: Annotated[ + Optional[SampleRateHz], Field(description="Sample rate in Hz") + ] = None + channels: Annotated[ + Optional[Channels], Field(description="Audio channel configuration") + ] = None + file_size: Annotated[ + Optional[int], Field(description="File size in bytes", ge=0) + ] = None + + +class VastVersion(Enum): + field_2_0 = "2.0" + field_3_0 = "3.0" + field_4_0 = "4.0" + field_4_1 = "4.1" + field_4_2 = "4.2" + + +class Assets25(BaseModel): + model_config = ConfigDict( + extra="forbid", + ) + asset_type: Literal["vast_tag"] + content: Annotated[str, Field(description="Complete VAST XML content")] + vast_version: Annotated[ + VastVersion, Field(description="VAST specification version") + ] + vpaid_enabled: Annotated[ + Optional[bool], Field(description="Whether VPAID is used") + ] = None + duration_seconds: Annotated[ + Optional[float], Field(description="Expected video duration in seconds", ge=0.0) + ] = None + + +class Format8(Enum): + plain = "plain" + html = "html" + markdown = "markdown" + + +class Assets26(BaseModel): + model_config = ConfigDict( + extra="forbid", + ) + asset_type: Literal["text"] + content: Annotated[str, Field(description="Text content")] + length: Annotated[Optional[int], Field(description="Character count", ge=0)] = None + format: Annotated[Optional[Format8], Field(description="Text format")] = "plain" + + +class Purpose(Enum): + clickthrough = "clickthrough" + landing_page = "landing_page" + tracking_pixel = "tracking_pixel" + impression_tracker = "impression_tracker" + + +class Assets27(BaseModel): + model_config = ConfigDict( + extra="forbid", + ) + asset_type: Literal["url"] + url: Annotated[AnyUrl, Field(description="The URL")] + purpose: Annotated[Optional[Purpose], Field(description="Purpose of this URL")] = ( + None + ) + + +class Method(Enum): + get = "GET" + post = "POST" + + +class ResponseType(Enum): + html = "html" + json = "json" + xml = "xml" + javascript = "javascript" + + +class Method3(Enum): + hmac_sha256 = "hmac_sha256" + api_key = "api_key" + none = "none" + + +class Security(BaseModel): + method: Method3 + hmac_header: Optional[str] = None + api_key_header: Optional[str] = None + + +class Assets28(BaseModel): + model_config = ConfigDict( + extra="forbid", + ) + asset_type: Literal["webhook"] + url: Annotated[AnyUrl, Field(description="Webhook URL to call for dynamic content")] + method: Optional[Method] = "POST" + timeout_ms: Annotated[Optional[int], Field(ge=10, le=5000)] = 500 + supported_macros: Annotated[ + Optional[list[str]], + Field(description="Universal macros that can be passed to webhook"), + ] = None + required_macros: Annotated[ + Optional[list[str]], Field(description="Universal macros that must be provided") + ] = None + response_type: ResponseType + security: Security + fallback_required: Optional[bool] = True + + +class Assets29(BaseModel): + model_config = ConfigDict( + extra="forbid", + ) + asset_type: Literal["html"] + content: Annotated[str, Field(description="Complete HTML content")] + url: Annotated[ + Optional[AnyUrl], Field(description="URL to externally hosted HTML file") + ] = None + width: Annotated[Optional[int], Field(description="Ad width in pixels", ge=1)] = ( + None + ) + height: Annotated[Optional[int], Field(description="Ad height in pixels", ge=1)] = ( + None + ) + file_size: Annotated[ + Optional[int], Field(description="Total file size in bytes", ge=0) + ] = None + + +class Assets30(BaseModel): + model_config = ConfigDict( + extra="forbid", + ) + asset_type: Literal["html"] + content: Annotated[Optional[str], Field(description="Complete HTML content")] = None + url: Annotated[AnyUrl, Field(description="URL to externally hosted HTML file")] + width: Annotated[Optional[int], Field(description="Ad width in pixels", ge=1)] = ( + None + ) + height: Annotated[Optional[int], Field(description="Ad height in pixels", ge=1)] = ( + None + ) + file_size: Annotated[ + Optional[int], Field(description="Total file size in bytes", ge=0) + ] = None + + +class Assets31(BaseModel): + model_config = ConfigDict( + extra="forbid", + ) + asset_type: Literal["javascript"] + content: Annotated[str, Field(description="JavaScript code content")] + url: Annotated[ + Optional[AnyUrl], Field(description="URL to external JavaScript file") + ] = None + inline: Annotated[ + Optional[bool], + Field(description="Whether code should be inlined vs external script tag"), + ] = None + + +class Assets32(BaseModel): + model_config = ConfigDict( + extra="forbid", + ) + asset_type: Literal["javascript"] + content: Annotated[Optional[str], Field(description="JavaScript code content")] = ( + None + ) + url: Annotated[AnyUrl, Field(description="URL to external JavaScript file")] + inline: Annotated[ + Optional[bool], + Field(description="Whether code should be inlined vs external script tag"), + ] = None + + +class CreativeManifest(BaseModel): + model_config = ConfigDict( + extra="forbid", + ) + format_id: Annotated[ + Any, Field(description="Circular reference to /schemas/v1/core/format-id.json") + ] + promoted_offering: Annotated[ + Optional[str], + Field( + description="Product name or offering being advertised. Maps to promoted_offerings in create_media_buy request to associate creative with the product being promoted." + ), + ] = None + assets: Annotated[ + dict[ + str, + Union[ + Assets, + Assets23, + Assets24, + Assets25, + Assets26, + Assets27, + Assets28, + Union[Assets29, Assets30], + Union[Assets31, Assets32], + ], + ], + Field( + description="Map of asset roles (from format spec) to actual asset content. Each key is an asset_role defined by the format (e.g., 'hero_image', 'logo', 'headline', 'video_file', 'vast_tag')." + ), + ] + + +class Input(BaseModel): + model_config = ConfigDict( + extra="forbid", + ) + name: Annotated[ + str, + Field( + description="Human-readable name for this input set (e.g., 'Sunny morning on mobile', 'Evening podcast ad', 'Desktop dark mode')" + ), + ] + macros: Annotated[ + Optional[dict[str, str]], + Field( + description="Macro values to use for this preview. Supports all universal macros from the format's supported_macros list. See docs/media-buy/creatives/universal-macros.md for available macros." + ), + ] = None + context_description: Annotated[ + Optional[str], + Field( + description="Natural language description of the context for AI-generated content (e.g., 'User just searched for running shoes', 'Podcast discussing weather patterns', 'Article about electric vehicles')" + ), + ] = None + + +class Logo(BaseModel): + url: Annotated[AnyUrl, Field(description="URL to the logo asset")] + tags: Annotated[ + Optional[list[str]], + Field( + description="Semantic tags describing the logo variant (e.g., 'dark', 'light', 'square', 'horizontal', 'icon')" + ), + ] = None + width: Annotated[Optional[int], Field(description="Logo width in pixels")] = None + height: Annotated[Optional[int], Field(description="Logo height in pixels")] = None + + +class Colors(BaseModel): + primary: Annotated[ + Optional[str], + Field( + description="Primary brand color (hex format)", pattern="^#[0-9A-Fa-f]{6}$" + ), + ] = None + secondary: Annotated[ + Optional[str], + Field( + description="Secondary brand color (hex format)", + pattern="^#[0-9A-Fa-f]{6}$", + ), + ] = None + accent: Annotated[ + Optional[str], + Field(description="Accent color (hex format)", pattern="^#[0-9A-Fa-f]{6}$"), + ] = None + background: Annotated[ + Optional[str], + Field(description="Background color (hex format)", pattern="^#[0-9A-Fa-f]{6}$"), + ] = None + text: Annotated[ + Optional[str], + Field(description="Text color (hex format)", pattern="^#[0-9A-Fa-f]{6}$"), + ] = None + + +class Fonts(BaseModel): + primary: Annotated[Optional[str], Field(description="Primary font family name")] = ( + None + ) + secondary: Annotated[ + Optional[str], Field(description="Secondary font family name") + ] = None + font_urls: Annotated[ + Optional[list[AnyUrl]], + Field(description="URLs to web font files if using custom fonts"), + ] = None + + +class AssetType(Enum): + image = "image" + video = "video" + audio = "audio" + text = "text" + + +class Asset(BaseModel): + model_config = ConfigDict( + extra="forbid", + ) + asset_id: Annotated[str, Field(description="Unique identifier for this asset")] + asset_type: Annotated[AssetType, Field(description="Type of asset")] + url: Annotated[AnyUrl, Field(description="URL to CDN-hosted asset file")] + tags: Annotated[ + Optional[list[str]], + Field( + description="Tags for asset discovery (e.g., 'holiday', 'lifestyle', 'product_shot')" + ), + ] = None + name: Annotated[Optional[str], Field(description="Human-readable asset name")] = ( + None + ) + description: Annotated[ + Optional[str], Field(description="Asset description or usage notes") + ] = None + width: Annotated[ + Optional[int], Field(description="Image/video width in pixels") + ] = None + height: Annotated[ + Optional[int], Field(description="Image/video height in pixels") + ] = None + duration_seconds: Annotated[ + Optional[float], Field(description="Video/audio duration in seconds") + ] = None + file_size_bytes: Annotated[ + Optional[int], Field(description="File size in bytes") + ] = None + format: Annotated[ + Optional[str], Field(description="File format (e.g., 'jpg', 'mp4', 'mp3')") + ] = None + metadata: Annotated[ + Optional[dict[str, Any]], + Field(description="Additional asset-specific metadata"), + ] = None + + +class FeedFormat(Enum): + google_merchant_center = "google_merchant_center" + facebook_catalog = "facebook_catalog" + custom = "custom" + + +class UpdateFrequency(Enum): + realtime = "realtime" + hourly = "hourly" + daily = "daily" + weekly = "weekly" + + +class ProductCatalog(BaseModel): + model_config = ConfigDict( + extra="forbid", + ) + feed_url: Annotated[AnyUrl, Field(description="URL to product catalog feed")] + feed_format: Annotated[ + Optional[FeedFormat], Field(description="Format of the product feed") + ] = "google_merchant_center" + categories: Annotated[ + Optional[list[str]], + Field( + description="Product categories available in the catalog (for filtering)" + ), + ] = None + last_updated: Annotated[ + Optional[AwareDatetime], + Field(description="When the product catalog was last updated"), + ] = None + update_frequency: Annotated[ + Optional[UpdateFrequency], + Field(description="How frequently the product catalog is updated"), + ] = None + + +class Disclaimer(BaseModel): + text: Annotated[str, Field(description="Disclaimer text")] + context: Annotated[ + Optional[str], + Field( + description="When this disclaimer applies (e.g., 'financial_products', 'health_claims', 'all')" + ), + ] = None + required: Annotated[ + Optional[bool], Field(description="Whether this disclaimer must appear") + ] = True + + +class Contact(BaseModel): + email: Annotated[Optional[EmailStr], Field(description="Contact email")] = None + phone: Annotated[Optional[str], Field(description="Contact phone number")] = None + + +class Metadata(BaseModel): + created_date: Annotated[ + Optional[AwareDatetime], + Field(description="When this brand manifest was created"), + ] = None + updated_date: Annotated[ + Optional[AwareDatetime], + Field(description="When this brand manifest was last updated"), + ] = None + version: Annotated[ + Optional[str], Field(description="Brand card version number") + ] = None + + +class BrandManifest(BaseModel): + model_config = ConfigDict( + extra="forbid", + ) + url: Annotated[ + AnyUrl, + Field( + description="Primary brand URL for context and asset discovery. Creative agents can infer brand information from this URL." + ), + ] + name: Annotated[Optional[str], Field(description="Brand or business name")] = None + logos: Annotated[ + Optional[list[Logo]], + Field( + description="Brand logo assets with semantic tags for different use cases" + ), + ] = None + colors: Annotated[Optional[Colors], Field(description="Brand color palette")] = None + fonts: Annotated[ + Optional[Fonts], Field(description="Brand typography guidelines") + ] = None + tone: Annotated[ + Optional[str], + Field( + description="Brand voice and messaging tone (e.g., 'professional', 'casual', 'humorous', 'trustworthy', 'innovative')" + ), + ] = None + tagline: Annotated[Optional[str], Field(description="Brand tagline or slogan")] = ( + None + ) + assets: Annotated[ + Optional[list[Asset]], + Field( + description="Brand asset library with explicit assets and tags. Assets are referenced inline with URLs pointing to CDN-hosted files." + ), + ] = None + product_catalog: Annotated[ + Optional[ProductCatalog], + Field( + description="Product catalog information for e-commerce advertisers. Enables SKU-level creative generation and product selection." + ), + ] = None + disclaimers: Annotated[ + Optional[list[Disclaimer]], + Field( + description="Legal disclaimers or required text that must appear in creatives" + ), + ] = None + industry: Annotated[ + Optional[str], + Field( + description="Industry or vertical (e.g., 'retail', 'automotive', 'finance', 'healthcare')" + ), + ] = None + target_audience: Annotated[ + Optional[str], Field(description="Primary target audience description") + ] = None + contact: Annotated[ + Optional[Contact], Field(description="Brand contact information") + ] = None + metadata: Annotated[ + Optional[Metadata], Field(description="Additional brand metadata") + ] = None + + +Asset9 = Asset + + +ProductCatalog7 = ProductCatalog + + +class BrandManifest6(BaseModel): + model_config = ConfigDict( + extra="forbid", + ) + url: Annotated[ + Optional[AnyUrl], + Field( + description="Primary brand URL for context and asset discovery. Creative agents can infer brand information from this URL." + ), + ] = None + name: Annotated[str, Field(description="Brand or business name")] + logos: Annotated[ + Optional[list[Logo]], + Field( + description="Brand logo assets with semantic tags for different use cases" + ), + ] = None + colors: Annotated[Optional[Colors], Field(description="Brand color palette")] = None + fonts: Annotated[ + Optional[Fonts], Field(description="Brand typography guidelines") + ] = None + tone: Annotated[ + Optional[str], + Field( + description="Brand voice and messaging tone (e.g., 'professional', 'casual', 'humorous', 'trustworthy', 'innovative')" + ), + ] = None + tagline: Annotated[Optional[str], Field(description="Brand tagline or slogan")] = ( + None + ) + assets: Annotated[ + Optional[list[Asset9]], + Field( + description="Brand asset library with explicit assets and tags. Assets are referenced inline with URLs pointing to CDN-hosted files." + ), + ] = None + product_catalog: Annotated[ + Optional[ProductCatalog7], + Field( + description="Product catalog information for e-commerce advertisers. Enables SKU-level creative generation and product selection." + ), + ] = None + disclaimers: Annotated[ + Optional[list[Disclaimer]], + Field( + description="Legal disclaimers or required text that must appear in creatives" + ), + ] = None + industry: Annotated[ + Optional[str], + Field( + description="Industry or vertical (e.g., 'retail', 'automotive', 'finance', 'healthcare')" + ), + ] = None + target_audience: Annotated[ + Optional[str], Field(description="Primary target audience description") + ] = None + contact: Annotated[ + Optional[Contact], Field(description="Brand contact information") + ] = None + metadata: Annotated[ + Optional[Metadata], Field(description="Additional brand metadata") + ] = None + + +class ProductSelectors(BaseModel): + model_config = ConfigDict( + extra="forbid", + ) + manifest_skus: Annotated[ + Optional[list[str]], + Field( + description="Direct product SKU references from the brand manifest product catalog" + ), + ] = None + manifest_tags: Annotated[ + Optional[list[str]], + Field( + description="Select products by tags from the brand manifest product catalog (e.g., 'organic', 'sauces', 'holiday')" + ), + ] = None + manifest_category: Annotated[ + Optional[str], + Field( + description="Select products from a specific category in the brand manifest product catalog (e.g., 'beverages/soft-drinks', 'food/sauces')" + ), + ] = None + manifest_query: Annotated[ + Optional[str], + Field( + description="Natural language query to select products from the brand manifest (e.g., 'all Kraft Heinz pasta sauces', 'organic products under $20')" + ), + ] = None + + +class Offering(BaseModel): + model_config = ConfigDict( + extra="forbid", + ) + name: Annotated[ + str, + Field(description="Offering name (e.g., 'Winter Sale', 'New Product Launch')"), + ] + description: Annotated[ + Optional[str], Field(description="Description of what's being offered") + ] = None + assets: Annotated[ + Optional[list[dict[str, Any]]], + Field(description="Assets specific to this offering"), + ] = None + + +class AssetType14(Enum): + image = "image" + video = "video" + audio = "audio" + text = "text" + html = "html" + css = "css" + javascript = "javascript" + + +class AssetSelectors(BaseModel): + model_config = ConfigDict( + extra="forbid", + ) + tags: Annotated[ + Optional[list[str]], + Field( + description="Select assets with specific tags (e.g., ['holiday', 'premium'])" + ), + ] = None + asset_types: Annotated[ + Optional[list[AssetType14]], + Field(description="Filter by asset type (e.g., ['image', 'video'])"), + ] = None + exclude_tags: Annotated[ + Optional[list[str]], Field(description="Exclude assets with these tags") + ] = None + + +class PromotedOfferings(BaseModel): + model_config = ConfigDict( + extra="forbid", + ) + brand_manifest: Annotated[ + Union[Union[BrandManifest, BrandManifest6], AnyUrl], + Field( + description="Brand manifest provided either as an inline object or a URL string pointing to a hosted manifest", + examples=[ + { + "description": "Inline brand manifest", + "data": { + "url": "https://acmecorp.com", + "name": "ACME Corporation", + "colors": {"primary": "#FF6B35"}, + }, + }, + { + "description": "URL string reference to hosted manifest", + "data": "https://cdn.acmecorp.com/brand-manifest.json", + }, + ], + title="Brand Manifest Reference", + ), + ] + product_selectors: Annotated[ + Optional[ProductSelectors], + Field( + description="Specification of products or offerings being promoted in a campaign. Supports multiple selection methods from the brand manifest that can be combined using UNION (OR) logic. When multiple selection methods are provided, products matching ANY of the criteria are selected (logical OR, not AND).", + examples=[ + { + "description": "Direct SKU selection for specific products from brand manifest", + "data": {"manifest_skus": ["SKU-12345", "SKU-67890"]}, + }, + { + "description": "UNION selection: products tagged 'organic' OR 'sauces' OR in 'food/condiments' category from brand manifest", + "data": { + "manifest_tags": ["organic", "sauces"], + "manifest_category": "food/condiments", + }, + }, + { + "description": "Natural language product selection from brand manifest", + "data": {"manifest_query": "all Kraft Heinz pasta sauces under $5"}, + }, + { + "description": "Select products by tags", + "data": {"manifest_tags": ["holiday"]}, + }, + ], + title="Promoted Products", + ), + ] = None + offerings: Annotated[ + Optional[list[Offering]], + Field( + description="Inline offerings for campaigns without a product catalog. Each offering has a name, description, and associated assets." + ), + ] = None + asset_selectors: Annotated[ + Optional[AssetSelectors], + Field( + description="Selectors to choose specific assets from the brand manifest" + ), + ] = None + + +class PreviewCreativeRequest(BaseModel): + model_config = ConfigDict( + extra="forbid", + ) + format_id: Annotated[ + FormatId, + Field( + description="Structured format identifier with agent URL and format name", + title="Format ID", + ), + ] + creative_manifest: Annotated[ + CreativeManifest, + Field( + description="Complete specification of a creative with all assets needed for rendering in a specific format. Each asset is typed according to its asset_role from the format specification and contains the actual content/URL that fulfills the format requirements.", + title="Creative Manifest", + ), + ] + inputs: Annotated[ + Optional[list[Input]], + 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." + ), + ] = None + template_id: Annotated[ + Optional[str], + Field(description="Specific template ID for custom format rendering"), + ] = None + promoted_offerings: Annotated[ + Optional[PromotedOfferings], + Field( + description="Complete offering specification combining brand manifest, product selectors, and asset filters. Provides all context needed for creative generation about what is being promoted.", + examples=[ + { + "brand_manifest": {"url": "https://brand.com"}, + "product_selectors": {"manifest_skus": ["SKU-123", "SKU-456"]}, + "asset_selectors": { + "tags": ["holiday"], + "asset_types": ["image", "video"], + }, + } + ], + title="Promoted Offerings", + ), + ] = None diff --git a/src/creative_agent/schemas_generated/_schemas_v1_creative_preview_creative_response_json.py b/src/creative_agent/schemas_generated/_schemas_v1_creative_preview_creative_response_json.py new file mode 100644 index 0000000..da82f53 --- /dev/null +++ b/src/creative_agent/schemas_generated/_schemas_v1_creative_preview_creative_response_json.py @@ -0,0 +1,136 @@ +# generated by datamodel-codegen: +# filename: _schemas_v1_creative_preview-creative-response_json.json + +from __future__ import annotations + +from enum import Enum +from typing import Annotated, Optional + +from pydantic import AnyUrl, AwareDatetime, BaseModel, ConfigDict, Field + + +class Input(BaseModel): + name: Annotated[str, Field(description="Human-readable name for this variant")] + macros: Annotated[ + Optional[dict[str, str]], + Field(description="Macro values applied to this variant"), + ] = None + context_description: Annotated[ + Optional[str], Field(description="Context description applied to this variant") + ] = None + + +class PrimaryMediaType(Enum): + image = "image" + video = "video" + audio = "audio" + interactive = "interactive" + + +class EstimatedDimensions(BaseModel): + width: Annotated[float, Field(ge=0.0)] + height: Annotated[float, Field(ge=0.0)] + + +class Hints(BaseModel): + primary_media_type: Annotated[ + Optional[PrimaryMediaType], + Field( + description="Primary media type contained in the preview (for optimization only)" + ), + ] = None + estimated_dimensions: Annotated[ + Optional[EstimatedDimensions], + Field( + description="Estimated rendered dimensions (may differ from actual responsive rendering)" + ), + ] = None + estimated_duration_seconds: Annotated[ + Optional[float], + Field( + description="Estimated duration for video/audio content (for optimization only)", + ge=0.0, + ), + ] = None + contains_audio: Annotated[ + Optional[bool], + Field( + description="Whether the preview contains audio (helps with autoplay policies)" + ), + ] = None + requires_interaction: Annotated[ + Optional[bool], + Field( + description="Whether the preview requires user interaction to fully experience" + ), + ] = None + + +class Embedding(BaseModel): + recommended_sandbox: Annotated[ + Optional[str], + Field( + description="Recommended iframe sandbox attribute value (e.g., 'allow-scripts allow-same-origin')" + ), + ] = None + requires_https: Annotated[ + Optional[bool], + Field(description="Whether the preview requires HTTPS for secure embedding"), + ] = None + supports_fullscreen: Annotated[ + Optional[bool], + Field(description="Whether the preview supports fullscreen mode"), + ] = None + csp_policy: Annotated[ + Optional[str], + Field(description="Content Security Policy requirements for embedding"), + ] = None + + +class Preview(BaseModel): + preview_url: Annotated[ + AnyUrl, + Field( + description="URL to an HTML page that renders this preview variant. Can be embedded in an iframe. Handles all rendering complexity internally (images, video players, audio players, interactive content, etc.)." + ), + ] + input: Annotated[ + Input, + Field( + description="The input parameters that generated this preview variant. Echoes back the request input or shows defaults used." + ), + ] + hints: Annotated[ + Optional[Hints], + Field( + description="Optional optimization hints for clients. Clients MUST support HTML rendering regardless of hints. These enable optimizations like preloading appropriate codecs or sizing iframes." + ), + ] = None + embedding: Annotated[ + Optional[Embedding], + Field( + description="Optional security and embedding metadata for safe iframe integration" + ), + ] = None + + +class PreviewCreativeResponse(BaseModel): + model_config = ConfigDict( + extra="forbid", + ) + 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, + ), + ] + interactive_url: Annotated[ + Optional[AnyUrl], + 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 + expires_at: Annotated[ + AwareDatetime, Field(description="ISO 8601 timestamp when preview links expire") + ] diff --git a/src/creative_agent/schemas_generated/_schemas_v1_enums_identifier_types_json.py b/src/creative_agent/schemas_generated/_schemas_v1_enums_identifier_types_json.py new file mode 100644 index 0000000..8749ac0 --- /dev/null +++ b/src/creative_agent/schemas_generated/_schemas_v1_enums_identifier_types_json.py @@ -0,0 +1,28 @@ +# generated by datamodel-codegen: +# filename: _schemas_v1_enums_identifier-types_json.json + +from __future__ import annotations + +from enum import Enum + + +class PropertyIdentifierTypes(Enum): + domain = "domain" + subdomain = "subdomain" + network_id = "network_id" + ios_bundle = "ios_bundle" + android_package = "android_package" + apple_app_store_id = "apple_app_store_id" + google_play_id = "google_play_id" + roku_store_id = "roku_store_id" + fire_tv_asin = "fire_tv_asin" + samsung_app_id = "samsung_app_id" + apple_tv_bundle = "apple_tv_bundle" + bundle_id = "bundle_id" + venue_id = "venue_id" + screen_id = "screen_id" + openooh_venue_type = "openooh_venue_type" + rss_url = "rss_url" + apple_podcast_id = "apple_podcast_id" + spotify_show_id = "spotify_show_id" + podcast_guid = "podcast_guid" diff --git a/src/creative_agent/schemas_generated/_schemas_v1_media_buy_add_creative_assets_request_json.py b/src/creative_agent/schemas_generated/_schemas_v1_media_buy_add_creative_assets_request_json.py deleted file mode 100644 index ca80970..0000000 --- a/src/creative_agent/schemas_generated/_schemas_v1_media_buy_add_creative_assets_request_json.py +++ /dev/null @@ -1,468 +0,0 @@ -# generated by datamodel-codegen: -# filename: _schemas_v1_media-buy_add-creative-assets-request_json.json - -from __future__ import annotations - -from enum import Enum -from typing import Annotated, Literal, Optional, Union - -from pydantic import AnyUrl, BaseModel, ConfigDict, Field, RootModel - - -class FormatId(BaseModel): - model_config = ConfigDict( - extra="forbid", - ) - 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)" - ), - ] - id: Annotated[ - str, - Field( - description="Format identifier within the agent's namespace (e.g., 'display_300x250', 'video_standard_30s')", - pattern="^[a-zA-Z0-9_-]+$", - ), - ] - - -class Assets(BaseModel): - model_config = ConfigDict( - extra="forbid", - ) - asset_type: Literal["image"] - url: Annotated[AnyUrl, Field(description="URL to the image asset")] - width: Annotated[ - Optional[int], Field(description="Image width in pixels", ge=1) - ] = None - height: Annotated[ - Optional[int], Field(description="Image height in pixels", ge=1) - ] = None - format: Annotated[ - Optional[str], - Field(description="Image file format (jpg, png, gif, webp, etc.)"), - ] = None - alt_text: Annotated[ - Optional[str], Field(description="Alternative text for accessibility") - ] = None - - -class Assets12(BaseModel): - model_config = ConfigDict( - extra="forbid", - ) - asset_type: Literal["video"] - url: Annotated[AnyUrl, Field(description="URL to the video asset")] - width: Annotated[ - Optional[int], Field(description="Video width in pixels", ge=1) - ] = None - height: Annotated[ - Optional[int], Field(description="Video height in pixels", ge=1) - ] = None - duration_ms: Annotated[ - Optional[int], Field(description="Video duration in milliseconds", ge=0) - ] = None - format: Annotated[ - Optional[str], Field(description="Video file format (mp4, webm, mov, etc.)") - ] = None - bitrate_kbps: Annotated[ - Optional[int], Field(description="Video bitrate in kilobits per second", ge=1) - ] = None - - -class Assets13(BaseModel): - model_config = ConfigDict( - extra="forbid", - ) - asset_type: Literal["audio"] - url: Annotated[AnyUrl, Field(description="URL to the audio asset")] - duration_ms: Annotated[ - Optional[int], Field(description="Audio duration in milliseconds", ge=0) - ] = None - format: Annotated[ - Optional[str], Field(description="Audio file format (mp3, wav, aac, etc.)") - ] = None - bitrate_kbps: Annotated[ - Optional[int], Field(description="Audio bitrate in kilobits per second", ge=1) - ] = None - - -class Assets14(BaseModel): - model_config = ConfigDict( - extra="forbid", - ) - asset_type: Literal["text"] - content: Annotated[str, Field(description="Text content")] - max_length: Annotated[ - Optional[int], Field(description="Maximum character length constraint", ge=1) - ] = None - language: Annotated[ - Optional[str], Field(description="Language code (e.g., 'en', 'es', 'fr')") - ] = None - - -class Assets15(BaseModel): - model_config = ConfigDict( - extra="forbid", - ) - asset_type: Literal["html"] - content: Annotated[str, Field(description="HTML content")] - version: Annotated[ - Optional[str], Field(description="HTML version (e.g., 'HTML5')") - ] = None - - -class Assets16(BaseModel): - model_config = ConfigDict( - extra="forbid", - ) - asset_type: Literal["css"] - content: Annotated[str, Field(description="CSS content")] - media: Annotated[ - Optional[str], - Field(description="CSS media query context (e.g., 'screen', 'print')"), - ] = None - - -class ModuleType(Enum): - esm = "esm" - commonjs = "commonjs" - script = "script" - - -class Assets17(BaseModel): - model_config = ConfigDict( - extra="forbid", - ) - asset_type: Literal["javascript"] - content: Annotated[str, Field(description="JavaScript content")] - module_type: Annotated[ - Optional[ModuleType], Field(description="JavaScript module type") - ] = None - - -class Colors(BaseModel): - primary: Optional[str] = None - secondary: Optional[str] = None - accent: Optional[str] = None - - -class Assets18(BaseModel): - model_config = ConfigDict( - extra="forbid", - ) - asset_type: Literal["promoted_offerings"] - url: Annotated[ - Optional[AnyUrl], - Field( - description="URL of the advertiser's brand or offering (e.g., https://retailer.com)" - ), - ] = None - colors: Annotated[Optional[Colors], Field(description="Brand colors")] = None - fonts: Annotated[Optional[list[str]], Field(description="Brand fonts")] = None - tone: Annotated[Optional[str], Field(description="Brand tone/voice")] = None - - -class Assets19(BaseModel): - model_config = ConfigDict( - extra="forbid", - ) - asset_type: Literal["url"] - url: Annotated[AnyUrl, Field(description="URL reference")] - description: Annotated[ - Optional[str], Field(description="Description of what this URL points to") - ] = None - - -class Input(BaseModel): - model_config = ConfigDict( - extra="forbid", - ) - name: Annotated[ - str, Field(description="Human-readable name for this preview variant") - ] - macros: Annotated[ - Optional[dict[str, str]], - Field(description="Macro values to apply for this preview"), - ] = None - context_description: Annotated[ - Optional[str], - Field( - description="Natural language description of the context for AI-generated content" - ), - ] = None - - -class Asset(BaseModel): - model_config = ConfigDict( - extra="forbid", - ) - creative_id: Annotated[str, Field(description="Unique identifier for the creative")] - name: Annotated[str, Field(description="Human-readable creative name")] - format_id: Annotated[ - FormatId, - Field( - description="Structured format identifier with agent URL and format name", - title="Format ID", - ), - ] - assets: Annotated[ - dict[ - str, - Union[ - Assets, - Assets12, - Assets13, - Assets14, - Assets15, - Assets16, - Assets17, - Assets18, - Assets19, - ], - ], - Field(description="Assets required by the format, keyed by asset_role"), - ] - inputs: Annotated[ - Optional[list[Input]], - Field( - description="Preview contexts for generative formats - defines what scenarios to generate previews for" - ), - ] = None - tags: Annotated[ - Optional[list[str]], - Field(description="User-defined tags for organization and searchability"), - ] = None - approved: Annotated[ - Optional[bool], - Field( - description="For generative creatives: set to true to approve and finalize, false to request regeneration with updated assets/message. Omit for non-generative creatives." - ), - ] = None - - -class AddCreativeAssetsRequest1(BaseModel): - model_config = ConfigDict( - extra="forbid", - ) - media_buy_id: Annotated[ - str, Field(description="Publisher's ID of the media buy to add creatives to") - ] - buyer_ref: Annotated[ - Optional[str], Field(description="Buyer's reference for the media buy") - ] = None - assets: Annotated[ - list[Asset], Field(description="Array of creative assets to upload") - ] - - -class Assets20(BaseModel): - model_config = ConfigDict( - extra="forbid", - ) - asset_type: Literal["image"] - url: Annotated[AnyUrl, Field(description="URL to the image asset")] - width: Annotated[ - Optional[int], Field(description="Image width in pixels", ge=1) - ] = None - height: Annotated[ - Optional[int], Field(description="Image height in pixels", ge=1) - ] = None - format: Annotated[ - Optional[str], - Field(description="Image file format (jpg, png, gif, webp, etc.)"), - ] = None - alt_text: Annotated[ - Optional[str], Field(description="Alternative text for accessibility") - ] = None - - -class Assets21(BaseModel): - model_config = ConfigDict( - extra="forbid", - ) - asset_type: Literal["video"] - url: Annotated[AnyUrl, Field(description="URL to the video asset")] - width: Annotated[ - Optional[int], Field(description="Video width in pixels", ge=1) - ] = None - height: Annotated[ - Optional[int], Field(description="Video height in pixels", ge=1) - ] = None - duration_ms: Annotated[ - Optional[int], Field(description="Video duration in milliseconds", ge=0) - ] = None - format: Annotated[ - Optional[str], Field(description="Video file format (mp4, webm, mov, etc.)") - ] = None - bitrate_kbps: Annotated[ - Optional[int], Field(description="Video bitrate in kilobits per second", ge=1) - ] = None - - -class Assets22(BaseModel): - model_config = ConfigDict( - extra="forbid", - ) - asset_type: Literal["audio"] - url: Annotated[AnyUrl, Field(description="URL to the audio asset")] - duration_ms: Annotated[ - Optional[int], Field(description="Audio duration in milliseconds", ge=0) - ] = None - format: Annotated[ - Optional[str], Field(description="Audio file format (mp3, wav, aac, etc.)") - ] = None - bitrate_kbps: Annotated[ - Optional[int], Field(description="Audio bitrate in kilobits per second", ge=1) - ] = None - - -class Assets23(BaseModel): - model_config = ConfigDict( - extra="forbid", - ) - asset_type: Literal["text"] - content: Annotated[str, Field(description="Text content")] - max_length: Annotated[ - Optional[int], Field(description="Maximum character length constraint", ge=1) - ] = None - language: Annotated[ - Optional[str], Field(description="Language code (e.g., 'en', 'es', 'fr')") - ] = None - - -class Assets24(BaseModel): - model_config = ConfigDict( - extra="forbid", - ) - asset_type: Literal["html"] - content: Annotated[str, Field(description="HTML content")] - version: Annotated[ - Optional[str], Field(description="HTML version (e.g., 'HTML5')") - ] = None - - -class Assets25(BaseModel): - model_config = ConfigDict( - extra="forbid", - ) - asset_type: Literal["css"] - content: Annotated[str, Field(description="CSS content")] - media: Annotated[ - Optional[str], - Field(description="CSS media query context (e.g., 'screen', 'print')"), - ] = None - - -class Assets26(BaseModel): - model_config = ConfigDict( - extra="forbid", - ) - asset_type: Literal["javascript"] - content: Annotated[str, Field(description="JavaScript content")] - module_type: Annotated[ - Optional[ModuleType], Field(description="JavaScript module type") - ] = None - - -class Assets27(BaseModel): - model_config = ConfigDict( - extra="forbid", - ) - asset_type: Literal["promoted_offerings"] - url: Annotated[ - Optional[AnyUrl], - Field( - description="URL of the advertiser's brand or offering (e.g., https://retailer.com)" - ), - ] = None - colors: Annotated[Optional[Colors], Field(description="Brand colors")] = None - fonts: Annotated[Optional[list[str]], Field(description="Brand fonts")] = None - tone: Annotated[Optional[str], Field(description="Brand tone/voice")] = None - - -class Assets28(BaseModel): - model_config = ConfigDict( - extra="forbid", - ) - asset_type: Literal["url"] - url: Annotated[AnyUrl, Field(description="URL reference")] - description: Annotated[ - Optional[str], Field(description="Description of what this URL points to") - ] = None - - -class Asset6(BaseModel): - model_config = ConfigDict( - extra="forbid", - ) - creative_id: Annotated[str, Field(description="Unique identifier for the creative")] - name: Annotated[str, Field(description="Human-readable creative name")] - format_id: Annotated[ - FormatId, - Field( - description="Structured format identifier with agent URL and format name", - title="Format ID", - ), - ] - assets: Annotated[ - dict[ - str, - Union[ - Assets20, - Assets21, - Assets22, - Assets23, - Assets24, - Assets25, - Assets26, - Assets27, - Assets28, - ], - ], - Field(description="Assets required by the format, keyed by asset_role"), - ] - inputs: Annotated[ - Optional[list[Input]], - Field( - description="Preview contexts for generative formats - defines what scenarios to generate previews for" - ), - ] = None - tags: Annotated[ - Optional[list[str]], - Field(description="User-defined tags for organization and searchability"), - ] = None - approved: Annotated[ - Optional[bool], - Field( - description="For generative creatives: set to true to approve and finalize, false to request regeneration with updated assets/message. Omit for non-generative creatives." - ), - ] = None - - -class AddCreativeAssetsRequest2(BaseModel): - model_config = ConfigDict( - extra="forbid", - ) - media_buy_id: Annotated[ - Optional[str], - Field(description="Publisher's ID of the media buy to add creatives to"), - ] = None - buyer_ref: Annotated[str, Field(description="Buyer's reference for the media buy")] - assets: Annotated[ - list[Asset6], Field(description="Array of creative assets to upload") - ] - - -class AddCreativeAssetsRequest( - RootModel[Union[AddCreativeAssetsRequest1, AddCreativeAssetsRequest2]] -): - root: Annotated[ - Union[AddCreativeAssetsRequest1, AddCreativeAssetsRequest2], - Field( - description="Request parameters for uploading creative assets", - title="Add Creative Assets Request", - ), - ] diff --git a/src/creative_agent/schemas_generated/_schemas_v1_media_buy_add_creative_assets_response_json.py b/src/creative_agent/schemas_generated/_schemas_v1_media_buy_add_creative_assets_response_json.py deleted file mode 100644 index be2ab4f..0000000 --- a/src/creative_agent/schemas_generated/_schemas_v1_media_buy_add_creative_assets_response_json.py +++ /dev/null @@ -1,67 +0,0 @@ -# generated by datamodel-codegen: -# filename: _schemas_v1_media-buy_add-creative-assets-response_json.json - -from __future__ import annotations - -from enum import Enum -from typing import Annotated, Optional - -from pydantic import BaseModel, ConfigDict, Field - - -class Status(Enum): - processing = "processing" - approved = "approved" - rejected = "rejected" - pending_review = "pending_review" - - -class SuggestedAdaptation(BaseModel): - model_config = ConfigDict( - extra="forbid", - ) - adaptation_id: Annotated[ - str, Field(description="Unique identifier for this adaptation") - ] - format_id: Annotated[str, Field(description="Target format ID for the adaptation")] - name: Annotated[str, Field(description="Suggested name for the adapted creative")] - description: Annotated[str, Field(description="What this adaptation does")] - changes_summary: Annotated[ - list[str], Field(description="List of changes that will be made") - ] - rationale: Annotated[str, Field(description="Why this adaptation is recommended")] - estimated_performance_lift: Annotated[ - Optional[float], - Field(description="Expected performance improvement (percentage)", ge=0.0), - ] = None - - -class AssetStatus(BaseModel): - model_config = ConfigDict( - extra="forbid", - ) - creative_id: Annotated[str, Field(description="The creative ID from the request")] - status: Annotated[ - Status, Field(description="Status of a creative asset", title="Creative Status") - ] - platform_id: Annotated[ - Optional[str], - Field(description="Platform-specific ID assigned to the creative"), - ] = None - review_feedback: Annotated[ - Optional[str], Field(description="Feedback from platform review (if any)") - ] = None - suggested_adaptations: Annotated[ - Optional[list[SuggestedAdaptation]], - Field(description="Array of recommended format adaptations"), - ] = None - - -class AddCreativeAssetsResponse(BaseModel): - model_config = ConfigDict( - extra="forbid", - ) - asset_statuses: Annotated[ - list[AssetStatus], - Field(description="Array of status information for each uploaded asset"), - ] diff --git a/src/creative_agent/schemas_generated/_schemas_v1_media_buy_create_media_buy_request_json.py b/src/creative_agent/schemas_generated/_schemas_v1_media_buy_create_media_buy_request_json.py deleted file mode 100644 index d328c5e..0000000 --- a/src/creative_agent/schemas_generated/_schemas_v1_media_buy_create_media_buy_request_json.py +++ /dev/null @@ -1,1168 +0,0 @@ -# generated by datamodel-codegen: -# filename: _schemas_v1_media-buy_create-media-buy-request_json.json - -from __future__ import annotations - -from enum import Enum -from typing import Annotated, Any, Optional, Union - -from pydantic import ( - AnyUrl, - AwareDatetime, - BaseModel, - ConfigDict, - EmailStr, - Field, - RootModel, -) - - -class Pacing(Enum): - even = "even" - asap = "asap" - front_loaded = "front_loaded" - - -class Budget(BaseModel): - model_config = ConfigDict( - extra="forbid", - ) - total: Annotated[float, Field(description="Total budget amount", ge=0.0)] - currency: Annotated[ - str, - Field( - description="ISO 4217 currency code", - examples=["USD", "EUR", "GBP"], - pattern="^[A-Z]{3}$", - ), - ] - pacing: Annotated[ - Optional[Pacing], Field(description="Budget pacing strategy", title="Pacing") - ] = None - - -class GeoCountryAnyOfItem(RootModel[str]): - root: Annotated[str, Field(pattern="^[A-Z]{2}$")] - - -class FrequencyCap(BaseModel): - model_config = ConfigDict( - extra="forbid", - ) - suppress_minutes: Annotated[ - float, Field(description="Minutes to suppress after impression", ge=0.0) - ] - - -class TargetingOverlay(BaseModel): - model_config = ConfigDict( - extra="forbid", - ) - geo_country_any_of: Annotated[ - Optional[list[GeoCountryAnyOfItem]], - Field( - description="Restrict delivery to specific countries (ISO codes). Use for regulatory compliance or RCT testing." - ), - ] = None - geo_region_any_of: Annotated[ - Optional[list[str]], - Field( - description="Restrict delivery to specific regions/states. Use for regulatory compliance or RCT testing." - ), - ] = None - geo_metro_any_of: Annotated[ - Optional[list[str]], - Field( - description="Restrict delivery to specific metro areas (DMA codes). Use for regulatory compliance or RCT testing." - ), - ] = None - geo_postal_code_any_of: Annotated[ - Optional[list[str]], - Field( - description="Restrict delivery to specific postal/ZIP codes. Use for regulatory compliance or RCT testing." - ), - ] = None - frequency_cap: Annotated[ - Optional[FrequencyCap], - Field( - description="Frequency capping settings for package-level application", - title="Frequency Cap", - ), - ] = None - - -class Packages(BaseModel): - model_config = ConfigDict( - extra="forbid", - ) - buyer_ref: Annotated[ - str, Field(description="Buyer's reference identifier for this package") - ] - products: Annotated[ - list[str], Field(description="Array of product IDs to include in this package") - ] - format_ids: Annotated[ - list[str], - Field( - description="Array of format IDs that will be used for this package - must be supported by all products" - ), - ] - budget: Annotated[ - Optional[Budget], - Field( - description="Budget configuration for a media buy or package", - title="Budget", - ), - ] = None - targeting_overlay: Annotated[ - Optional[TargetingOverlay], - Field( - description="Optional geographic refinements for media buys. Most targeting should be expressed in the brief and handled by the publisher. These fields are primarily for geographic restrictions (RCT testing, regulatory compliance).", - title="Targeting Overlay", - ), - ] = None - creative_ids: Annotated[ - Optional[list[str]], - Field(description="Creative IDs to assign to this package at creation time"), - ] = None - - -class Packages1(BaseModel): - model_config = ConfigDict( - extra="forbid", - ) - buyer_ref: Annotated[ - str, Field(description="Buyer's reference identifier for this package") - ] - products: Annotated[ - list[str], Field(description="Array of product IDs to include in this package") - ] - format_selection: Annotated[ - dict[str, Any], Field(description="Dynamic format selection criteria") - ] - budget: Annotated[ - Optional[Any], - Field(description="Circular reference to /schemas/v1/core/budget.json"), - ] = None - targeting_overlay: Annotated[ - Optional[Any], - Field(description="Circular reference to /schemas/v1/core/targeting.json"), - ] = None - creative_ids: Annotated[ - Optional[list[str]], - Field(description="Creative IDs to assign to this package at creation time"), - ] = None - - -class Logo(BaseModel): - url: Annotated[AnyUrl, Field(description="URL to the logo asset")] - tags: Annotated[ - Optional[list[str]], - Field( - description="Semantic tags describing the logo variant (e.g., 'dark', 'light', 'square', 'horizontal', 'icon')" - ), - ] = None - width: Annotated[Optional[int], Field(description="Logo width in pixels")] = None - height: Annotated[Optional[int], Field(description="Logo height in pixels")] = None - - -class Colors(BaseModel): - primary: Annotated[ - Optional[str], - Field( - description="Primary brand color (hex format)", pattern="^#[0-9A-Fa-f]{6}$" - ), - ] = None - secondary: Annotated[ - Optional[str], - Field( - description="Secondary brand color (hex format)", - pattern="^#[0-9A-Fa-f]{6}$", - ), - ] = None - accent: Annotated[ - Optional[str], - Field(description="Accent color (hex format)", pattern="^#[0-9A-Fa-f]{6}$"), - ] = None - background: Annotated[ - Optional[str], - Field(description="Background color (hex format)", pattern="^#[0-9A-Fa-f]{6}$"), - ] = None - text: Annotated[ - Optional[str], - Field(description="Text color (hex format)", pattern="^#[0-9A-Fa-f]{6}$"), - ] = None - - -class Fonts(BaseModel): - primary: Annotated[Optional[str], Field(description="Primary font family name")] = ( - None - ) - secondary: Annotated[ - Optional[str], Field(description="Secondary font family name") - ] = None - font_urls: Annotated[ - Optional[list[AnyUrl]], - Field(description="URLs to web font files if using custom fonts"), - ] = None - - -class AssetType(Enum): - image = "image" - video = "video" - audio = "audio" - text = "text" - - -class Asset(BaseModel): - model_config = ConfigDict( - extra="forbid", - ) - asset_id: Annotated[str, Field(description="Unique identifier for this asset")] - asset_type: Annotated[AssetType, Field(description="Type of asset")] - url: Annotated[AnyUrl, Field(description="URL to CDN-hosted asset file")] - tags: Annotated[ - Optional[list[str]], - Field( - description="Tags for asset discovery (e.g., 'holiday', 'lifestyle', 'product_shot')" - ), - ] = None - name: Annotated[Optional[str], Field(description="Human-readable asset name")] = ( - None - ) - description: Annotated[ - Optional[str], Field(description="Asset description or usage notes") - ] = None - width: Annotated[ - Optional[int], Field(description="Image/video width in pixels") - ] = None - height: Annotated[ - Optional[int], Field(description="Image/video height in pixels") - ] = None - duration_seconds: Annotated[ - Optional[float], Field(description="Video/audio duration in seconds") - ] = None - file_size_bytes: Annotated[ - Optional[int], Field(description="File size in bytes") - ] = None - format: Annotated[ - Optional[str], Field(description="File format (e.g., 'jpg', 'mp4', 'mp3')") - ] = None - metadata: Annotated[ - Optional[dict[str, Any]], - Field(description="Additional asset-specific metadata"), - ] = None - - -class FeedFormat(Enum): - google_merchant_center = "google_merchant_center" - facebook_catalog = "facebook_catalog" - custom = "custom" - - -class UpdateFrequency(Enum): - realtime = "realtime" - hourly = "hourly" - daily = "daily" - weekly = "weekly" - - -class ProductCatalog(BaseModel): - model_config = ConfigDict( - extra="forbid", - ) - feed_url: Annotated[AnyUrl, Field(description="URL to product catalog feed")] - feed_format: Annotated[ - Optional[FeedFormat], Field(description="Format of the product feed") - ] = "google_merchant_center" - categories: Annotated[ - Optional[list[str]], - Field( - description="Product categories available in the catalog (for filtering)" - ), - ] = None - last_updated: Annotated[ - Optional[AwareDatetime], - Field(description="When the product catalog was last updated"), - ] = None - update_frequency: Annotated[ - Optional[UpdateFrequency], - Field(description="How frequently the product catalog is updated"), - ] = None - - -class Disclaimer(BaseModel): - text: Annotated[str, Field(description="Disclaimer text")] - context: Annotated[ - Optional[str], - Field( - description="When this disclaimer applies (e.g., 'financial_products', 'health_claims', 'all')" - ), - ] = None - required: Annotated[ - Optional[bool], Field(description="Whether this disclaimer must appear") - ] = True - - -class Contact(BaseModel): - email: Annotated[Optional[EmailStr], Field(description="Contact email")] = None - phone: Annotated[Optional[str], Field(description="Contact phone number")] = None - - -class Metadata(BaseModel): - created_date: Annotated[ - Optional[AwareDatetime], - Field(description="When this brand manifest was created"), - ] = None - updated_date: Annotated[ - Optional[AwareDatetime], - Field(description="When this brand manifest was last updated"), - ] = None - version: Annotated[ - Optional[str], Field(description="Brand card version number") - ] = None - - -class BrandManifest(BaseModel): - model_config = ConfigDict( - extra="forbid", - ) - url: Annotated[ - AnyUrl, - Field( - description="Primary brand URL for context and asset discovery. Creative agents can infer brand information from this URL." - ), - ] - name: Annotated[Optional[str], Field(description="Brand or business name")] = None - logos: Annotated[ - Optional[list[Logo]], - Field( - description="Brand logo assets with semantic tags for different use cases" - ), - ] = None - colors: Annotated[Optional[Colors], Field(description="Brand color palette")] = None - fonts: Annotated[ - Optional[Fonts], Field(description="Brand typography guidelines") - ] = None - tone: Annotated[ - Optional[str], - Field( - description="Brand voice and messaging tone (e.g., 'professional', 'casual', 'humorous', 'trustworthy', 'innovative')" - ), - ] = None - tagline: Annotated[Optional[str], Field(description="Brand tagline or slogan")] = ( - None - ) - assets: Annotated[ - Optional[list[Asset]], - Field( - description="Brand asset library with explicit assets and tags. Assets are referenced inline with URLs pointing to CDN-hosted files." - ), - ] = None - product_catalog: Annotated[ - Optional[ProductCatalog], - Field( - description="Product catalog information for e-commerce advertisers. Enables SKU-level creative generation and product selection." - ), - ] = None - disclaimers: Annotated[ - Optional[list[Disclaimer]], - Field( - description="Legal disclaimers or required text that must appear in creatives" - ), - ] = None - industry: Annotated[ - Optional[str], - Field( - description="Industry or vertical (e.g., 'retail', 'automotive', 'finance', 'healthcare')" - ), - ] = None - target_audience: Annotated[ - Optional[str], Field(description="Primary target audience description") - ] = None - contact: Annotated[ - Optional[Contact], Field(description="Brand contact information") - ] = None - metadata: Annotated[ - Optional[Metadata], Field(description="Additional brand metadata") - ] = None - - -class Asset8(BaseModel): - model_config = ConfigDict( - extra="forbid", - ) - asset_id: Annotated[str, Field(description="Unique identifier for this asset")] - asset_type: Annotated[AssetType, Field(description="Type of asset")] - url: Annotated[AnyUrl, Field(description="URL to CDN-hosted asset file")] - tags: Annotated[ - Optional[list[str]], - Field( - description="Tags for asset discovery (e.g., 'holiday', 'lifestyle', 'product_shot')" - ), - ] = None - name: Annotated[Optional[str], Field(description="Human-readable asset name")] = ( - None - ) - description: Annotated[ - Optional[str], Field(description="Asset description or usage notes") - ] = None - width: Annotated[ - Optional[int], Field(description="Image/video width in pixels") - ] = None - height: Annotated[ - Optional[int], Field(description="Image/video height in pixels") - ] = None - duration_seconds: Annotated[ - Optional[float], Field(description="Video/audio duration in seconds") - ] = None - file_size_bytes: Annotated[ - Optional[int], Field(description="File size in bytes") - ] = None - format: Annotated[ - Optional[str], Field(description="File format (e.g., 'jpg', 'mp4', 'mp3')") - ] = None - metadata: Annotated[ - Optional[dict[str, Any]], - Field(description="Additional asset-specific metadata"), - ] = None - - -class ProductCatalog5(BaseModel): - model_config = ConfigDict( - extra="forbid", - ) - feed_url: Annotated[AnyUrl, Field(description="URL to product catalog feed")] - feed_format: Annotated[ - Optional[FeedFormat], Field(description="Format of the product feed") - ] = "google_merchant_center" - categories: Annotated[ - Optional[list[str]], - Field( - description="Product categories available in the catalog (for filtering)" - ), - ] = None - last_updated: Annotated[ - Optional[AwareDatetime], - Field(description="When the product catalog was last updated"), - ] = None - update_frequency: Annotated[ - Optional[UpdateFrequency], - Field(description="How frequently the product catalog is updated"), - ] = None - - -class BrandManifest4(BaseModel): - model_config = ConfigDict( - extra="forbid", - ) - url: Annotated[ - Optional[AnyUrl], - Field( - description="Primary brand URL for context and asset discovery. Creative agents can infer brand information from this URL." - ), - ] = None - name: Annotated[str, Field(description="Brand or business name")] - logos: Annotated[ - Optional[list[Logo]], - Field( - description="Brand logo assets with semantic tags for different use cases" - ), - ] = None - colors: Annotated[Optional[Colors], Field(description="Brand color palette")] = None - fonts: Annotated[ - Optional[Fonts], Field(description="Brand typography guidelines") - ] = None - tone: Annotated[ - Optional[str], - Field( - description="Brand voice and messaging tone (e.g., 'professional', 'casual', 'humorous', 'trustworthy', 'innovative')" - ), - ] = None - tagline: Annotated[Optional[str], Field(description="Brand tagline or slogan")] = ( - None - ) - assets: Annotated[ - Optional[list[Asset8]], - Field( - description="Brand asset library with explicit assets and tags. Assets are referenced inline with URLs pointing to CDN-hosted files." - ), - ] = None - product_catalog: Annotated[ - Optional[ProductCatalog5], - Field( - description="Product catalog information for e-commerce advertisers. Enables SKU-level creative generation and product selection." - ), - ] = None - disclaimers: Annotated[ - Optional[list[Disclaimer]], - Field( - description="Legal disclaimers or required text that must appear in creatives" - ), - ] = None - industry: Annotated[ - Optional[str], - Field( - description="Industry or vertical (e.g., 'retail', 'automotive', 'finance', 'healthcare')" - ), - ] = None - target_audience: Annotated[ - Optional[str], Field(description="Primary target audience description") - ] = None - contact: Annotated[ - Optional[Contact], Field(description="Brand contact information") - ] = None - metadata: Annotated[ - Optional[Metadata], Field(description="Additional brand metadata") - ] = None - - -class Scheme(Enum): - bearer = "Bearer" - hmac_sha256 = "HMAC-SHA256" - - -class Authentication(BaseModel): - model_config = ConfigDict( - extra="forbid", - ) - schemes: Annotated[ - list[Scheme], - Field( - description="Array of authentication schemes. Supported: ['Bearer'] for simple token auth, ['HMAC-SHA256'] for signature verification (recommended for production)", - max_length=1, - min_length=1, - ), - ] - credentials: Annotated[ - str, - Field( - description="Credentials for authentication. For Bearer: token sent in Authorization header. For HMAC-SHA256: shared secret used to generate signature. Minimum 32 characters. Exchanged out-of-band during onboarding.", - min_length=32, - ), - ] - - -class ReportingFrequency(Enum): - hourly = "hourly" - daily = "daily" - monthly = "monthly" - - -class RequestedMetric(Enum): - impressions = "impressions" - spend = "spend" - clicks = "clicks" - ctr = "ctr" - video_completions = "video_completions" - completion_rate = "completion_rate" - conversions = "conversions" - viewability = "viewability" - engagement_rate = "engagement_rate" - - -class ReportingWebhook(BaseModel): - url: Annotated[ - AnyUrl, Field(description="Webhook endpoint URL for task status notifications") - ] - token: Annotated[ - Optional[str], - Field( - description="Optional client-provided token for webhook validation. Echoed back in webhook payload to validate request authenticity.", - min_length=16, - ), - ] = None - authentication: Annotated[ - Authentication, - Field( - description="Authentication configuration for webhook delivery (A2A-compatible)" - ), - ] - reporting_frequency: Annotated[ - ReportingFrequency, - Field( - description="Frequency for automated reporting delivery. Must be supported by all products in the media buy." - ), - ] - requested_metrics: Annotated[ - Optional[list[RequestedMetric]], - Field( - description="Optional list of metrics to include in webhook notifications. If omitted, all available metrics are included. Must be subset of product's available_metrics." - ), - ] = None - - -class CreateMediaBuyRequest1(BaseModel): - model_config = ConfigDict( - extra="forbid", - ) - adcp_version: Annotated[ - Optional[str], - Field( - description="AdCP schema version for this request", - pattern="^\\d+\\.\\d+\\.\\d+$", - ), - ] = "1.6.1" - buyer_ref: Annotated[ - str, Field(description="Buyer's reference identifier for this media buy") - ] - packages: Annotated[ - list[Union[Packages, Packages1]], - Field(description="Array of package configurations"), - ] - brand_manifest: Annotated[ - Optional[Union[Union[BrandManifest, BrandManifest4], AnyUrl]], - Field( - description="Brand manifest provided either as an inline object or a URL string pointing to a hosted manifest", - examples=[ - { - "description": "Inline brand manifest", - "data": { - "url": "https://acmecorp.com", - "name": "ACME Corporation", - "colors": {"primary": "#FF6B35"}, - }, - }, - { - "description": "URL string reference to hosted manifest", - "data": "https://cdn.acmecorp.com/brand-manifest.json", - }, - ], - title="Brand Manifest Reference", - ), - ] = None - promoted_offering: Annotated[ - str, - Field( - description="DEPRECATED: Use brand_manifest instead. Legacy field for describing what is being promoted." - ), - ] - po_number: Annotated[ - Optional[str], Field(description="Purchase order number for tracking") - ] = None - start_time: Annotated[ - Union[str, AwareDatetime], - Field( - description="Campaign start timing: 'asap' or ISO 8601 date-time", - title="Start Timing", - ), - ] - end_time: Annotated[ - AwareDatetime, Field(description="Campaign end date/time in ISO 8601 format") - ] - budget: Annotated[ - float, - Field( - description="Total budget for this media buy. Currency is determined by the pricing_option_id selected in each package.", - ge=0.0, - ), - ] - reporting_webhook: Optional[ReportingWebhook] = None - - -class Budget2(BaseModel): - model_config = ConfigDict( - extra="forbid", - ) - total: Annotated[float, Field(description="Total budget amount", ge=0.0)] - currency: Annotated[ - str, - Field( - description="ISO 4217 currency code", - examples=["USD", "EUR", "GBP"], - pattern="^[A-Z]{3}$", - ), - ] - pacing: Annotated[ - Optional[Pacing], Field(description="Budget pacing strategy", title="Pacing") - ] = None - - -class TargetingOverlay3(BaseModel): - model_config = ConfigDict( - extra="forbid", - ) - geo_country_any_of: Annotated[ - Optional[list[GeoCountryAnyOfItem]], - Field( - description="Restrict delivery to specific countries (ISO codes). Use for regulatory compliance or RCT testing." - ), - ] = None - geo_region_any_of: Annotated[ - Optional[list[str]], - Field( - description="Restrict delivery to specific regions/states. Use for regulatory compliance or RCT testing." - ), - ] = None - geo_metro_any_of: Annotated[ - Optional[list[str]], - Field( - description="Restrict delivery to specific metro areas (DMA codes). Use for regulatory compliance or RCT testing." - ), - ] = None - geo_postal_code_any_of: Annotated[ - Optional[list[str]], - Field( - description="Restrict delivery to specific postal/ZIP codes. Use for regulatory compliance or RCT testing." - ), - ] = None - frequency_cap: Annotated[ - Optional[FrequencyCap], - Field( - description="Frequency capping settings for package-level application", - title="Frequency Cap", - ), - ] = None - - -class Packages2(BaseModel): - model_config = ConfigDict( - extra="forbid", - ) - buyer_ref: Annotated[ - str, Field(description="Buyer's reference identifier for this package") - ] - products: Annotated[ - list[str], Field(description="Array of product IDs to include in this package") - ] - format_ids: Annotated[ - list[str], - Field( - description="Array of format IDs that will be used for this package - must be supported by all products" - ), - ] - budget: Annotated[ - Optional[Budget2], - Field( - description="Budget configuration for a media buy or package", - title="Budget", - ), - ] = None - targeting_overlay: Annotated[ - Optional[TargetingOverlay3], - Field( - description="Optional geographic refinements for media buys. Most targeting should be expressed in the brief and handled by the publisher. These fields are primarily for geographic restrictions (RCT testing, regulatory compliance).", - title="Targeting Overlay", - ), - ] = None - creative_ids: Annotated[ - Optional[list[str]], - Field(description="Creative IDs to assign to this package at creation time"), - ] = None - - -class Packages3(BaseModel): - model_config = ConfigDict( - extra="forbid", - ) - buyer_ref: Annotated[ - str, Field(description="Buyer's reference identifier for this package") - ] - products: Annotated[ - list[str], Field(description="Array of product IDs to include in this package") - ] - format_selection: Annotated[ - dict[str, Any], Field(description="Dynamic format selection criteria") - ] - budget: Annotated[ - Optional[Any], - Field(description="Circular reference to /schemas/v1/core/budget.json"), - ] = None - targeting_overlay: Annotated[ - Optional[Any], - Field(description="Circular reference to /schemas/v1/core/targeting.json"), - ] = None - creative_ids: Annotated[ - Optional[list[str]], - Field(description="Creative IDs to assign to this package at creation time"), - ] = None - - -class Asset9(BaseModel): - model_config = ConfigDict( - extra="forbid", - ) - asset_id: Annotated[str, Field(description="Unique identifier for this asset")] - asset_type: Annotated[AssetType, Field(description="Type of asset")] - url: Annotated[AnyUrl, Field(description="URL to CDN-hosted asset file")] - tags: Annotated[ - Optional[list[str]], - Field( - description="Tags for asset discovery (e.g., 'holiday', 'lifestyle', 'product_shot')" - ), - ] = None - name: Annotated[Optional[str], Field(description="Human-readable asset name")] = ( - None - ) - description: Annotated[ - Optional[str], Field(description="Asset description or usage notes") - ] = None - width: Annotated[ - Optional[int], Field(description="Image/video width in pixels") - ] = None - height: Annotated[ - Optional[int], Field(description="Image/video height in pixels") - ] = None - duration_seconds: Annotated[ - Optional[float], Field(description="Video/audio duration in seconds") - ] = None - file_size_bytes: Annotated[ - Optional[int], Field(description="File size in bytes") - ] = None - format: Annotated[ - Optional[str], Field(description="File format (e.g., 'jpg', 'mp4', 'mp3')") - ] = None - metadata: Annotated[ - Optional[dict[str, Any]], - Field(description="Additional asset-specific metadata"), - ] = None - - -class ProductCatalog6(BaseModel): - model_config = ConfigDict( - extra="forbid", - ) - feed_url: Annotated[AnyUrl, Field(description="URL to product catalog feed")] - feed_format: Annotated[ - Optional[FeedFormat], Field(description="Format of the product feed") - ] = "google_merchant_center" - categories: Annotated[ - Optional[list[str]], - Field( - description="Product categories available in the catalog (for filtering)" - ), - ] = None - last_updated: Annotated[ - Optional[AwareDatetime], - Field(description="When the product catalog was last updated"), - ] = None - update_frequency: Annotated[ - Optional[UpdateFrequency], - Field(description="How frequently the product catalog is updated"), - ] = None - - -class BrandManifest5(BaseModel): - model_config = ConfigDict( - extra="forbid", - ) - url: Annotated[ - AnyUrl, - Field( - description="Primary brand URL for context and asset discovery. Creative agents can infer brand information from this URL." - ), - ] - name: Annotated[Optional[str], Field(description="Brand or business name")] = None - logos: Annotated[ - Optional[list[Logo]], - Field( - description="Brand logo assets with semantic tags for different use cases" - ), - ] = None - colors: Annotated[Optional[Colors], Field(description="Brand color palette")] = None - fonts: Annotated[ - Optional[Fonts], Field(description="Brand typography guidelines") - ] = None - tone: Annotated[ - Optional[str], - Field( - description="Brand voice and messaging tone (e.g., 'professional', 'casual', 'humorous', 'trustworthy', 'innovative')" - ), - ] = None - tagline: Annotated[Optional[str], Field(description="Brand tagline or slogan")] = ( - None - ) - assets: Annotated[ - Optional[list[Asset9]], - Field( - description="Brand asset library with explicit assets and tags. Assets are referenced inline with URLs pointing to CDN-hosted files." - ), - ] = None - product_catalog: Annotated[ - Optional[ProductCatalog6], - Field( - description="Product catalog information for e-commerce advertisers. Enables SKU-level creative generation and product selection." - ), - ] = None - disclaimers: Annotated[ - Optional[list[Disclaimer]], - Field( - description="Legal disclaimers or required text that must appear in creatives" - ), - ] = None - industry: Annotated[ - Optional[str], - Field( - description="Industry or vertical (e.g., 'retail', 'automotive', 'finance', 'healthcare')" - ), - ] = None - target_audience: Annotated[ - Optional[str], Field(description="Primary target audience description") - ] = None - contact: Annotated[ - Optional[Contact], Field(description="Brand contact information") - ] = None - metadata: Annotated[ - Optional[Metadata], Field(description="Additional brand metadata") - ] = None - - -class Asset10(BaseModel): - model_config = ConfigDict( - extra="forbid", - ) - asset_id: Annotated[str, Field(description="Unique identifier for this asset")] - asset_type: Annotated[AssetType, Field(description="Type of asset")] - url: Annotated[AnyUrl, Field(description="URL to CDN-hosted asset file")] - tags: Annotated[ - Optional[list[str]], - Field( - description="Tags for asset discovery (e.g., 'holiday', 'lifestyle', 'product_shot')" - ), - ] = None - name: Annotated[Optional[str], Field(description="Human-readable asset name")] = ( - None - ) - description: Annotated[ - Optional[str], Field(description="Asset description or usage notes") - ] = None - width: Annotated[ - Optional[int], Field(description="Image/video width in pixels") - ] = None - height: Annotated[ - Optional[int], Field(description="Image/video height in pixels") - ] = None - duration_seconds: Annotated[ - Optional[float], Field(description="Video/audio duration in seconds") - ] = None - file_size_bytes: Annotated[ - Optional[int], Field(description="File size in bytes") - ] = None - format: Annotated[ - Optional[str], Field(description="File format (e.g., 'jpg', 'mp4', 'mp3')") - ] = None - metadata: Annotated[ - Optional[dict[str, Any]], - Field(description="Additional asset-specific metadata"), - ] = None - - -class ProductCatalog7(BaseModel): - model_config = ConfigDict( - extra="forbid", - ) - feed_url: Annotated[AnyUrl, Field(description="URL to product catalog feed")] - feed_format: Annotated[ - Optional[FeedFormat], Field(description="Format of the product feed") - ] = "google_merchant_center" - categories: Annotated[ - Optional[list[str]], - Field( - description="Product categories available in the catalog (for filtering)" - ), - ] = None - last_updated: Annotated[ - Optional[AwareDatetime], - Field(description="When the product catalog was last updated"), - ] = None - update_frequency: Annotated[ - Optional[UpdateFrequency], - Field(description="How frequently the product catalog is updated"), - ] = None - - -class BrandManifest6(BaseModel): - model_config = ConfigDict( - extra="forbid", - ) - url: Annotated[ - Optional[AnyUrl], - Field( - description="Primary brand URL for context and asset discovery. Creative agents can infer brand information from this URL." - ), - ] = None - name: Annotated[str, Field(description="Brand or business name")] - logos: Annotated[ - Optional[list[Logo]], - Field( - description="Brand logo assets with semantic tags for different use cases" - ), - ] = None - colors: Annotated[Optional[Colors], Field(description="Brand color palette")] = None - fonts: Annotated[ - Optional[Fonts], Field(description="Brand typography guidelines") - ] = None - tone: Annotated[ - Optional[str], - Field( - description="Brand voice and messaging tone (e.g., 'professional', 'casual', 'humorous', 'trustworthy', 'innovative')" - ), - ] = None - tagline: Annotated[Optional[str], Field(description="Brand tagline or slogan")] = ( - None - ) - assets: Annotated[ - Optional[list[Asset10]], - Field( - description="Brand asset library with explicit assets and tags. Assets are referenced inline with URLs pointing to CDN-hosted files." - ), - ] = None - product_catalog: Annotated[ - Optional[ProductCatalog7], - Field( - description="Product catalog information for e-commerce advertisers. Enables SKU-level creative generation and product selection." - ), - ] = None - disclaimers: Annotated[ - Optional[list[Disclaimer]], - Field( - description="Legal disclaimers or required text that must appear in creatives" - ), - ] = None - industry: Annotated[ - Optional[str], - Field( - description="Industry or vertical (e.g., 'retail', 'automotive', 'finance', 'healthcare')" - ), - ] = None - target_audience: Annotated[ - Optional[str], Field(description="Primary target audience description") - ] = None - contact: Annotated[ - Optional[Contact], Field(description="Brand contact information") - ] = None - metadata: Annotated[ - Optional[Metadata], Field(description="Additional brand metadata") - ] = None - - -class Authentication2(BaseModel): - model_config = ConfigDict( - extra="forbid", - ) - schemes: Annotated[ - list[Scheme], - Field( - description="Array of authentication schemes. Supported: ['Bearer'] for simple token auth, ['HMAC-SHA256'] for signature verification (recommended for production)", - max_length=1, - min_length=1, - ), - ] - credentials: Annotated[ - str, - Field( - description="Credentials for authentication. For Bearer: token sent in Authorization header. For HMAC-SHA256: shared secret used to generate signature. Minimum 32 characters. Exchanged out-of-band during onboarding.", - min_length=32, - ), - ] - - -class ReportingWebhook1(BaseModel): - url: Annotated[ - AnyUrl, Field(description="Webhook endpoint URL for task status notifications") - ] - token: Annotated[ - Optional[str], - Field( - description="Optional client-provided token for webhook validation. Echoed back in webhook payload to validate request authenticity.", - min_length=16, - ), - ] = None - authentication: Annotated[ - Authentication2, - Field( - description="Authentication configuration for webhook delivery (A2A-compatible)" - ), - ] - reporting_frequency: Annotated[ - ReportingFrequency, - Field( - description="Frequency for automated reporting delivery. Must be supported by all products in the media buy." - ), - ] - requested_metrics: Annotated[ - Optional[list[RequestedMetric]], - Field( - description="Optional list of metrics to include in webhook notifications. If omitted, all available metrics are included. Must be subset of product's available_metrics." - ), - ] = None - - -class CreateMediaBuyRequest2(BaseModel): - model_config = ConfigDict( - extra="forbid", - ) - adcp_version: Annotated[ - Optional[str], - Field( - description="AdCP schema version for this request", - pattern="^\\d+\\.\\d+\\.\\d+$", - ), - ] = "1.6.1" - buyer_ref: Annotated[ - str, Field(description="Buyer's reference identifier for this media buy") - ] - packages: Annotated[ - list[Union[Packages2, Packages3]], - Field(description="Array of package configurations"), - ] - brand_manifest: Annotated[ - Union[Union[BrandManifest5, BrandManifest6], AnyUrl], - Field( - description="Brand manifest provided either as an inline object or a URL string pointing to a hosted manifest", - examples=[ - { - "description": "Inline brand manifest", - "data": { - "url": "https://acmecorp.com", - "name": "ACME Corporation", - "colors": {"primary": "#FF6B35"}, - }, - }, - { - "description": "URL string reference to hosted manifest", - "data": "https://cdn.acmecorp.com/brand-manifest.json", - }, - ], - title="Brand Manifest Reference", - ), - ] - promoted_offering: Annotated[ - Optional[str], - Field( - description="DEPRECATED: Use brand_manifest instead. Legacy field for describing what is being promoted." - ), - ] = None - po_number: Annotated[ - Optional[str], Field(description="Purchase order number for tracking") - ] = None - start_time: Annotated[ - Union[str, AwareDatetime], - Field( - description="Campaign start timing: 'asap' or ISO 8601 date-time", - title="Start Timing", - ), - ] - end_time: Annotated[ - AwareDatetime, Field(description="Campaign end date/time in ISO 8601 format") - ] - budget: Annotated[ - float, - Field( - description="Total budget for this media buy. Currency is determined by the pricing_option_id selected in each package.", - ge=0.0, - ), - ] - reporting_webhook: Optional[ReportingWebhook1] = None - - -class CreateMediaBuyRequest( - RootModel[Union[CreateMediaBuyRequest1, CreateMediaBuyRequest2]] -): - root: Annotated[ - Union[CreateMediaBuyRequest1, CreateMediaBuyRequest2], - Field( - description="Request parameters for creating a media buy", - title="Create Media Buy Request", - ), - ] diff --git a/src/creative_agent/schemas_generated/_schemas_v1_media_buy_create_media_buy_response_json.py b/src/creative_agent/schemas_generated/_schemas_v1_media_buy_create_media_buy_response_json.py deleted file mode 100644 index b5c9475..0000000 --- a/src/creative_agent/schemas_generated/_schemas_v1_media_buy_create_media_buy_response_json.py +++ /dev/null @@ -1,103 +0,0 @@ -# generated by datamodel-codegen: -# filename: _schemas_v1_media-buy_create-media-buy-response_json.json - -from __future__ import annotations - -from enum import Enum -from typing import Annotated, Any, Optional - -from pydantic import AwareDatetime, BaseModel, ConfigDict, Field - - -class Status(Enum): - submitted = "submitted" - working = "working" - input_required = "input-required" - completed = "completed" - canceled = "canceled" - failed = "failed" - rejected = "rejected" - auth_required = "auth-required" - unknown = "unknown" - - -class Package(BaseModel): - model_config = ConfigDict( - extra="forbid", - ) - package_id: Annotated[ - str, Field(description="Publisher's unique identifier for the package") - ] - buyer_ref: Annotated[ - str, Field(description="Buyer's reference identifier for the package") - ] - - -class Error(BaseModel): - model_config = ConfigDict( - extra="forbid", - ) - code: Annotated[str, Field(description="Error code for programmatic handling")] - message: Annotated[str, Field(description="Human-readable error message")] - field: Annotated[ - Optional[str], - Field( - description="Field path associated with the error (e.g., 'packages[0].targeting')" - ), - ] = None - suggestion: Annotated[ - Optional[str], Field(description="Suggested fix for the error") - ] = None - retry_after: Annotated[ - Optional[float], - Field(description="Seconds to wait before retrying the operation", ge=0.0), - ] = None - details: Annotated[ - Optional[Any], Field(description="Additional task-specific error details") - ] = None - - -class CreateMediaBuyResponse(BaseModel): - model_config = ConfigDict( - extra="forbid", - ) - adcp_version: Annotated[ - str, - Field( - description="AdCP schema version used for this response", - pattern="^\\d+\\.\\d+\\.\\d+$", - ), - ] - status: Annotated[ - Status, - Field( - description="Standardized task status values based on A2A TaskState enum. Indicates the current state of any AdCP operation.", - title="Task Status", - ), - ] - task_id: Annotated[ - Optional[str], - Field( - description="Unique identifier for tracking this async operation (present for submitted/working status)" - ), - ] = None - media_buy_id: Annotated[ - Optional[str], - Field(description="Publisher's unique identifier for the created media buy"), - ] = None - buyer_ref: Annotated[ - str, Field(description="Buyer's reference identifier for this media buy") - ] - creative_deadline: Annotated[ - Optional[AwareDatetime], - Field(description="ISO 8601 timestamp for creative upload deadline"), - ] = None - packages: Annotated[ - Optional[list[Package]], Field(description="Array of created packages") - ] = None - errors: Annotated[ - Optional[list[Error]], - Field( - description="Task-specific errors and warnings (e.g., partial package creation failures)" - ), - ] = None diff --git a/src/creative_agent/schemas_generated/_schemas_v1_media_buy_get_media_buy_delivery_request_json.py b/src/creative_agent/schemas_generated/_schemas_v1_media_buy_get_media_buy_delivery_request_json.py deleted file mode 100644 index dbbf15b..0000000 --- a/src/creative_agent/schemas_generated/_schemas_v1_media_buy_get_media_buy_delivery_request_json.py +++ /dev/null @@ -1,67 +0,0 @@ -# generated by datamodel-codegen: -# filename: _schemas_v1_media-buy_get-media-buy-delivery-request_json.json - -from __future__ import annotations - -from enum import Enum -from typing import Annotated, Optional, Union - -from pydantic import BaseModel, ConfigDict, Field - - -class StatusFilter(Enum): - active = "active" - pending = "pending" - paused = "paused" - completed = "completed" - failed = "failed" - all = "all" - - -class StatusFilterEnum(Enum): - active = "active" - pending = "pending" - paused = "paused" - completed = "completed" - failed = "failed" - - -class GetMediaBuyDeliveryRequest(BaseModel): - model_config = ConfigDict( - extra="forbid", - ) - adcp_version: Annotated[ - Optional[str], - Field( - description="AdCP schema version for this request", - pattern="^\\d+\\.\\d+\\.\\d+$", - ), - ] = "1.6.0" - media_buy_ids: Annotated[ - Optional[list[str]], - Field(description="Array of publisher media buy IDs to get delivery data for"), - ] = None - buyer_refs: Annotated[ - Optional[list[str]], - Field(description="Array of buyer reference IDs to get delivery data for"), - ] = None - status_filter: Annotated[ - Optional[Union[StatusFilter, list[StatusFilterEnum]]], - Field( - description="Filter by status. Can be a single status or array of statuses" - ), - ] = None - start_date: Annotated[ - Optional[str], - Field( - description="Start date for reporting period (YYYY-MM-DD)", - pattern="^\\d{4}-\\d{2}-\\d{2}$", - ), - ] = None - end_date: Annotated[ - Optional[str], - Field( - description="End date for reporting period (YYYY-MM-DD)", - pattern="^\\d{4}-\\d{2}-\\d{2}$", - ), - ] = None diff --git a/src/creative_agent/schemas_generated/_schemas_v1_media_buy_get_media_buy_delivery_response_json.py b/src/creative_agent/schemas_generated/_schemas_v1_media_buy_get_media_buy_delivery_response_json.py deleted file mode 100644 index 93f7761..0000000 --- a/src/creative_agent/schemas_generated/_schemas_v1_media_buy_get_media_buy_delivery_response_json.py +++ /dev/null @@ -1,389 +0,0 @@ -# generated by datamodel-codegen: -# filename: _schemas_v1_media-buy_get-media-buy-delivery-response_json.json - -from __future__ import annotations - -from enum import Enum -from typing import Annotated, Any, Optional - -from pydantic import AwareDatetime, BaseModel, ConfigDict, Field - - -class NotificationType(Enum): - scheduled = "scheduled" - final = "final" - delayed = "delayed" - adjusted = "adjusted" - - -class ReportingPeriod(BaseModel): - model_config = ConfigDict( - extra="forbid", - ) - start: Annotated[ - AwareDatetime, - Field( - description="ISO 8601 start timestamp in UTC (e.g., 2024-02-05T00:00:00Z)" - ), - ] - end: Annotated[ - AwareDatetime, - Field(description="ISO 8601 end timestamp in UTC (e.g., 2024-02-05T23:59:59Z)"), - ] - - -class AggregatedTotals(BaseModel): - model_config = ConfigDict( - extra="forbid", - ) - impressions: Annotated[ - float, - Field(description="Total impressions delivered across all media buys", ge=0.0), - ] - spend: Annotated[ - float, Field(description="Total amount spent across all media buys", ge=0.0) - ] - clicks: Annotated[ - Optional[float], - Field(description="Total clicks across all media buys (if applicable)", ge=0.0), - ] = None - video_completions: Annotated[ - Optional[float], - Field( - description="Total video completions across all media buys (if applicable)", - ge=0.0, - ), - ] = None - media_buy_count: Annotated[ - int, Field(description="Number of media buys included in the response", ge=0) - ] - - -class Status(Enum): - pending = "pending" - active = "active" - paused = "paused" - completed = "completed" - failed = "failed" - reporting_delayed = "reporting_delayed" - - -class PricingModel(Enum): - cpm = "cpm" - cpc = "cpc" - cpcv = "cpcv" - cpv = "cpv" - cpp = "cpp" - flat_rate = "flat_rate" - - -class QuartileData(BaseModel): - q1_views: Annotated[ - Optional[float], Field(description="25% completion views", ge=0.0) - ] = None - q2_views: Annotated[ - Optional[float], Field(description="50% completion views", ge=0.0) - ] = None - q3_views: Annotated[ - Optional[float], Field(description="75% completion views", ge=0.0) - ] = None - q4_views: Annotated[ - Optional[float], Field(description="100% completion views", ge=0.0) - ] = None - - -class VenueBreakdownItem(BaseModel): - model_config = ConfigDict( - extra="forbid", - ) - venue_id: Annotated[str, Field(description="Venue identifier")] - venue_name: Annotated[ - Optional[str], Field(description="Human-readable venue name") - ] = None - venue_type: Annotated[ - Optional[str], - Field( - description="Venue type (e.g., 'airport', 'transit', 'retail', 'billboard')" - ), - ] = None - impressions: Annotated[ - int, Field(description="Impressions delivered at this venue", ge=0) - ] - loop_plays: Annotated[ - Optional[int], Field(description="Loop plays at this venue", ge=0) - ] = None - screens_used: Annotated[ - Optional[int], Field(description="Number of screens used at this venue", ge=0) - ] = None - - -class DoohMetrics(BaseModel): - model_config = ConfigDict( - extra="forbid", - ) - loop_plays: Annotated[ - Optional[int], Field(description="Number of times ad played in rotation", ge=0) - ] = None - screens_used: Annotated[ - Optional[int], - Field(description="Number of unique screens displaying the ad", ge=0), - ] = None - screen_time_seconds: Annotated[ - Optional[int], Field(description="Total display time in seconds", ge=0) - ] = None - sov_achieved: Annotated[ - Optional[float], - Field( - description="Actual share of voice delivered (0.0 to 1.0)", ge=0.0, le=1.0 - ), - ] = None - calculation_notes: Annotated[ - Optional[str], - Field(description="Explanation of how DOOH impressions were calculated"), - ] = None - venue_breakdown: Annotated[ - Optional[list[VenueBreakdownItem]], - Field(description="Per-venue performance breakdown"), - ] = None - - -class Totals(BaseModel): - impressions: Annotated[ - Optional[float], Field(description="Impressions delivered", ge=0.0) - ] = None - spend: Annotated[Optional[float], Field(description="Amount spent", ge=0.0)] = None - clicks: Annotated[Optional[float], Field(description="Total clicks", ge=0.0)] = None - ctr: Annotated[ - Optional[float], - Field(description="Click-through rate (clicks/impressions)", ge=0.0, le=1.0), - ] = None - views: Annotated[ - Optional[float], Field(description="Views at threshold (for CPV)", ge=0.0) - ] = None - completed_views: Annotated[ - Optional[float], Field(description="100% completions (for CPCV)", ge=0.0) - ] = None - video_completions: Annotated[ - Optional[float], - Field(description="DEPRECATED: Use completed_views instead", ge=0.0), - ] = None - completion_rate: Annotated[ - Optional[float], - Field( - description="Completion rate (completed_views/impressions)", ge=0.0, le=1.0 - ), - ] = None - conversions: Annotated[ - Optional[float], - Field( - description="Conversions (reserved for future CPA pricing support)", ge=0.0 - ), - ] = None - leads: Annotated[ - Optional[float], - Field( - description="Leads generated (reserved for future CPL pricing support)", - ge=0.0, - ), - ] = None - grps: Annotated[ - Optional[float], - Field(description="Gross Rating Points delivered (for CPP)", ge=0.0), - ] = None - reach: Annotated[ - Optional[float], - Field( - description="Unique reach - units depend on measurement provider (e.g., individuals, households, devices, cookies). See delivery_measurement.provider for methodology.", - ge=0.0, - ), - ] = None - frequency: Annotated[ - Optional[float], - Field( - description="Average frequency per individual (typically measured over campaign duration, but can vary by measurement provider)", - ge=0.0, - ), - ] = None - quartile_data: Annotated[ - Optional[QuartileData], Field(description="Video quartile completion data") - ] = None - dooh_metrics: Annotated[ - Optional[DoohMetrics], - Field(description="DOOH-specific metrics (only included for DOOH campaigns)"), - ] = None - effective_rate: Annotated[ - Optional[float], - Field( - description="Effective rate paid per unit based on pricing_model (e.g., actual CPM for 'cpm', actual cost per completed view for 'cpcv', actual cost per point for 'cpp')", - ge=0.0, - ), - ] = None - - -class ByPackageItem(BaseModel): - package_id: Annotated[str, Field(description="Publisher's package identifier")] - buyer_ref: Annotated[ - Optional[str], - Field(description="Buyer's reference identifier for this package"), - ] = None - pacing_index: Annotated[ - Optional[float], - Field( - description="Delivery pace (1.0 = on track, <1.0 = behind, >1.0 = ahead)", - ge=0.0, - ), - ] = None - - -class DailyBreakdownItem(BaseModel): - model_config = ConfigDict( - extra="forbid", - ) - date: Annotated[ - str, Field(description="Date (YYYY-MM-DD)", pattern="^\\d{4}-\\d{2}-\\d{2}$") - ] - impressions: Annotated[float, Field(description="Daily impressions", ge=0.0)] - spend: Annotated[float, Field(description="Daily spend", ge=0.0)] - - -class MediaBuyDelivery(BaseModel): - model_config = ConfigDict( - extra="forbid", - ) - media_buy_id: Annotated[str, Field(description="Publisher's media buy identifier")] - buyer_ref: Annotated[ - Optional[str], - Field(description="Buyer's reference identifier for this media buy"), - ] = None - status: Annotated[ - Status, - Field( - description="Current media buy status. In webhook context, reporting_delayed indicates data temporarily unavailable." - ), - ] - message: Annotated[ - Optional[str], - Field( - description="Human-readable message (typically present when status is reporting_delayed or failed)" - ), - ] = None - expected_availability: Annotated[ - Optional[AwareDatetime], - Field( - description="When delayed data is expected to be available (only present when status is reporting_delayed)" - ), - ] = None - is_adjusted: Annotated[ - Optional[bool], - Field( - description="Indicates this delivery contains updated data for a previously reported period. Buyer should replace previous period data with these totals." - ), - ] = None - pricing_model: Annotated[ - Optional[PricingModel], - Field( - description="Supported pricing models for advertising products", - title="Pricing Model", - ), - ] = None - totals: Totals - by_package: Annotated[ - list[ByPackageItem], Field(description="Metrics broken down by package") - ] - daily_breakdown: Annotated[ - Optional[list[DailyBreakdownItem]], Field(description="Day-by-day delivery") - ] = None - - -class Error(BaseModel): - model_config = ConfigDict( - extra="forbid", - ) - code: Annotated[str, Field(description="Error code for programmatic handling")] - message: Annotated[str, Field(description="Human-readable error message")] - field: Annotated[ - Optional[str], - Field( - description="Field path associated with the error (e.g., 'packages[0].targeting')" - ), - ] = None - suggestion: Annotated[ - Optional[str], Field(description="Suggested fix for the error") - ] = None - retry_after: Annotated[ - Optional[float], - Field(description="Seconds to wait before retrying the operation", ge=0.0), - ] = None - details: Annotated[ - Optional[Any], Field(description="Additional task-specific error details") - ] = None - - -class GetMediaBuyDeliveryResponse(BaseModel): - model_config = ConfigDict( - extra="forbid", - ) - adcp_version: Annotated[ - str, - Field( - description="AdCP schema version used for this response", - pattern="^\\d+\\.\\d+\\.\\d+$", - ), - ] - notification_type: Annotated[ - Optional[NotificationType], - 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[ - Optional[bool], - Field( - description="Indicates if any media buys in this webhook have missing/delayed data (only present in webhook deliveries)" - ), - ] = None - unavailable_count: Annotated[ - Optional[int], - Field( - description="Number of media buys with reporting_delayed or failed status (only present in webhook deliveries when partial_data is true)", - ge=0, - ), - ] = None - sequence_number: Annotated[ - Optional[int], - Field( - description="Sequential notification number (only present in webhook deliveries, starts at 1)", - ge=1, - ), - ] = None - next_expected_at: Annotated[ - Optional[AwareDatetime], - Field( - description="ISO 8601 timestamp for next expected notification (only present in webhook deliveries when notification_type is not 'final')" - ), - ] = None - reporting_period: Annotated[ - ReportingPeriod, - Field(description="Date range for the report. All periods use UTC timezone."), - ] - currency: Annotated[ - str, Field(description="ISO 4217 currency code", pattern="^[A-Z]{3}$") - ] - aggregated_totals: Annotated[ - Optional[AggregatedTotals], - Field( - description="Combined metrics across all returned media buys. Only included in API responses (get_media_buy_delivery), not in webhook notifications." - ), - ] = 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." - ), - ] - errors: Annotated[ - Optional[list[Error]], - Field( - description="Task-specific errors and warnings (e.g., missing delivery data, reporting platform issues)" - ), - ] = None diff --git a/src/creative_agent/schemas_generated/_schemas_v1_media_buy_get_products_request_json.py b/src/creative_agent/schemas_generated/_schemas_v1_media_buy_get_products_request_json.py deleted file mode 100644 index 93d5384..0000000 --- a/src/creative_agent/schemas_generated/_schemas_v1_media_buy_get_products_request_json.py +++ /dev/null @@ -1,814 +0,0 @@ -# generated by datamodel-codegen: -# filename: _schemas_v1_media-buy_get-products-request_json.json - -from __future__ import annotations - -from enum import Enum -from typing import Annotated, Any, Optional, Union - -from pydantic import ( - AnyUrl, - AwareDatetime, - BaseModel, - ConfigDict, - EmailStr, - Field, - RootModel, -) - - -class Logo(BaseModel): - url: Annotated[AnyUrl, Field(description="URL to the logo asset")] - tags: Annotated[ - Optional[list[str]], - Field( - description="Semantic tags describing the logo variant (e.g., 'dark', 'light', 'square', 'horizontal', 'icon')" - ), - ] = None - width: Annotated[Optional[int], Field(description="Logo width in pixels")] = None - height: Annotated[Optional[int], Field(description="Logo height in pixels")] = None - - -class Colors(BaseModel): - primary: Annotated[ - Optional[str], - Field( - description="Primary brand color (hex format)", pattern="^#[0-9A-Fa-f]{6}$" - ), - ] = None - secondary: Annotated[ - Optional[str], - Field( - description="Secondary brand color (hex format)", - pattern="^#[0-9A-Fa-f]{6}$", - ), - ] = None - accent: Annotated[ - Optional[str], - Field(description="Accent color (hex format)", pattern="^#[0-9A-Fa-f]{6}$"), - ] = None - background: Annotated[ - Optional[str], - Field(description="Background color (hex format)", pattern="^#[0-9A-Fa-f]{6}$"), - ] = None - text: Annotated[ - Optional[str], - Field(description="Text color (hex format)", pattern="^#[0-9A-Fa-f]{6}$"), - ] = None - - -class Fonts(BaseModel): - primary: Annotated[Optional[str], Field(description="Primary font family name")] = ( - None - ) - secondary: Annotated[ - Optional[str], Field(description="Secondary font family name") - ] = None - font_urls: Annotated[ - Optional[list[AnyUrl]], - Field(description="URLs to web font files if using custom fonts"), - ] = None - - -class AssetType(Enum): - image = "image" - video = "video" - audio = "audio" - text = "text" - - -class Asset(BaseModel): - model_config = ConfigDict( - extra="forbid", - ) - asset_id: Annotated[str, Field(description="Unique identifier for this asset")] - asset_type: Annotated[AssetType, Field(description="Type of asset")] - url: Annotated[AnyUrl, Field(description="URL to CDN-hosted asset file")] - tags: Annotated[ - Optional[list[str]], - Field( - description="Tags for asset discovery (e.g., 'holiday', 'lifestyle', 'product_shot')" - ), - ] = None - name: Annotated[Optional[str], Field(description="Human-readable asset name")] = ( - None - ) - description: Annotated[ - Optional[str], Field(description="Asset description or usage notes") - ] = None - width: Annotated[ - Optional[int], Field(description="Image/video width in pixels") - ] = None - height: Annotated[ - Optional[int], Field(description="Image/video height in pixels") - ] = None - duration_seconds: Annotated[ - Optional[float], Field(description="Video/audio duration in seconds") - ] = None - file_size_bytes: Annotated[ - Optional[int], Field(description="File size in bytes") - ] = None - format: Annotated[ - Optional[str], Field(description="File format (e.g., 'jpg', 'mp4', 'mp3')") - ] = None - metadata: Annotated[ - Optional[dict[str, Any]], - Field(description="Additional asset-specific metadata"), - ] = None - - -class FeedFormat(Enum): - google_merchant_center = "google_merchant_center" - facebook_catalog = "facebook_catalog" - custom = "custom" - - -class UpdateFrequency(Enum): - realtime = "realtime" - hourly = "hourly" - daily = "daily" - weekly = "weekly" - - -class ProductCatalog(BaseModel): - model_config = ConfigDict( - extra="forbid", - ) - feed_url: Annotated[AnyUrl, Field(description="URL to product catalog feed")] - feed_format: Annotated[ - Optional[FeedFormat], Field(description="Format of the product feed") - ] = "google_merchant_center" - categories: Annotated[ - Optional[list[str]], - Field( - description="Product categories available in the catalog (for filtering)" - ), - ] = None - last_updated: Annotated[ - Optional[AwareDatetime], - Field(description="When the product catalog was last updated"), - ] = None - update_frequency: Annotated[ - Optional[UpdateFrequency], - Field(description="How frequently the product catalog is updated"), - ] = None - - -class Disclaimer(BaseModel): - text: Annotated[str, Field(description="Disclaimer text")] - context: Annotated[ - Optional[str], - Field( - description="When this disclaimer applies (e.g., 'financial_products', 'health_claims', 'all')" - ), - ] = None - required: Annotated[ - Optional[bool], Field(description="Whether this disclaimer must appear") - ] = True - - -class Contact(BaseModel): - email: Annotated[Optional[EmailStr], Field(description="Contact email")] = None - phone: Annotated[Optional[str], Field(description="Contact phone number")] = None - - -class Metadata(BaseModel): - created_date: Annotated[ - Optional[AwareDatetime], - Field(description="When this brand manifest was created"), - ] = None - updated_date: Annotated[ - Optional[AwareDatetime], - Field(description="When this brand manifest was last updated"), - ] = None - version: Annotated[ - Optional[str], Field(description="Brand card version number") - ] = None - - -class BrandManifest(BaseModel): - model_config = ConfigDict( - extra="forbid", - ) - url: Annotated[ - AnyUrl, - Field( - description="Primary brand URL for context and asset discovery. Creative agents can infer brand information from this URL." - ), - ] - name: Annotated[Optional[str], Field(description="Brand or business name")] = None - logos: Annotated[ - Optional[list[Logo]], - Field( - description="Brand logo assets with semantic tags for different use cases" - ), - ] = None - colors: Annotated[Optional[Colors], Field(description="Brand color palette")] = None - fonts: Annotated[ - Optional[Fonts], Field(description="Brand typography guidelines") - ] = None - tone: Annotated[ - Optional[str], - Field( - description="Brand voice and messaging tone (e.g., 'professional', 'casual', 'humorous', 'trustworthy', 'innovative')" - ), - ] = None - tagline: Annotated[Optional[str], Field(description="Brand tagline or slogan")] = ( - None - ) - assets: Annotated[ - Optional[list[Asset]], - Field( - description="Brand asset library with explicit assets and tags. Assets are referenced inline with URLs pointing to CDN-hosted files." - ), - ] = None - product_catalog: Annotated[ - Optional[ProductCatalog], - Field( - description="Product catalog information for e-commerce advertisers. Enables SKU-level creative generation and product selection." - ), - ] = None - disclaimers: Annotated[ - Optional[list[Disclaimer]], - Field( - description="Legal disclaimers or required text that must appear in creatives" - ), - ] = None - industry: Annotated[ - Optional[str], - Field( - description="Industry or vertical (e.g., 'retail', 'automotive', 'finance', 'healthcare')" - ), - ] = None - target_audience: Annotated[ - Optional[str], Field(description="Primary target audience description") - ] = None - contact: Annotated[ - Optional[Contact], Field(description="Brand contact information") - ] = None - metadata: Annotated[ - Optional[Metadata], Field(description="Additional brand metadata") - ] = None - - -class Asset12(BaseModel): - model_config = ConfigDict( - extra="forbid", - ) - asset_id: Annotated[str, Field(description="Unique identifier for this asset")] - asset_type: Annotated[AssetType, Field(description="Type of asset")] - url: Annotated[AnyUrl, Field(description="URL to CDN-hosted asset file")] - tags: Annotated[ - Optional[list[str]], - Field( - description="Tags for asset discovery (e.g., 'holiday', 'lifestyle', 'product_shot')" - ), - ] = None - name: Annotated[Optional[str], Field(description="Human-readable asset name")] = ( - None - ) - description: Annotated[ - Optional[str], Field(description="Asset description or usage notes") - ] = None - width: Annotated[ - Optional[int], Field(description="Image/video width in pixels") - ] = None - height: Annotated[ - Optional[int], Field(description="Image/video height in pixels") - ] = None - duration_seconds: Annotated[ - Optional[float], Field(description="Video/audio duration in seconds") - ] = None - file_size_bytes: Annotated[ - Optional[int], Field(description="File size in bytes") - ] = None - format: Annotated[ - Optional[str], Field(description="File format (e.g., 'jpg', 'mp4', 'mp3')") - ] = None - metadata: Annotated[ - Optional[dict[str, Any]], - Field(description="Additional asset-specific metadata"), - ] = None - - -class ProductCatalog9(BaseModel): - model_config = ConfigDict( - extra="forbid", - ) - feed_url: Annotated[AnyUrl, Field(description="URL to product catalog feed")] - feed_format: Annotated[ - Optional[FeedFormat], Field(description="Format of the product feed") - ] = "google_merchant_center" - categories: Annotated[ - Optional[list[str]], - Field( - description="Product categories available in the catalog (for filtering)" - ), - ] = None - last_updated: Annotated[ - Optional[AwareDatetime], - Field(description="When the product catalog was last updated"), - ] = None - update_frequency: Annotated[ - Optional[UpdateFrequency], - Field(description="How frequently the product catalog is updated"), - ] = None - - -class BrandManifest8(BaseModel): - model_config = ConfigDict( - extra="forbid", - ) - url: Annotated[ - Optional[AnyUrl], - Field( - description="Primary brand URL for context and asset discovery. Creative agents can infer brand information from this URL." - ), - ] = None - name: Annotated[str, Field(description="Brand or business name")] - logos: Annotated[ - Optional[list[Logo]], - Field( - description="Brand logo assets with semantic tags for different use cases" - ), - ] = None - colors: Annotated[Optional[Colors], Field(description="Brand color palette")] = None - fonts: Annotated[ - Optional[Fonts], Field(description="Brand typography guidelines") - ] = None - tone: Annotated[ - Optional[str], - Field( - description="Brand voice and messaging tone (e.g., 'professional', 'casual', 'humorous', 'trustworthy', 'innovative')" - ), - ] = None - tagline: Annotated[Optional[str], Field(description="Brand tagline or slogan")] = ( - None - ) - assets: Annotated[ - Optional[list[Asset12]], - Field( - description="Brand asset library with explicit assets and tags. Assets are referenced inline with URLs pointing to CDN-hosted files." - ), - ] = None - product_catalog: Annotated[ - Optional[ProductCatalog9], - Field( - description="Product catalog information for e-commerce advertisers. Enables SKU-level creative generation and product selection." - ), - ] = None - disclaimers: Annotated[ - Optional[list[Disclaimer]], - Field( - description="Legal disclaimers or required text that must appear in creatives" - ), - ] = None - industry: Annotated[ - Optional[str], - Field( - description="Industry or vertical (e.g., 'retail', 'automotive', 'finance', 'healthcare')" - ), - ] = None - target_audience: Annotated[ - Optional[str], Field(description="Primary target audience description") - ] = None - contact: Annotated[ - Optional[Contact], Field(description="Brand contact information") - ] = None - metadata: Annotated[ - Optional[Metadata], Field(description="Additional brand metadata") - ] = None - - -class DeliveryType(Enum): - guaranteed = "guaranteed" - non_guaranteed = "non_guaranteed" - - -class FormatType(Enum): - video = "video" - display = "display" - audio = "audio" - - -class Filters(BaseModel): - model_config = ConfigDict( - extra="forbid", - ) - delivery_type: Annotated[ - Optional[DeliveryType], - Field(description="Type of inventory delivery", title="Delivery Type"), - ] = None - is_fixed_price: Annotated[ - Optional[bool], Field(description="Filter for fixed price vs auction products") - ] = None - format_types: Annotated[ - Optional[list[FormatType]], Field(description="Filter by format types") - ] = None - format_ids: Annotated[ - Optional[list[str]], Field(description="Filter by specific format IDs") - ] = None - standard_formats_only: Annotated[ - Optional[bool], - Field(description="Only return products accepting IAB standard formats"), - ] = None - min_exposures: Annotated[ - Optional[int], - Field( - description="Minimum exposures/impressions needed for measurement validity", - ge=1, - ), - ] = None - - -class GetProductsRequest1(BaseModel): - model_config = ConfigDict( - extra="forbid", - ) - adcp_version: Annotated[ - Optional[str], - Field( - description="AdCP schema version for this request", - pattern="^\\d+\\.\\d+\\.\\d+$", - ), - ] = "1.6.0" - brief: Annotated[ - Optional[str], - Field(description="Natural language description of campaign requirements"), - ] = None - promoted_offering: Annotated[ - str, - Field( - description="DEPRECATED: Use brand_manifest instead. Legacy field for describing what is being promoted." - ), - ] - brand_manifest: Annotated[ - Optional[Union[Union[BrandManifest, BrandManifest8], AnyUrl]], - Field( - description="Brand manifest provided either as an inline object or a URL string pointing to a hosted manifest", - examples=[ - { - "description": "Inline brand manifest", - "data": { - "url": "https://acmecorp.com", - "name": "ACME Corporation", - "colors": {"primary": "#FF6B35"}, - }, - }, - { - "description": "URL string reference to hosted manifest", - "data": "https://cdn.acmecorp.com/brand-manifest.json", - }, - ], - title="Brand Manifest Reference", - ), - ] = None - filters: Annotated[ - Optional[Filters], Field(description="Structured filters for product discovery") - ] = None - - -class Asset13(BaseModel): - model_config = ConfigDict( - extra="forbid", - ) - asset_id: Annotated[str, Field(description="Unique identifier for this asset")] - asset_type: Annotated[AssetType, Field(description="Type of asset")] - url: Annotated[AnyUrl, Field(description="URL to CDN-hosted asset file")] - tags: Annotated[ - Optional[list[str]], - Field( - description="Tags for asset discovery (e.g., 'holiday', 'lifestyle', 'product_shot')" - ), - ] = None - name: Annotated[Optional[str], Field(description="Human-readable asset name")] = ( - None - ) - description: Annotated[ - Optional[str], Field(description="Asset description or usage notes") - ] = None - width: Annotated[ - Optional[int], Field(description="Image/video width in pixels") - ] = None - height: Annotated[ - Optional[int], Field(description="Image/video height in pixels") - ] = None - duration_seconds: Annotated[ - Optional[float], Field(description="Video/audio duration in seconds") - ] = None - file_size_bytes: Annotated[ - Optional[int], Field(description="File size in bytes") - ] = None - format: Annotated[ - Optional[str], Field(description="File format (e.g., 'jpg', 'mp4', 'mp3')") - ] = None - metadata: Annotated[ - Optional[dict[str, Any]], - Field(description="Additional asset-specific metadata"), - ] = None - - -class ProductCatalog10(BaseModel): - model_config = ConfigDict( - extra="forbid", - ) - feed_url: Annotated[AnyUrl, Field(description="URL to product catalog feed")] - feed_format: Annotated[ - Optional[FeedFormat], Field(description="Format of the product feed") - ] = "google_merchant_center" - categories: Annotated[ - Optional[list[str]], - Field( - description="Product categories available in the catalog (for filtering)" - ), - ] = None - last_updated: Annotated[ - Optional[AwareDatetime], - Field(description="When the product catalog was last updated"), - ] = None - update_frequency: Annotated[ - Optional[UpdateFrequency], - Field(description="How frequently the product catalog is updated"), - ] = None - - -class BrandManifest9(BaseModel): - model_config = ConfigDict( - extra="forbid", - ) - url: Annotated[ - AnyUrl, - Field( - description="Primary brand URL for context and asset discovery. Creative agents can infer brand information from this URL." - ), - ] - name: Annotated[Optional[str], Field(description="Brand or business name")] = None - logos: Annotated[ - Optional[list[Logo]], - Field( - description="Brand logo assets with semantic tags for different use cases" - ), - ] = None - colors: Annotated[Optional[Colors], Field(description="Brand color palette")] = None - fonts: Annotated[ - Optional[Fonts], Field(description="Brand typography guidelines") - ] = None - tone: Annotated[ - Optional[str], - Field( - description="Brand voice and messaging tone (e.g., 'professional', 'casual', 'humorous', 'trustworthy', 'innovative')" - ), - ] = None - tagline: Annotated[Optional[str], Field(description="Brand tagline or slogan")] = ( - None - ) - assets: Annotated[ - Optional[list[Asset13]], - Field( - description="Brand asset library with explicit assets and tags. Assets are referenced inline with URLs pointing to CDN-hosted files." - ), - ] = None - product_catalog: Annotated[ - Optional[ProductCatalog10], - Field( - description="Product catalog information for e-commerce advertisers. Enables SKU-level creative generation and product selection." - ), - ] = None - disclaimers: Annotated[ - Optional[list[Disclaimer]], - Field( - description="Legal disclaimers or required text that must appear in creatives" - ), - ] = None - industry: Annotated[ - Optional[str], - Field( - description="Industry or vertical (e.g., 'retail', 'automotive', 'finance', 'healthcare')" - ), - ] = None - target_audience: Annotated[ - Optional[str], Field(description="Primary target audience description") - ] = None - contact: Annotated[ - Optional[Contact], Field(description="Brand contact information") - ] = None - metadata: Annotated[ - Optional[Metadata], Field(description="Additional brand metadata") - ] = None - - -class Asset14(BaseModel): - model_config = ConfigDict( - extra="forbid", - ) - asset_id: Annotated[str, Field(description="Unique identifier for this asset")] - asset_type: Annotated[AssetType, Field(description="Type of asset")] - url: Annotated[AnyUrl, Field(description="URL to CDN-hosted asset file")] - tags: Annotated[ - Optional[list[str]], - Field( - description="Tags for asset discovery (e.g., 'holiday', 'lifestyle', 'product_shot')" - ), - ] = None - name: Annotated[Optional[str], Field(description="Human-readable asset name")] = ( - None - ) - description: Annotated[ - Optional[str], Field(description="Asset description or usage notes") - ] = None - width: Annotated[ - Optional[int], Field(description="Image/video width in pixels") - ] = None - height: Annotated[ - Optional[int], Field(description="Image/video height in pixels") - ] = None - duration_seconds: Annotated[ - Optional[float], Field(description="Video/audio duration in seconds") - ] = None - file_size_bytes: Annotated[ - Optional[int], Field(description="File size in bytes") - ] = None - format: Annotated[ - Optional[str], Field(description="File format (e.g., 'jpg', 'mp4', 'mp3')") - ] = None - metadata: Annotated[ - Optional[dict[str, Any]], - Field(description="Additional asset-specific metadata"), - ] = None - - -class ProductCatalog11(BaseModel): - model_config = ConfigDict( - extra="forbid", - ) - feed_url: Annotated[AnyUrl, Field(description="URL to product catalog feed")] - feed_format: Annotated[ - Optional[FeedFormat], Field(description="Format of the product feed") - ] = "google_merchant_center" - categories: Annotated[ - Optional[list[str]], - Field( - description="Product categories available in the catalog (for filtering)" - ), - ] = None - last_updated: Annotated[ - Optional[AwareDatetime], - Field(description="When the product catalog was last updated"), - ] = None - update_frequency: Annotated[ - Optional[UpdateFrequency], - Field(description="How frequently the product catalog is updated"), - ] = None - - -class BrandManifest10(BaseModel): - model_config = ConfigDict( - extra="forbid", - ) - url: Annotated[ - Optional[AnyUrl], - Field( - description="Primary brand URL for context and asset discovery. Creative agents can infer brand information from this URL." - ), - ] = None - name: Annotated[str, Field(description="Brand or business name")] - logos: Annotated[ - Optional[list[Logo]], - Field( - description="Brand logo assets with semantic tags for different use cases" - ), - ] = None - colors: Annotated[Optional[Colors], Field(description="Brand color palette")] = None - fonts: Annotated[ - Optional[Fonts], Field(description="Brand typography guidelines") - ] = None - tone: Annotated[ - Optional[str], - Field( - description="Brand voice and messaging tone (e.g., 'professional', 'casual', 'humorous', 'trustworthy', 'innovative')" - ), - ] = None - tagline: Annotated[Optional[str], Field(description="Brand tagline or slogan")] = ( - None - ) - assets: Annotated[ - Optional[list[Asset14]], - Field( - description="Brand asset library with explicit assets and tags. Assets are referenced inline with URLs pointing to CDN-hosted files." - ), - ] = None - product_catalog: Annotated[ - Optional[ProductCatalog11], - Field( - description="Product catalog information for e-commerce advertisers. Enables SKU-level creative generation and product selection." - ), - ] = None - disclaimers: Annotated[ - Optional[list[Disclaimer]], - Field( - description="Legal disclaimers or required text that must appear in creatives" - ), - ] = None - industry: Annotated[ - Optional[str], - Field( - description="Industry or vertical (e.g., 'retail', 'automotive', 'finance', 'healthcare')" - ), - ] = None - target_audience: Annotated[ - Optional[str], Field(description="Primary target audience description") - ] = None - contact: Annotated[ - Optional[Contact], Field(description="Brand contact information") - ] = None - metadata: Annotated[ - Optional[Metadata], Field(description="Additional brand metadata") - ] = None - - -class Filters1(BaseModel): - model_config = ConfigDict( - extra="forbid", - ) - delivery_type: Annotated[ - Optional[DeliveryType], - Field(description="Type of inventory delivery", title="Delivery Type"), - ] = None - is_fixed_price: Annotated[ - Optional[bool], Field(description="Filter for fixed price vs auction products") - ] = None - format_types: Annotated[ - Optional[list[FormatType]], Field(description="Filter by format types") - ] = None - format_ids: Annotated[ - Optional[list[str]], Field(description="Filter by specific format IDs") - ] = None - standard_formats_only: Annotated[ - Optional[bool], - Field(description="Only return products accepting IAB standard formats"), - ] = None - min_exposures: Annotated[ - Optional[int], - Field( - description="Minimum exposures/impressions needed for measurement validity", - ge=1, - ), - ] = None - - -class GetProductsRequest2(BaseModel): - model_config = ConfigDict( - extra="forbid", - ) - adcp_version: Annotated[ - Optional[str], - Field( - description="AdCP schema version for this request", - pattern="^\\d+\\.\\d+\\.\\d+$", - ), - ] = "1.6.0" - brief: Annotated[ - Optional[str], - Field(description="Natural language description of campaign requirements"), - ] = None - promoted_offering: Annotated[ - Optional[str], - Field( - description="DEPRECATED: Use brand_manifest instead. Legacy field for describing what is being promoted." - ), - ] = None - brand_manifest: Annotated[ - Union[Union[BrandManifest9, BrandManifest10], AnyUrl], - Field( - description="Brand manifest provided either as an inline object or a URL string pointing to a hosted manifest", - examples=[ - { - "description": "Inline brand manifest", - "data": { - "url": "https://acmecorp.com", - "name": "ACME Corporation", - "colors": {"primary": "#FF6B35"}, - }, - }, - { - "description": "URL string reference to hosted manifest", - "data": "https://cdn.acmecorp.com/brand-manifest.json", - }, - ], - title="Brand Manifest Reference", - ), - ] - filters: Annotated[ - Optional[Filters1], - Field(description="Structured filters for product discovery"), - ] = None - - -class GetProductsRequest(RootModel[Union[GetProductsRequest1, GetProductsRequest2]]): - root: Annotated[ - Union[GetProductsRequest1, GetProductsRequest2], - Field( - description="Request parameters for discovering available advertising products", - title="Get Products Request", - ), - ] diff --git a/src/creative_agent/schemas_generated/_schemas_v1_media_buy_get_products_response_json.py b/src/creative_agent/schemas_generated/_schemas_v1_media_buy_get_products_response_json.py deleted file mode 100644 index 4aabbbf..0000000 --- a/src/creative_agent/schemas_generated/_schemas_v1_media_buy_get_products_response_json.py +++ /dev/null @@ -1,1270 +0,0 @@ -# generated by datamodel-codegen: -# filename: _schemas_v1_media-buy_get-products-response_json.json - -from __future__ import annotations - -from enum import Enum -from typing import Annotated, Any, Literal, Optional, Union - -from pydantic import AwareDatetime, BaseModel, ConfigDict, Field, RootModel - - -class Status(Enum): - submitted = "submitted" - working = "working" - input_required = "input-required" - completed = "completed" - canceled = "canceled" - failed = "failed" - rejected = "rejected" - auth_required = "auth-required" - unknown = "unknown" - - -class PropertyType(Enum): - website = "website" - mobile_app = "mobile_app" - ctv_app = "ctv_app" - dooh = "dooh" - podcast = "podcast" - radio = "radio" - streaming_audio = "streaming_audio" - - -class Identifier(BaseModel): - model_config = ConfigDict( - extra="forbid", - ) - type: Annotated[ - str, - Field( - description="Type of identifier (e.g., 'domain', 'bundle_id', 'roku_store_id', 'podcast_guid')" - ), - ] - value: Annotated[ - str, - Field( - description="The identifier value. For domain type: 'example.com' matches www.example.com and m.example.com only; 'subdomain.example.com' matches that specific subdomain; '*.example.com' matches all subdomains" - ), - ] - - -class Tag(RootModel[str]): - root: Annotated[ - str, - Field( - description="Lowercase tag with underscores (e.g., 'conde_nast_network', 'premium_content')", - pattern="^[a-z0-9_]+$", - ), - ] - - -class Property(BaseModel): - model_config = ConfigDict( - extra="forbid", - ) - property_type: Annotated[ - PropertyType, Field(description="Type of advertising property") - ] - name: Annotated[str, Field(description="Human-readable property name")] - identifiers: Annotated[ - list[Identifier], - Field(description="Array of identifiers for this property", min_length=1), - ] - tags: Annotated[ - Optional[list[Tag]], - Field( - description="Tags for categorization and grouping (e.g., network membership, content categories)" - ), - ] = None - publisher_domain: Annotated[ - str, - Field( - description="Domain where adagents.json should be checked for authorization validation" - ), - ] - - -class PropertyTag(RootModel[str]): - root: Annotated[ - str, - Field( - description="Lowercase tag with underscores (e.g., 'local_radio', 'premium_content')", - pattern="^[a-z0-9_]+$", - ), - ] - - -class DeliveryType(Enum): - guaranteed = "guaranteed" - non_guaranteed = "non_guaranteed" - - -class PricingOptions(BaseModel): - model_config = ConfigDict( - extra="forbid", - ) - pricing_option_id: Annotated[ - str, - Field( - description="Unique identifier for this pricing option within the product (e.g., 'cpm_usd_guaranteed')" - ), - ] - pricing_model: Annotated[ - Literal["cpm"], Field(description="Cost per 1,000 impressions") - ] - rate: Annotated[ - float, Field(description="Fixed CPM rate (cost per 1,000 impressions)", ge=0.0) - ] - currency: Annotated[ - str, - Field( - description="ISO 4217 currency code", - examples=["USD", "EUR", "GBP", "JPY"], - pattern="^[A-Z]{3}$", - ), - ] - min_spend_per_package: Annotated[ - Optional[float], - Field( - description="Minimum spend requirement per package using this pricing option, in the specified currency", - ge=0.0, - ), - ] = None - - -class PriceGuidance(BaseModel): - floor: Annotated[ - float, - Field( - description="Minimum bid price - publisher will reject bids under this value", - ge=0.0, - ), - ] - p25: Annotated[ - Optional[float], Field(description="25th percentile winning price", ge=0.0) - ] = None - p50: Annotated[ - Optional[float], Field(description="Median winning price", ge=0.0) - ] = None - p75: Annotated[ - Optional[float], Field(description="75th percentile winning price", ge=0.0) - ] = None - p90: Annotated[ - Optional[float], Field(description="90th percentile winning price", ge=0.0) - ] = None - - -class PricingOptions15(BaseModel): - model_config = ConfigDict( - extra="forbid", - ) - pricing_option_id: Annotated[ - str, - Field( - description="Unique identifier for this pricing option within the product (e.g., 'cpm_usd_auction')" - ), - ] - pricing_model: Annotated[ - Literal["cpm"], Field(description="Cost per 1,000 impressions") - ] - currency: Annotated[ - str, - Field( - description="ISO 4217 currency code", - examples=["USD", "EUR", "GBP", "JPY"], - pattern="^[A-Z]{3}$", - ), - ] - price_guidance: Annotated[ - PriceGuidance, - Field(description="Pricing guidance for auction-based CPM bidding"), - ] - min_spend_per_package: Annotated[ - Optional[float], - Field( - description="Minimum spend requirement per package using this pricing option, in the specified currency", - ge=0.0, - ), - ] = None - - -class PricingOptions16(BaseModel): - model_config = ConfigDict( - extra="forbid", - ) - pricing_option_id: Annotated[ - str, - Field( - description="Unique identifier for this pricing option within the product (e.g., 'cpc_usd_fixed')" - ), - ] - pricing_model: Annotated[Literal["cpc"], Field(description="Cost per click")] - rate: Annotated[float, Field(description="Fixed CPC rate (cost per click)", ge=0.0)] - currency: Annotated[ - str, - Field( - description="ISO 4217 currency code", - examples=["USD", "EUR", "GBP", "JPY"], - pattern="^[A-Z]{3}$", - ), - ] - min_spend_per_package: Annotated[ - Optional[float], - Field( - description="Minimum spend requirement per package using this pricing option, in the specified currency", - ge=0.0, - ), - ] = None - - -class PricingOptions17(BaseModel): - model_config = ConfigDict( - extra="forbid", - ) - pricing_option_id: Annotated[ - str, - Field( - description="Unique identifier for this pricing option within the product (e.g., 'cpcv_usd_guaranteed')" - ), - ] - pricing_model: Annotated[ - Literal["cpcv"], Field(description="Cost per completed view (100% completion)") - ] - rate: Annotated[ - float, Field(description="Fixed CPCV rate (cost per 100% completion)", ge=0.0) - ] - currency: Annotated[ - str, - Field( - description="ISO 4217 currency code", - examples=["USD", "EUR", "GBP", "JPY"], - pattern="^[A-Z]{3}$", - ), - ] - min_spend_per_package: Annotated[ - Optional[float], - Field( - description="Minimum spend requirement per package using this pricing option, in the specified currency", - ge=0.0, - ), - ] = None - - -class ViewThreshold(RootModel[float]): - root: Annotated[ - float, - Field( - description="Percentage completion threshold for CPV pricing (0.0 to 1.0, e.g., 0.5 = 50% completion)", - ge=0.0, - le=1.0, - ), - ] - - -class ViewThreshold7(BaseModel): - model_config = ConfigDict( - extra="forbid", - ) - duration_seconds: Annotated[ - int, - Field( - description="Seconds of viewing required (e.g., 30 for YouTube-style '30 seconds = view')", - ge=1, - ), - ] - - -class Parameters(BaseModel): - model_config = ConfigDict( - extra="forbid", - ) - view_threshold: Union[ViewThreshold, ViewThreshold7] - - -class PricingOptions18(BaseModel): - model_config = ConfigDict( - extra="forbid", - ) - pricing_option_id: Annotated[ - str, - Field( - description="Unique identifier for this pricing option within the product (e.g., 'cpv_usd_50pct')" - ), - ] - pricing_model: Annotated[ - Literal["cpv"], Field(description="Cost per view at threshold") - ] - rate: Annotated[float, Field(description="Fixed CPV rate (cost per view)", ge=0.0)] - currency: Annotated[ - str, - Field( - description="ISO 4217 currency code", - examples=["USD", "EUR", "GBP", "JPY"], - pattern="^[A-Z]{3}$", - ), - ] - parameters: Annotated[ - Parameters, - Field(description="CPV-specific parameters defining the view threshold"), - ] - min_spend_per_package: Annotated[ - Optional[float], - Field( - description="Minimum spend requirement per package using this pricing option, in the specified currency", - ge=0.0, - ), - ] = None - - -class Parameters10(BaseModel): - model_config = ConfigDict( - extra="forbid", - ) - demographic: Annotated[ - str, - Field( - description="Target demographic in Nielsen format: P/M/W/A/C + age range. Examples: P18-49 (Persons 18-49), M25-54 (Men 25-54), W35+ (Women 35+), A18-34 (Adults 18-34), C2-11 (Children 2-11)", - pattern="^[PMWAC][0-9]{2}(-[0-9]{2}|\\+)$", - ), - ] - min_points: Annotated[ - Optional[float], - Field(description="Minimum GRPs/TRPs required for this pricing option", ge=0.0), - ] = None - - -class PricingOptions19(BaseModel): - model_config = ConfigDict( - extra="forbid", - ) - pricing_option_id: Annotated[ - str, - Field( - description="Unique identifier for this pricing option within the product (e.g., 'cpp_usd_p18-49')" - ), - ] - pricing_model: Annotated[ - Literal["cpp"], Field(description="Cost per Gross Rating Point") - ] - rate: Annotated[ - float, Field(description="Fixed CPP rate (cost per rating point)", ge=0.0) - ] - currency: Annotated[ - str, - Field( - description="ISO 4217 currency code", - examples=["USD", "EUR", "GBP", "JPY"], - pattern="^[A-Z]{3}$", - ), - ] - parameters: Annotated[ - Parameters10, - Field( - description="CPP-specific parameters for demographic targeting and GRP requirements" - ), - ] - min_spend_per_package: Annotated[ - Optional[float], - Field( - description="Minimum spend requirement per package using this pricing option, in the specified currency", - ge=0.0, - ), - ] = None - - -class Parameters11(BaseModel): - model_config = ConfigDict( - extra="forbid", - ) - duration_hours: Annotated[ - Optional[float], - Field( - description="Duration in hours for time-based flat rate pricing (DOOH)", - ge=0.0, - ), - ] = None - sov_percentage: Annotated[ - Optional[float], - Field( - description="Guaranteed share of voice as percentage (DOOH, 0-100)", - ge=0.0, - le=100.0, - ), - ] = None - loop_duration_seconds: Annotated[ - Optional[int], - Field(description="Duration of ad loop rotation in seconds (DOOH)", ge=1), - ] = None - min_plays_per_hour: Annotated[ - Optional[int], - Field( - description="Minimum number of times ad plays per hour (DOOH frequency guarantee)", - ge=0, - ), - ] = None - venue_package: Annotated[ - Optional[str], - Field( - description="Named venue package identifier for DOOH (e.g., 'times_square_network', 'airport_terminals')" - ), - ] = None - estimated_impressions: Annotated[ - Optional[int], - Field( - description="Estimated impressions for this flat rate option (informational, commonly used with SOV or time-based DOOH)", - ge=0, - ), - ] = None - daypart: Annotated[ - Optional[str], - Field( - description="Specific daypart for time-based pricing (e.g., 'morning_commute', 'evening_prime', 'overnight')" - ), - ] = None - - -class PricingOptions20(BaseModel): - model_config = ConfigDict( - extra="forbid", - ) - pricing_option_id: Annotated[ - str, - Field( - description="Unique identifier for this pricing option within the product (e.g., 'flat_rate_usd_24h_takeover')" - ), - ] - pricing_model: Annotated[ - Literal["flat_rate"], - Field(description="Fixed cost regardless of delivery volume"), - ] - rate: Annotated[float, Field(description="Flat rate cost", ge=0.0)] - currency: Annotated[ - str, - Field( - description="ISO 4217 currency code", - examples=["USD", "EUR", "GBP", "JPY"], - pattern="^[A-Z]{3}$", - ), - ] - is_fixed: Annotated[ - Literal[True], - Field( - description="Whether this is a fixed rate (true) or auction-based (false)" - ), - ] - parameters: Annotated[ - Optional[Parameters11], - Field(description="Flat rate parameters for DOOH and time-based campaigns"), - ] = None - min_spend_per_package: Annotated[ - Optional[float], - Field( - description="Minimum spend requirement per package using this pricing option, in the specified currency", - ge=0.0, - ), - ] = None - - -class Measurement(BaseModel): - model_config = ConfigDict( - extra="forbid", - ) - type: Annotated[ - str, - Field( - description="Type of measurement", - examples=["incremental_sales_lift", "brand_lift", "foot_traffic"], - ), - ] - attribution: Annotated[ - str, - Field( - description="Attribution methodology", - examples=["deterministic_purchase", "probabilistic"], - ), - ] - window: Annotated[ - Optional[str], - Field(description="Attribution window", examples=["30_days", "7_days"]), - ] = None - reporting: Annotated[ - str, - Field( - description="Reporting frequency and format", - examples=["weekly_dashboard", "real_time_api"], - ), - ] - - -class DeliveryMeasurement(BaseModel): - provider: Annotated[ - str, - Field( - description="Measurement provider(s) used for this product (e.g., 'Google Ad Manager with IAS viewability', 'Nielsen DAR', 'Geopath for DOOH impressions')" - ), - ] - notes: Annotated[ - Optional[str], - Field( - description="Additional details about measurement methodology in plain language (e.g., 'MRC-accredited viewability. 50% in-view for 1s display / 2s video', 'Panel-based demographic measurement updated monthly')" - ), - ] = None - - -class AvailableReportingFrequency(Enum): - hourly = "hourly" - daily = "daily" - monthly = "monthly" - - -class AvailableMetric(Enum): - impressions = "impressions" - spend = "spend" - clicks = "clicks" - ctr = "ctr" - video_completions = "video_completions" - completion_rate = "completion_rate" - conversions = "conversions" - viewability = "viewability" - engagement_rate = "engagement_rate" - - -class ReportingCapabilities(BaseModel): - model_config = ConfigDict( - extra="forbid", - ) - available_reporting_frequencies: Annotated[ - list[AvailableReportingFrequency], - Field(description="Supported reporting frequency options", min_length=1), - ] - expected_delay_minutes: Annotated[ - int, - Field( - description="Expected delay in minutes before reporting data becomes available (e.g., 240 for 4-hour delay)", - examples=[240, 300, 1440], - ge=0, - ), - ] - timezone: Annotated[ - str, - Field( - description="Timezone for reporting periods. Use 'UTC' or IANA timezone (e.g., 'America/New_York'). Critical for daily/monthly frequency alignment.", - examples=[ - "UTC", - "America/New_York", - "Europe/London", - "America/Los_Angeles", - ], - ), - ] - supports_webhooks: Annotated[ - bool, - Field( - description="Whether this product supports webhook-based reporting notifications" - ), - ] - available_metrics: Annotated[ - list[AvailableMetric], - Field( - description="Metrics available in reporting. Impressions and spend are always implicitly included.", - examples=[ - ["impressions", "spend", "clicks", "video_completions"], - ["impressions", "spend", "conversions"], - ], - ), - ] - - -class CoBranding(Enum): - required = "required" - optional = "optional" - none = "none" - - -class LandingPage(Enum): - any = "any" - retailer_site_only = "retailer_site_only" - must_include_retailer = "must_include_retailer" - - -class CreativePolicy(BaseModel): - model_config = ConfigDict( - extra="forbid", - ) - co_branding: Annotated[CoBranding, Field(description="Co-branding requirement")] - landing_page: Annotated[LandingPage, Field(description="Landing page requirements")] - templates_available: Annotated[ - bool, Field(description="Whether creative templates are provided") - ] - - -class Products(BaseModel): - model_config = ConfigDict( - extra="forbid", - ) - product_id: Annotated[str, Field(description="Unique identifier for the product")] - name: Annotated[str, Field(description="Human-readable product name")] - description: Annotated[ - str, Field(description="Detailed description of the product and its inventory") - ] - properties: Annotated[ - list[Property], - Field( - description="Array of advertising properties covered by this product for adagents.json validation", - min_length=1, - ), - ] - property_tags: Annotated[ - Optional[list[PropertyTag]], - Field( - description="Tags identifying groups of properties covered by this product (use list_authorized_properties to get full property details)", - min_length=1, - ), - ] = None - format_ids: Annotated[ - list[str], - Field( - description="Array of supported creative format IDs - use list_creative_formats to get full format details" - ), - ] - delivery_type: Annotated[ - DeliveryType, - Field(description="Type of inventory delivery", title="Delivery Type"), - ] - pricing_options: Annotated[ - list[ - Union[ - PricingOptions, - PricingOptions15, - PricingOptions16, - PricingOptions17, - PricingOptions18, - PricingOptions19, - PricingOptions20, - ] - ], - Field(description="Available pricing models for this product", min_length=1), - ] - estimated_exposures: Annotated[ - Optional[int], - Field( - description="Estimated exposures/impressions for guaranteed products", ge=0 - ), - ] = None - measurement: Annotated[ - Optional[Measurement], - Field( - description="Measurement capabilities included with a product", - title="Measurement", - ), - ] = None - delivery_measurement: Annotated[ - DeliveryMeasurement, - Field( - description="Measurement provider and methodology for delivery metrics. The buyer accepts the declared provider as the source of truth for the buy. REQUIRED for all products." - ), - ] - reporting_capabilities: Annotated[ - Optional[ReportingCapabilities], - Field( - description="Reporting capabilities available for a product", - title="Reporting Capabilities", - ), - ] = None - creative_policy: Annotated[ - Optional[CreativePolicy], - Field( - description="Creative requirements and restrictions for a product", - title="Creative Policy", - ), - ] = None - is_custom: Annotated[ - Optional[bool], Field(description="Whether this is a custom product") - ] = None - brief_relevance: Annotated[ - Optional[str], - Field( - description="Explanation of why this product matches the brief (only included when brief is provided)" - ), - ] = None - expires_at: Annotated[ - Optional[AwareDatetime], - Field(description="Expiration timestamp for custom products"), - ] = None - - -class Property3(BaseModel): - model_config = ConfigDict( - extra="forbid", - ) - property_type: Annotated[ - PropertyType, Field(description="Type of advertising property") - ] - name: Annotated[str, Field(description="Human-readable property name")] - identifiers: Annotated[ - list[Identifier], - Field(description="Array of identifiers for this property", min_length=1), - ] - tags: Annotated[ - Optional[list[Tag]], - Field( - description="Tags for categorization and grouping (e.g., network membership, content categories)" - ), - ] = None - publisher_domain: Annotated[ - str, - Field( - description="Domain where adagents.json should be checked for authorization validation" - ), - ] - - -class PricingOptions21(BaseModel): - model_config = ConfigDict( - extra="forbid", - ) - pricing_option_id: Annotated[ - str, - Field( - description="Unique identifier for this pricing option within the product (e.g., 'cpm_usd_guaranteed')" - ), - ] - pricing_model: Annotated[ - Literal["cpm"], Field(description="Cost per 1,000 impressions") - ] - rate: Annotated[ - float, Field(description="Fixed CPM rate (cost per 1,000 impressions)", ge=0.0) - ] - currency: Annotated[ - str, - Field( - description="ISO 4217 currency code", - examples=["USD", "EUR", "GBP", "JPY"], - pattern="^[A-Z]{3}$", - ), - ] - min_spend_per_package: Annotated[ - Optional[float], - Field( - description="Minimum spend requirement per package using this pricing option, in the specified currency", - ge=0.0, - ), - ] = None - - -class PricingOptions22(BaseModel): - model_config = ConfigDict( - extra="forbid", - ) - pricing_option_id: Annotated[ - str, - Field( - description="Unique identifier for this pricing option within the product (e.g., 'cpm_usd_auction')" - ), - ] - pricing_model: Annotated[ - Literal["cpm"], Field(description="Cost per 1,000 impressions") - ] - currency: Annotated[ - str, - Field( - description="ISO 4217 currency code", - examples=["USD", "EUR", "GBP", "JPY"], - pattern="^[A-Z]{3}$", - ), - ] - price_guidance: Annotated[ - PriceGuidance, - Field(description="Pricing guidance for auction-based CPM bidding"), - ] - min_spend_per_package: Annotated[ - Optional[float], - Field( - description="Minimum spend requirement per package using this pricing option, in the specified currency", - ge=0.0, - ), - ] = None - - -class PricingOptions23(BaseModel): - model_config = ConfigDict( - extra="forbid", - ) - pricing_option_id: Annotated[ - str, - Field( - description="Unique identifier for this pricing option within the product (e.g., 'cpc_usd_fixed')" - ), - ] - pricing_model: Annotated[Literal["cpc"], Field(description="Cost per click")] - rate: Annotated[float, Field(description="Fixed CPC rate (cost per click)", ge=0.0)] - currency: Annotated[ - str, - Field( - description="ISO 4217 currency code", - examples=["USD", "EUR", "GBP", "JPY"], - pattern="^[A-Z]{3}$", - ), - ] - min_spend_per_package: Annotated[ - Optional[float], - Field( - description="Minimum spend requirement per package using this pricing option, in the specified currency", - ge=0.0, - ), - ] = None - - -class PricingOptions24(BaseModel): - model_config = ConfigDict( - extra="forbid", - ) - pricing_option_id: Annotated[ - str, - Field( - description="Unique identifier for this pricing option within the product (e.g., 'cpcv_usd_guaranteed')" - ), - ] - pricing_model: Annotated[ - Literal["cpcv"], Field(description="Cost per completed view (100% completion)") - ] - rate: Annotated[ - float, Field(description="Fixed CPCV rate (cost per 100% completion)", ge=0.0) - ] - currency: Annotated[ - str, - Field( - description="ISO 4217 currency code", - examples=["USD", "EUR", "GBP", "JPY"], - pattern="^[A-Z]{3}$", - ), - ] - min_spend_per_package: Annotated[ - Optional[float], - Field( - description="Minimum spend requirement per package using this pricing option, in the specified currency", - ge=0.0, - ), - ] = None - - -class ViewThreshold8(RootModel[float]): - root: Annotated[ - float, - Field( - description="Percentage completion threshold for CPV pricing (0.0 to 1.0, e.g., 0.5 = 50% completion)", - ge=0.0, - le=1.0, - ), - ] - - -class ViewThreshold9(BaseModel): - model_config = ConfigDict( - extra="forbid", - ) - duration_seconds: Annotated[ - int, - Field( - description="Seconds of viewing required (e.g., 30 for YouTube-style '30 seconds = view')", - ge=1, - ), - ] - - -class Parameters12(BaseModel): - model_config = ConfigDict( - extra="forbid", - ) - view_threshold: Union[ViewThreshold8, ViewThreshold9] - - -class PricingOptions25(BaseModel): - model_config = ConfigDict( - extra="forbid", - ) - pricing_option_id: Annotated[ - str, - Field( - description="Unique identifier for this pricing option within the product (e.g., 'cpv_usd_50pct')" - ), - ] - pricing_model: Annotated[ - Literal["cpv"], Field(description="Cost per view at threshold") - ] - rate: Annotated[float, Field(description="Fixed CPV rate (cost per view)", ge=0.0)] - currency: Annotated[ - str, - Field( - description="ISO 4217 currency code", - examples=["USD", "EUR", "GBP", "JPY"], - pattern="^[A-Z]{3}$", - ), - ] - parameters: Annotated[ - Parameters12, - Field(description="CPV-specific parameters defining the view threshold"), - ] - min_spend_per_package: Annotated[ - Optional[float], - Field( - description="Minimum spend requirement per package using this pricing option, in the specified currency", - ge=0.0, - ), - ] = None - - -class Parameters13(BaseModel): - model_config = ConfigDict( - extra="forbid", - ) - demographic: Annotated[ - str, - Field( - description="Target demographic in Nielsen format: P/M/W/A/C + age range. Examples: P18-49 (Persons 18-49), M25-54 (Men 25-54), W35+ (Women 35+), A18-34 (Adults 18-34), C2-11 (Children 2-11)", - pattern="^[PMWAC][0-9]{2}(-[0-9]{2}|\\+)$", - ), - ] - min_points: Annotated[ - Optional[float], - Field(description="Minimum GRPs/TRPs required for this pricing option", ge=0.0), - ] = None - - -class PricingOptions26(BaseModel): - model_config = ConfigDict( - extra="forbid", - ) - pricing_option_id: Annotated[ - str, - Field( - description="Unique identifier for this pricing option within the product (e.g., 'cpp_usd_p18-49')" - ), - ] - pricing_model: Annotated[ - Literal["cpp"], Field(description="Cost per Gross Rating Point") - ] - rate: Annotated[ - float, Field(description="Fixed CPP rate (cost per rating point)", ge=0.0) - ] - currency: Annotated[ - str, - Field( - description="ISO 4217 currency code", - examples=["USD", "EUR", "GBP", "JPY"], - pattern="^[A-Z]{3}$", - ), - ] - parameters: Annotated[ - Parameters13, - Field( - description="CPP-specific parameters for demographic targeting and GRP requirements" - ), - ] - min_spend_per_package: Annotated[ - Optional[float], - Field( - description="Minimum spend requirement per package using this pricing option, in the specified currency", - ge=0.0, - ), - ] = None - - -class Parameters14(BaseModel): - model_config = ConfigDict( - extra="forbid", - ) - duration_hours: Annotated[ - Optional[float], - Field( - description="Duration in hours for time-based flat rate pricing (DOOH)", - ge=0.0, - ), - ] = None - sov_percentage: Annotated[ - Optional[float], - Field( - description="Guaranteed share of voice as percentage (DOOH, 0-100)", - ge=0.0, - le=100.0, - ), - ] = None - loop_duration_seconds: Annotated[ - Optional[int], - Field(description="Duration of ad loop rotation in seconds (DOOH)", ge=1), - ] = None - min_plays_per_hour: Annotated[ - Optional[int], - Field( - description="Minimum number of times ad plays per hour (DOOH frequency guarantee)", - ge=0, - ), - ] = None - venue_package: Annotated[ - Optional[str], - Field( - description="Named venue package identifier for DOOH (e.g., 'times_square_network', 'airport_terminals')" - ), - ] = None - estimated_impressions: Annotated[ - Optional[int], - Field( - description="Estimated impressions for this flat rate option (informational, commonly used with SOV or time-based DOOH)", - ge=0, - ), - ] = None - daypart: Annotated[ - Optional[str], - Field( - description="Specific daypart for time-based pricing (e.g., 'morning_commute', 'evening_prime', 'overnight')" - ), - ] = None - - -class PricingOptions27(BaseModel): - model_config = ConfigDict( - extra="forbid", - ) - pricing_option_id: Annotated[ - str, - Field( - description="Unique identifier for this pricing option within the product (e.g., 'flat_rate_usd_24h_takeover')" - ), - ] - pricing_model: Annotated[ - Literal["flat_rate"], - Field(description="Fixed cost regardless of delivery volume"), - ] - rate: Annotated[float, Field(description="Flat rate cost", ge=0.0)] - currency: Annotated[ - str, - Field( - description="ISO 4217 currency code", - examples=["USD", "EUR", "GBP", "JPY"], - pattern="^[A-Z]{3}$", - ), - ] - is_fixed: Annotated[ - Literal[True], - Field( - description="Whether this is a fixed rate (true) or auction-based (false)" - ), - ] - parameters: Annotated[ - Optional[Parameters14], - Field(description="Flat rate parameters for DOOH and time-based campaigns"), - ] = None - min_spend_per_package: Annotated[ - Optional[float], - Field( - description="Minimum spend requirement per package using this pricing option, in the specified currency", - ge=0.0, - ), - ] = None - - -class ReportingCapabilities3(BaseModel): - model_config = ConfigDict( - extra="forbid", - ) - available_reporting_frequencies: Annotated[ - list[AvailableReportingFrequency], - Field(description="Supported reporting frequency options", min_length=1), - ] - expected_delay_minutes: Annotated[ - int, - Field( - description="Expected delay in minutes before reporting data becomes available (e.g., 240 for 4-hour delay)", - examples=[240, 300, 1440], - ge=0, - ), - ] - timezone: Annotated[ - str, - Field( - description="Timezone for reporting periods. Use 'UTC' or IANA timezone (e.g., 'America/New_York'). Critical for daily/monthly frequency alignment.", - examples=[ - "UTC", - "America/New_York", - "Europe/London", - "America/Los_Angeles", - ], - ), - ] - supports_webhooks: Annotated[ - bool, - Field( - description="Whether this product supports webhook-based reporting notifications" - ), - ] - available_metrics: Annotated[ - list[AvailableMetric], - Field( - description="Metrics available in reporting. Impressions and spend are always implicitly included.", - examples=[ - ["impressions", "spend", "clicks", "video_completions"], - ["impressions", "spend", "conversions"], - ], - ), - ] - - -class CreativePolicy4(BaseModel): - model_config = ConfigDict( - extra="forbid", - ) - co_branding: Annotated[CoBranding, Field(description="Co-branding requirement")] - landing_page: Annotated[LandingPage, Field(description="Landing page requirements")] - templates_available: Annotated[ - bool, Field(description="Whether creative templates are provided") - ] - - -class Products1(BaseModel): - model_config = ConfigDict( - extra="forbid", - ) - product_id: Annotated[str, Field(description="Unique identifier for the product")] - name: Annotated[str, Field(description="Human-readable product name")] - description: Annotated[ - str, Field(description="Detailed description of the product and its inventory") - ] - properties: Annotated[ - Optional[list[Property3]], - Field( - description="Array of advertising properties covered by this product for adagents.json validation", - min_length=1, - ), - ] = None - property_tags: Annotated[ - list[PropertyTag], - Field( - description="Tags identifying groups of properties covered by this product (use list_authorized_properties to get full property details)", - min_length=1, - ), - ] - format_ids: Annotated[ - list[str], - Field( - description="Array of supported creative format IDs - use list_creative_formats to get full format details" - ), - ] - delivery_type: Annotated[ - DeliveryType, - Field(description="Type of inventory delivery", title="Delivery Type"), - ] - pricing_options: Annotated[ - list[ - Union[ - PricingOptions21, - PricingOptions22, - PricingOptions23, - PricingOptions24, - PricingOptions25, - PricingOptions26, - PricingOptions27, - ] - ], - Field(description="Available pricing models for this product", min_length=1), - ] - estimated_exposures: Annotated[ - Optional[int], - Field( - description="Estimated exposures/impressions for guaranteed products", ge=0 - ), - ] = None - measurement: Annotated[ - Optional[Measurement], - Field( - description="Measurement capabilities included with a product", - title="Measurement", - ), - ] = None - delivery_measurement: Annotated[ - DeliveryMeasurement, - Field( - description="Measurement provider and methodology for delivery metrics. The buyer accepts the declared provider as the source of truth for the buy. REQUIRED for all products." - ), - ] - reporting_capabilities: Annotated[ - Optional[ReportingCapabilities3], - Field( - description="Reporting capabilities available for a product", - title="Reporting Capabilities", - ), - ] = None - creative_policy: Annotated[ - Optional[CreativePolicy4], - Field( - description="Creative requirements and restrictions for a product", - title="Creative Policy", - ), - ] = None - is_custom: Annotated[ - Optional[bool], Field(description="Whether this is a custom product") - ] = None - brief_relevance: Annotated[ - Optional[str], - Field( - description="Explanation of why this product matches the brief (only included when brief is provided)" - ), - ] = None - expires_at: Annotated[ - Optional[AwareDatetime], - Field(description="Expiration timestamp for custom products"), - ] = None - - -class Error(BaseModel): - model_config = ConfigDict( - extra="forbid", - ) - code: Annotated[str, Field(description="Error code for programmatic handling")] - message: Annotated[str, Field(description="Human-readable error message")] - field: Annotated[ - Optional[str], - Field( - description="Field path associated with the error (e.g., 'packages[0].targeting')" - ), - ] = None - suggestion: Annotated[ - Optional[str], Field(description="Suggested fix for the error") - ] = None - retry_after: Annotated[ - Optional[float], - Field(description="Seconds to wait before retrying the operation", ge=0.0), - ] = None - details: Annotated[ - Optional[Any], Field(description="Additional task-specific error details") - ] = None - - -class GetProductsResponse(BaseModel): - model_config = ConfigDict( - extra="forbid", - ) - adcp_version: Annotated[ - str, - Field( - description="AdCP schema version used for this response", - pattern="^\\d+\\.\\d+\\.\\d+$", - ), - ] - status: Annotated[ - Optional[Status], - Field( - description="Standardized task status values based on A2A TaskState enum. Indicates the current state of any AdCP operation.", - title="Task Status", - ), - ] = "completed" - products: Annotated[ - list[Union[Products, Products1]], - Field(description="Array of matching products"), - ] - errors: Annotated[ - Optional[list[Error]], - Field( - description="Task-specific errors and warnings (e.g., product filtering issues)" - ), - ] = None diff --git a/src/creative_agent/schemas_generated/_schemas_v1_media_buy_list_authorized_properties_request_json.py b/src/creative_agent/schemas_generated/_schemas_v1_media_buy_list_authorized_properties_request_json.py deleted file mode 100644 index 43d4d14..0000000 --- a/src/creative_agent/schemas_generated/_schemas_v1_media_buy_list_authorized_properties_request_json.py +++ /dev/null @@ -1,35 +0,0 @@ -# generated by datamodel-codegen: -# filename: _schemas_v1_media-buy_list-authorized-properties-request_json.json - -from __future__ import annotations - -from typing import Annotated, Optional - -from pydantic import BaseModel, ConfigDict, Field, RootModel - - -class Tag(RootModel[str]): - root: Annotated[ - str, - Field( - description="Tag to filter by (e.g., 'local_radio', 'premium_content')", - pattern="^[a-z0-9_]+$", - ), - ] - - -class ListAuthorizedPropertiesRequest(BaseModel): - model_config = ConfigDict( - extra="forbid", - ) - adcp_version: Annotated[ - Optional[str], - Field( - description="AdCP schema version for this request", - pattern="^\\d+\\.\\d+\\.\\d+$", - ), - ] = "1.0.0" - tags: Annotated[ - Optional[list[Tag]], - Field(description="Filter properties by specific tags (optional)"), - ] = None diff --git a/src/creative_agent/schemas_generated/_schemas_v1_media_buy_list_authorized_properties_response_json.py b/src/creative_agent/schemas_generated/_schemas_v1_media_buy_list_authorized_properties_response_json.py deleted file mode 100644 index 049587e..0000000 --- a/src/creative_agent/schemas_generated/_schemas_v1_media_buy_list_authorized_properties_response_json.py +++ /dev/null @@ -1,174 +0,0 @@ -# generated by datamodel-codegen: -# filename: _schemas_v1_media-buy_list-authorized-properties-response_json.json - -from __future__ import annotations - -from enum import Enum -from typing import Annotated, Any, Optional - -from pydantic import BaseModel, ConfigDict, Field, RootModel - - -class PropertyType(Enum): - website = "website" - mobile_app = "mobile_app" - ctv_app = "ctv_app" - dooh = "dooh" - podcast = "podcast" - radio = "radio" - streaming_audio = "streaming_audio" - - -class Identifier(BaseModel): - model_config = ConfigDict( - extra="forbid", - ) - type: Annotated[ - str, - Field( - description="Type of identifier (e.g., 'domain', 'bundle_id', 'roku_store_id', 'podcast_guid')" - ), - ] - value: Annotated[ - str, - Field( - description="The identifier value. For domain type: 'example.com' matches www.example.com and m.example.com only; 'subdomain.example.com' matches that specific subdomain; '*.example.com' matches all subdomains" - ), - ] - - -class Tag(RootModel[str]): - root: Annotated[ - str, - Field( - description="Lowercase tag with underscores (e.g., 'conde_nast_network', 'premium_content')", - pattern="^[a-z0-9_]+$", - ), - ] - - -class Property(BaseModel): - model_config = ConfigDict( - extra="forbid", - ) - property_type: Annotated[ - PropertyType, Field(description="Type of advertising property") - ] - name: Annotated[str, Field(description="Human-readable property name")] - identifiers: Annotated[ - list[Identifier], - Field(description="Array of identifiers for this property", min_length=1), - ] - tags: Annotated[ - Optional[list[Tag]], - Field( - description="Tags for categorization and grouping (e.g., network membership, content categories)" - ), - ] = None - publisher_domain: Annotated[ - str, - Field( - description="Domain where adagents.json should be checked for authorization validation" - ), - ] - - -class Tags(BaseModel): - model_config = ConfigDict( - extra="forbid", - ) - name: Annotated[str, Field(description="Human-readable name for this tag")] - description: Annotated[ - str, Field(description="Description of what this tag represents") - ] - - -class PrimaryChannel(Enum): - display = "display" - video = "video" - audio = "audio" - native = "native" - dooh = "dooh" - ctv = "ctv" - podcast = "podcast" - retail = "retail" - social = "social" - - -class PrimaryCountry(RootModel[str]): - root: Annotated[str, Field(pattern="^[A-Z]{2}$")] - - -class Error(BaseModel): - model_config = ConfigDict( - extra="forbid", - ) - code: Annotated[str, Field(description="Error code for programmatic handling")] - message: Annotated[str, Field(description="Human-readable error message")] - field: Annotated[ - Optional[str], - Field( - description="Field path associated with the error (e.g., 'packages[0].targeting')" - ), - ] = None - suggestion: Annotated[ - Optional[str], Field(description="Suggested fix for the error") - ] = None - retry_after: Annotated[ - Optional[float], - Field(description="Seconds to wait before retrying the operation", ge=0.0), - ] = None - details: Annotated[ - Optional[Any], Field(description="Additional task-specific error details") - ] = None - - -class ListAuthorizedPropertiesResponse(BaseModel): - model_config = ConfigDict( - extra="forbid", - ) - adcp_version: Annotated[ - str, - Field( - description="AdCP schema version used for this response", - pattern="^\\d+\\.\\d+\\.\\d+$", - ), - ] - properties: Annotated[ - list[Property], - Field( - description="Array of all properties this agent is authorized to represent" - ), - ] - tags: Annotated[ - Optional[dict[str, Tags]], - Field(description="Metadata for each tag referenced by properties"), - ] = None - primary_channels: Annotated[ - Optional[list[PrimaryChannel]], - Field( - description="Primary advertising channels represented in this property portfolio. Helps buying agents quickly filter relevance.", - min_length=1, - ), - ] = None - primary_countries: Annotated[ - Optional[list[PrimaryCountry]], - Field( - description="Primary countries (ISO 3166-1 alpha-2 codes) where properties are concentrated. Helps buying agents quickly filter relevance.", - min_length=1, - ), - ] = None - portfolio_description: Annotated[ - Optional[str], - Field( - description="Markdown-formatted description of the property portfolio, including inventory types, audience characteristics, and special features.", - max_length=5000, - min_length=1, - ), - ] = None - errors: Annotated[ - Optional[list[Error]], - Field( - description="Task-specific errors and warnings (e.g., property availability issues)" - ), - ] = None diff --git a/src/creative_agent/schemas_generated/_schemas_v1_media_buy_list_creatives_request_json.py b/src/creative_agent/schemas_generated/_schemas_v1_media_buy_list_creatives_request_json.py deleted file mode 100644 index 032e1da..0000000 --- a/src/creative_agent/schemas_generated/_schemas_v1_media_buy_list_creatives_request_json.py +++ /dev/null @@ -1,231 +0,0 @@ -# generated by datamodel-codegen: -# filename: _schemas_v1_media-buy_list-creatives-request_json.json - -from __future__ import annotations - -from enum import Enum -from typing import Annotated, Any, Optional - -from pydantic import AwareDatetime, BaseModel, ConfigDict, Field - - -class Status(Enum): - processing = "processing" - approved = "approved" - rejected = "rejected" - pending_review = "pending_review" - - -class SnippetType(Enum): - vast_xml = "vast_xml" - vast_url = "vast_url" - html = "html" - javascript = "javascript" - iframe = "iframe" - daast_url = "daast_url" - - -class Filters(BaseModel): - model_config = ConfigDict( - extra="forbid", - ) - format: Annotated[ - Optional[str], - Field( - description="Filter by creative format type (e.g., video, audio, display)" - ), - ] = None - formats: Annotated[ - Optional[list[str]], - Field(description="Filter by multiple creative format types"), - ] = None - status: Annotated[ - Optional[Status], - Field(description="Status of a creative asset", title="Creative Status"), - ] = None - statuses: Annotated[ - Optional[list[Any]], Field(description="Filter by multiple creative statuses") - ] = None - tags: Annotated[ - Optional[list[str]], - Field(description="Filter by creative tags (all tags must match)"), - ] = None - tags_any: Annotated[ - Optional[list[str]], - Field(description="Filter by creative tags (any tag must match)"), - ] = None - name_contains: Annotated[ - Optional[str], - Field( - description="Filter by creative names containing this text (case-insensitive)" - ), - ] = None - creative_ids: Annotated[ - Optional[list[str]], - Field(description="Filter by specific creative IDs", max_length=100), - ] = None - created_after: Annotated[ - Optional[AwareDatetime], - Field(description="Filter creatives created after this date (ISO 8601)"), - ] = None - created_before: Annotated[ - Optional[AwareDatetime], - Field(description="Filter creatives created before this date (ISO 8601)"), - ] = None - updated_after: Annotated[ - Optional[AwareDatetime], - Field(description="Filter creatives last updated after this date (ISO 8601)"), - ] = None - updated_before: Annotated[ - Optional[AwareDatetime], - Field(description="Filter creatives last updated before this date (ISO 8601)"), - ] = None - assigned_to_package: Annotated[ - Optional[str], - Field(description="Filter creatives assigned to this specific package"), - ] = None - assigned_to_packages: Annotated[ - Optional[list[str]], - Field(description="Filter creatives assigned to any of these packages"), - ] = None - unassigned: Annotated[ - Optional[bool], - Field( - description="Filter for unassigned creatives when true, assigned creatives when false" - ), - ] = None - snippet_type: Annotated[ - Optional[SnippetType], - Field( - description="Types of third-party creative snippets supported by AdCP", - examples=[ - { - "type": "vast_xml", - "description": "Inline VAST XML", - "snippet": 'Sample Ad...', - }, - { - "type": "vast_url", - "description": "VAST endpoint URL", - "snippet": "https://ads.example.com/vast?campaign=12345&placement=video", - }, - { - "type": "html", - "description": "HTML display ad", - "snippet": '
Ad
', - }, - { - "type": "javascript", - "description": "JavaScript ad tag", - "snippet": '', - }, - { - "type": "iframe", - "description": "iFrame ad tag", - "snippet": '', - }, - { - "type": "daast_url", - "description": "DAAST audio ad URL", - "snippet": "https://audio-ads.example.com/daast?campaign=audio123", - }, - ], - title="Snippet Type", - ), - ] = None - has_performance_data: Annotated[ - Optional[bool], - Field(description="Filter creatives that have performance data when true"), - ] = None - - -class FieldModel(Enum): - created_date = "created_date" - updated_date = "updated_date" - name = "name" - status = "status" - assignment_count = "assignment_count" - performance_score = "performance_score" - - -class Direction(Enum): - asc = "asc" - desc = "desc" - - -class Sort(BaseModel): - model_config = ConfigDict( - extra="forbid", - ) - field: Annotated[Optional[FieldModel], Field(description="Field to sort by")] = ( - "created_date" - ) - direction: Annotated[Optional[Direction], Field(description="Sort direction")] = ( - "desc" - ) - - -class Pagination(BaseModel): - model_config = ConfigDict( - extra="forbid", - ) - limit: Annotated[ - Optional[int], - Field(description="Maximum number of creatives to return", ge=1, le=100), - ] = 50 - offset: Annotated[ - Optional[int], Field(description="Number of creatives to skip", ge=0) - ] = 0 - - -class Field1(Enum): - creative_id = "creative_id" - name = "name" - format = "format" - status = "status" - created_date = "created_date" - updated_date = "updated_date" - tags = "tags" - assignments = "assignments" - performance = "performance" - sub_assets = "sub_assets" - - -class ListCreativesRequest(BaseModel): - model_config = ConfigDict( - extra="forbid", - ) - adcp_version: Annotated[ - Optional[str], - Field( - description="AdCP schema version for this request", - pattern="^\\d+\\.\\d+\\.\\d+$", - ), - ] = "1.6.0" - filters: Annotated[ - Optional[Filters], Field(description="Filter criteria for querying creatives") - ] = None - sort: Annotated[Optional[Sort], Field(description="Sorting parameters")] = None - pagination: Annotated[ - Optional[Pagination], Field(description="Pagination parameters") - ] = None - include_assignments: Annotated[ - Optional[bool], - Field(description="Include package assignment information in response"), - ] = True - include_performance: Annotated[ - Optional[bool], - Field(description="Include aggregated performance metrics in response"), - ] = False - include_sub_assets: Annotated[ - Optional[bool], - Field( - description="Include sub-assets (for carousel/native formats) in response" - ), - ] = False - fields: Annotated[ - Optional[list[Field1]], - Field( - description="Specific fields to include in response (omit for all fields)" - ), - ] = None diff --git a/src/creative_agent/schemas_generated/_schemas_v1_media_buy_list_creatives_response_json.py b/src/creative_agent/schemas_generated/_schemas_v1_media_buy_list_creatives_response_json.py deleted file mode 100644 index 2cb33e0..0000000 --- a/src/creative_agent/schemas_generated/_schemas_v1_media_buy_list_creatives_response_json.py +++ /dev/null @@ -1,341 +0,0 @@ -# generated by datamodel-codegen: -# filename: _schemas_v1_media-buy_list-creatives-response_json.json - -from __future__ import annotations - -from enum import Enum -from typing import Annotated, Optional, Union - -from pydantic import AnyUrl, AwareDatetime, BaseModel, ConfigDict, Field - - -class Direction(Enum): - asc = "asc" - desc = "desc" - - -class SortApplied(BaseModel): - field: Optional[str] = None - direction: Optional[Direction] = None - - -class QuerySummary(BaseModel): - model_config = ConfigDict( - extra="forbid", - ) - total_matching: Annotated[ - int, - Field( - description="Total number of creatives matching filters (across all pages)", - ge=0, - ), - ] - returned: Annotated[ - int, Field(description="Number of creatives returned in this response", ge=0) - ] - filters_applied: Annotated[ - Optional[list[str]], - Field(description="List of filters that were applied to the query"), - ] = None - sort_applied: Annotated[ - Optional[SortApplied], Field(description="Sort order that was applied") - ] = None - - -class Pagination(BaseModel): - model_config = ConfigDict( - extra="forbid", - ) - limit: Annotated[ - int, Field(description="Maximum number of results requested", ge=1) - ] - offset: Annotated[int, Field(description="Number of results skipped", ge=0)] - has_more: Annotated[bool, Field(description="Whether more results are available")] - total_pages: Annotated[ - Optional[int], Field(description="Total number of pages available", ge=0) - ] = None - current_page: Annotated[ - Optional[int], Field(description="Current page number (1-based)", ge=1) - ] = None - - -class Status(Enum): - processing = "processing" - approved = "approved" - rejected = "rejected" - pending_review = "pending_review" - - -class SnippetType(Enum): - vast_xml = "vast_xml" - vast_url = "vast_url" - html = "html" - javascript = "javascript" - iframe = "iframe" - daast_url = "daast_url" - - -class Status13(Enum): - active = "active" - paused = "paused" - ended = "ended" - - -class AssignedPackage(BaseModel): - model_config = ConfigDict( - extra="forbid", - ) - package_id: Annotated[str, Field(description="Package identifier")] - package_name: Annotated[ - Optional[str], Field(description="Human-readable package name") - ] = None - assigned_date: Annotated[ - AwareDatetime, Field(description="When this assignment was created") - ] - status: Annotated[Status13, Field(description="Status of this specific assignment")] - - -class Assignments(BaseModel): - model_config = ConfigDict( - extra="forbid", - ) - assignment_count: Annotated[ - int, Field(description="Total number of active package assignments", ge=0) - ] - assigned_packages: Annotated[ - Optional[list[AssignedPackage]], - Field(description="List of packages this creative is assigned to"), - ] = None - - -class Performance(BaseModel): - model_config = ConfigDict( - extra="forbid", - ) - impressions: Annotated[ - Optional[int], - Field(description="Total impressions across all assignments", ge=0), - ] = None - clicks: Annotated[ - Optional[int], Field(description="Total clicks across all assignments", ge=0) - ] = None - ctr: Annotated[ - Optional[float], - Field(description="Click-through rate (clicks/impressions)", ge=0.0, le=1.0), - ] = None - conversion_rate: Annotated[ - Optional[float], - Field(description="Conversion rate across all assignments", ge=0.0, le=1.0), - ] = None - performance_score: Annotated[ - Optional[float], - Field(description="Aggregated performance score (0-100)", ge=0.0, le=100.0), - ] = None - last_updated: Annotated[ - AwareDatetime, Field(description="When performance data was last updated") - ] - - -class SubAssets(BaseModel): - model_config = ConfigDict( - extra="forbid", - ) - asset_type: Annotated[ - str, - Field( - description="Type of asset. Common types: headline, body_text, thumbnail_image, product_image, featured_image, logo, cta_text, price_text, sponsor_name, author_name, click_url" - ), - ] - asset_id: Annotated[ - str, Field(description="Unique identifier for the asset within the creative") - ] - content_uri: Annotated[ - AnyUrl, Field(description="URL for media assets (images, videos, etc.)") - ] - content: Annotated[ - Optional[Union[str, list[str]]], - Field( - description="Text content for text-based assets like headlines, body text, CTA text, etc." - ), - ] = None - - -class SubAssets1(BaseModel): - model_config = ConfigDict( - extra="forbid", - ) - asset_type: Annotated[ - str, - Field( - description="Type of asset. Common types: headline, body_text, thumbnail_image, product_image, featured_image, logo, cta_text, price_text, sponsor_name, author_name, click_url" - ), - ] - asset_id: Annotated[ - str, Field(description="Unique identifier for the asset within the creative") - ] - content_uri: Annotated[ - Optional[AnyUrl], - Field(description="URL for media assets (images, videos, etc.)"), - ] = None - content: Annotated[ - Union[str, list[str]], - Field( - description="Text content for text-based assets like headlines, body text, CTA text, etc." - ), - ] - - -class Creative(BaseModel): - model_config = ConfigDict( - extra="forbid", - ) - creative_id: Annotated[str, Field(description="Unique identifier for the creative")] - name: Annotated[str, Field(description="Human-readable creative name")] - format: Annotated[str, Field(description="Creative format type")] - status: Annotated[ - Status, Field(description="Status of a creative asset", title="Creative Status") - ] - created_date: Annotated[ - AwareDatetime, - Field(description="When the creative was uploaded to the library"), - ] - updated_date: Annotated[ - AwareDatetime, Field(description="When the creative was last modified") - ] - media_url: Annotated[ - Optional[AnyUrl], - Field(description="URL of the creative file (for hosted assets)"), - ] = None - snippet: Annotated[ - Optional[str], - Field( - description="Third-party tag, VAST XML, or code snippet (for third-party assets)" - ), - ] = None - snippet_type: Annotated[ - Optional[SnippetType], - Field( - description="Types of third-party creative snippets supported by AdCP", - examples=[ - { - "type": "vast_xml", - "description": "Inline VAST XML", - "snippet": 'Sample Ad...', - }, - { - "type": "vast_url", - "description": "VAST endpoint URL", - "snippet": "https://ads.example.com/vast?campaign=12345&placement=video", - }, - { - "type": "html", - "description": "HTML display ad", - "snippet": '
Ad
', - }, - { - "type": "javascript", - "description": "JavaScript ad tag", - "snippet": '', - }, - { - "type": "iframe", - "description": "iFrame ad tag", - "snippet": '', - }, - { - "type": "daast_url", - "description": "DAAST audio ad URL", - "snippet": "https://audio-ads.example.com/daast?campaign=audio123", - }, - ], - title="Snippet Type", - ), - ] = None - click_url: Annotated[ - Optional[AnyUrl], Field(description="Landing page URL for the creative") - ] = None - duration: Annotated[ - Optional[float], - Field(description="Duration in milliseconds (for video/audio)", ge=0.0), - ] = None - width: Annotated[ - Optional[float], - Field(description="Width in pixels (for video/display)", ge=0.0), - ] = None - height: Annotated[ - Optional[float], - Field(description="Height in pixels (for video/display)", ge=0.0), - ] = None - tags: Annotated[ - Optional[list[str]], - Field(description="User-defined tags for organization and searchability"), - ] = None - assignments: Annotated[ - Optional[Assignments], - Field( - description="Current package assignments (included when include_assignments=true)" - ), - ] = None - performance: Annotated[ - Optional[Performance], - Field( - description="Aggregated performance metrics (included when include_performance=true)" - ), - ] = None - sub_assets: Annotated[ - Optional[list[Union[SubAssets, SubAssets1]]], - Field( - description="Sub-assets for multi-asset formats (included when include_sub_assets=true)" - ), - ] = None - - -class StatusSummary(BaseModel): - model_config = ConfigDict( - extra="forbid", - ) - approved: Annotated[ - Optional[int], Field(description="Number of approved creatives", ge=0) - ] = None - pending_review: Annotated[ - Optional[int], Field(description="Number of creatives pending review", ge=0) - ] = None - rejected: Annotated[ - Optional[int], Field(description="Number of rejected creatives", ge=0) - ] = None - archived: Annotated[ - Optional[int], Field(description="Number of archived creatives", ge=0) - ] = None - - -class ListCreativesResponse(BaseModel): - model_config = ConfigDict( - extra="forbid", - ) - adcp_version: Annotated[ - str, - Field( - description="AdCP schema version used for this response", - pattern="^\\d+\\.\\d+\\.\\d+$", - ), - ] - message: Annotated[str, Field(description="Human-readable result message")] - context_id: Annotated[ - Optional[str], Field(description="Context ID for tracking related operations") - ] = None - query_summary: Annotated[ - QuerySummary, Field(description="Summary of the query that was executed") - ] - pagination: Annotated[ - Pagination, Field(description="Pagination information for navigating results") - ] - creatives: Annotated[ - list[Creative], Field(description="Array of creative assets matching the query") - ] - format_summary: Annotated[ - Optional[dict[str, int]], - Field(description="Breakdown of creatives by format type"), - ] = None - status_summary: Annotated[ - Optional[StatusSummary], Field(description="Breakdown of creatives by status") - ] = None diff --git a/src/creative_agent/schemas_generated/_schemas_v1_media_buy_package_request_json.py b/src/creative_agent/schemas_generated/_schemas_v1_media_buy_package_request_json.py deleted file mode 100644 index 3941e6a..0000000 --- a/src/creative_agent/schemas_generated/_schemas_v1_media_buy_package_request_json.py +++ /dev/null @@ -1,156 +0,0 @@ -# generated by datamodel-codegen: -# filename: _schemas_v1_media-buy_package-request_json.json - -from __future__ import annotations - -from enum import Enum -from typing import Annotated, Any, Optional, Union - -from pydantic import BaseModel, ConfigDict, Field, RootModel - - -class Pacing(Enum): - even = "even" - asap = "asap" - front_loaded = "front_loaded" - - -class Budget(BaseModel): - model_config = ConfigDict( - extra="forbid", - ) - total: Annotated[float, Field(description="Total budget amount", ge=0.0)] - currency: Annotated[ - str, - Field( - description="ISO 4217 currency code", - examples=["USD", "EUR", "GBP"], - pattern="^[A-Z]{3}$", - ), - ] - pacing: Annotated[ - Optional[Pacing], Field(description="Budget pacing strategy", title="Pacing") - ] = None - - -class GeoCountryAnyOfItem(RootModel[str]): - root: Annotated[str, Field(pattern="^[A-Z]{2}$")] - - -class FrequencyCap(BaseModel): - model_config = ConfigDict( - extra="forbid", - ) - suppress_minutes: Annotated[ - float, Field(description="Minutes to suppress after impression", ge=0.0) - ] - - -class TargetingOverlay(BaseModel): - model_config = ConfigDict( - extra="forbid", - ) - geo_country_any_of: Annotated[ - Optional[list[GeoCountryAnyOfItem]], - Field( - description="Restrict delivery to specific countries (ISO codes). Use for regulatory compliance or RCT testing." - ), - ] = None - geo_region_any_of: Annotated[ - Optional[list[str]], - Field( - description="Restrict delivery to specific regions/states. Use for regulatory compliance or RCT testing." - ), - ] = None - geo_metro_any_of: Annotated[ - Optional[list[str]], - Field( - description="Restrict delivery to specific metro areas (DMA codes). Use for regulatory compliance or RCT testing." - ), - ] = None - geo_postal_code_any_of: Annotated[ - Optional[list[str]], - Field( - description="Restrict delivery to specific postal/ZIP codes. Use for regulatory compliance or RCT testing." - ), - ] = None - frequency_cap: Annotated[ - Optional[FrequencyCap], - Field( - description="Frequency capping settings for package-level application", - title="Frequency Cap", - ), - ] = None - - -class PackageRequest1(BaseModel): - model_config = ConfigDict( - extra="forbid", - ) - buyer_ref: Annotated[ - str, Field(description="Buyer's reference identifier for this package") - ] - products: Annotated[ - list[str], Field(description="Array of product IDs to include in this package") - ] - format_ids: Annotated[ - list[str], - Field( - description="Array of format IDs that will be used for this package - must be supported by all products" - ), - ] - budget: Annotated[ - Optional[Budget], - Field( - description="Budget configuration for a media buy or package", - title="Budget", - ), - ] = None - targeting_overlay: Annotated[ - Optional[TargetingOverlay], - Field( - description="Optional geographic refinements for media buys. Most targeting should be expressed in the brief and handled by the publisher. These fields are primarily for geographic restrictions (RCT testing, regulatory compliance).", - title="Targeting Overlay", - ), - ] = None - creative_ids: Annotated[ - Optional[list[str]], - Field(description="Creative IDs to assign to this package at creation time"), - ] = None - - -class PackageRequest2(BaseModel): - model_config = ConfigDict( - extra="forbid", - ) - buyer_ref: Annotated[ - str, Field(description="Buyer's reference identifier for this package") - ] - products: Annotated[ - list[str], Field(description="Array of product IDs to include in this package") - ] - format_selection: Annotated[ - dict[str, Any], Field(description="Dynamic format selection criteria") - ] - budget: Annotated[ - Optional[Any], - Field(description="Circular reference to /schemas/v1/core/budget.json"), - ] = None - targeting_overlay: Annotated[ - Optional[Any], - Field(description="Circular reference to /schemas/v1/core/targeting.json"), - ] = None - creative_ids: Annotated[ - Optional[list[str]], - Field(description="Creative IDs to assign to this package at creation time"), - ] = None - - -class PackageRequest(RootModel[Union[PackageRequest1, PackageRequest2]]): - root: Annotated[ - Union[PackageRequest1, PackageRequest2], - Field( - description="Package configuration for media buy creation", - title="Package Request", - ), - ] diff --git a/src/creative_agent/schemas_generated/_schemas_v1_media_buy_sync_creatives_request_json.py b/src/creative_agent/schemas_generated/_schemas_v1_media_buy_sync_creatives_request_json.py deleted file mode 100644 index 606bdf7..0000000 --- a/src/creative_agent/schemas_generated/_schemas_v1_media_buy_sync_creatives_request_json.py +++ /dev/null @@ -1,351 +0,0 @@ -# generated by datamodel-codegen: -# filename: _schemas_v1_media-buy_sync-creatives-request_json.json - -from __future__ import annotations - -from enum import Enum -from typing import Annotated, Literal, Optional, Union - -from pydantic import AnyUrl, BaseModel, ConfigDict, Field - - -class FormatId(BaseModel): - model_config = ConfigDict( - extra="forbid", - ) - 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)" - ), - ] - id: Annotated[ - str, - Field( - description="Format identifier within the agent's namespace (e.g., 'display_300x250', 'video_standard_30s')", - pattern="^[a-zA-Z0-9_-]+$", - ), - ] - - -class Assets(BaseModel): - model_config = ConfigDict( - extra="forbid", - ) - asset_type: Literal["image"] - url: Annotated[AnyUrl, Field(description="URL to the image asset")] - width: Annotated[ - Optional[int], Field(description="Image width in pixels", ge=1) - ] = None - height: Annotated[ - Optional[int], Field(description="Image height in pixels", ge=1) - ] = None - format: Annotated[ - Optional[str], - Field(description="Image file format (jpg, png, gif, webp, etc.)"), - ] = None - alt_text: Annotated[ - Optional[str], Field(description="Alternative text for accessibility") - ] = None - - -class Assets30(BaseModel): - model_config = ConfigDict( - extra="forbid", - ) - asset_type: Literal["video"] - url: Annotated[AnyUrl, Field(description="URL to the video asset")] - width: Annotated[ - Optional[int], Field(description="Video width in pixels", ge=1) - ] = None - height: Annotated[ - Optional[int], Field(description="Video height in pixels", ge=1) - ] = None - duration_ms: Annotated[ - Optional[int], Field(description="Video duration in milliseconds", ge=0) - ] = None - format: Annotated[ - Optional[str], Field(description="Video file format (mp4, webm, mov, etc.)") - ] = None - bitrate_kbps: Annotated[ - Optional[int], Field(description="Video bitrate in kilobits per second", ge=1) - ] = None - - -class Assets31(BaseModel): - model_config = ConfigDict( - extra="forbid", - ) - asset_type: Literal["audio"] - url: Annotated[AnyUrl, Field(description="URL to the audio asset")] - duration_ms: Annotated[ - Optional[int], Field(description="Audio duration in milliseconds", ge=0) - ] = None - format: Annotated[ - Optional[str], Field(description="Audio file format (mp3, wav, aac, etc.)") - ] = None - bitrate_kbps: Annotated[ - Optional[int], Field(description="Audio bitrate in kilobits per second", ge=1) - ] = None - - -class Assets32(BaseModel): - model_config = ConfigDict( - extra="forbid", - ) - asset_type: Literal["text"] - content: Annotated[str, Field(description="Text content")] - max_length: Annotated[ - Optional[int], Field(description="Maximum character length constraint", ge=1) - ] = None - language: Annotated[ - Optional[str], Field(description="Language code (e.g., 'en', 'es', 'fr')") - ] = None - - -class Assets33(BaseModel): - model_config = ConfigDict( - extra="forbid", - ) - asset_type: Literal["html"] - content: Annotated[str, Field(description="HTML content")] - version: Annotated[ - Optional[str], Field(description="HTML version (e.g., 'HTML5')") - ] = None - - -class Assets34(BaseModel): - model_config = ConfigDict( - extra="forbid", - ) - asset_type: Literal["css"] - content: Annotated[str, Field(description="CSS content")] - media: Annotated[ - Optional[str], - Field(description="CSS media query context (e.g., 'screen', 'print')"), - ] = None - - -class ModuleType(Enum): - esm = "esm" - commonjs = "commonjs" - script = "script" - - -class Assets35(BaseModel): - model_config = ConfigDict( - extra="forbid", - ) - asset_type: Literal["javascript"] - content: Annotated[str, Field(description="JavaScript content")] - module_type: Annotated[ - Optional[ModuleType], Field(description="JavaScript module type") - ] = None - - -class Colors(BaseModel): - primary: Optional[str] = None - secondary: Optional[str] = None - accent: Optional[str] = None - - -class Assets36(BaseModel): - model_config = ConfigDict( - extra="forbid", - ) - asset_type: Literal["promoted_offerings"] - url: Annotated[ - Optional[AnyUrl], - Field( - description="URL of the advertiser's brand or offering (e.g., https://retailer.com)" - ), - ] = None - colors: Annotated[Optional[Colors], Field(description="Brand colors")] = None - fonts: Annotated[Optional[list[str]], Field(description="Brand fonts")] = None - tone: Annotated[Optional[str], Field(description="Brand tone/voice")] = None - - -class Assets37(BaseModel): - model_config = ConfigDict( - extra="forbid", - ) - asset_type: Literal["url"] - url: Annotated[AnyUrl, Field(description="URL reference")] - description: Annotated[ - Optional[str], Field(description="Description of what this URL points to") - ] = None - - -class Input(BaseModel): - model_config = ConfigDict( - extra="forbid", - ) - name: Annotated[ - str, Field(description="Human-readable name for this preview variant") - ] - macros: Annotated[ - Optional[dict[str, str]], - Field(description="Macro values to apply for this preview"), - ] = None - context_description: Annotated[ - Optional[str], - Field( - description="Natural language description of the context for AI-generated content" - ), - ] = None - - -class Creative(BaseModel): - model_config = ConfigDict( - extra="forbid", - ) - creative_id: Annotated[str, Field(description="Unique identifier for the creative")] - name: Annotated[str, Field(description="Human-readable creative name")] - format_id: Annotated[ - FormatId, - Field( - description="Structured format identifier with agent URL and format name", - title="Format ID", - ), - ] - assets: Annotated[ - dict[ - str, - Union[ - Assets, - Assets30, - Assets31, - Assets32, - Assets33, - Assets34, - Assets35, - Assets36, - Assets37, - ], - ], - Field(description="Assets required by the format, keyed by asset_role"), - ] - inputs: Annotated[ - Optional[list[Input]], - Field( - description="Preview contexts for generative formats - defines what scenarios to generate previews for" - ), - ] = None - tags: Annotated[ - Optional[list[str]], - Field(description="User-defined tags for organization and searchability"), - ] = None - approved: Annotated[ - Optional[bool], - Field( - description="For generative creatives: set to true to approve and finalize, false to request regeneration with updated assets/message. Omit for non-generative creatives." - ), - ] = None - - -class ValidationMode(Enum): - strict = "strict" - lenient = "lenient" - - -class Scheme(Enum): - bearer = "Bearer" - hmac_sha256 = "HMAC-SHA256" - - -class Authentication(BaseModel): - model_config = ConfigDict( - extra="forbid", - ) - schemes: Annotated[ - list[Scheme], - Field( - description="Array of authentication schemes. Supported: ['Bearer'] for simple token auth, ['HMAC-SHA256'] for signature verification (recommended for production)", - max_length=1, - min_length=1, - ), - ] - credentials: Annotated[ - str, - Field( - description="Credentials for authentication. For Bearer: token sent in Authorization header. For HMAC-SHA256: shared secret used to generate signature. Minimum 32 characters. Exchanged out-of-band during onboarding.", - min_length=32, - ), - ] - - -class PushNotificationConfig(BaseModel): - model_config = ConfigDict( - extra="forbid", - ) - url: Annotated[ - AnyUrl, Field(description="Webhook endpoint URL for task status notifications") - ] - token: Annotated[ - Optional[str], - Field( - description="Optional client-provided token for webhook validation. Echoed back in webhook payload to validate request authenticity.", - min_length=16, - ), - ] = None - authentication: Annotated[ - Authentication, - Field( - description="Authentication configuration for webhook delivery (A2A-compatible)" - ), - ] - - -class SyncCreativesRequest(BaseModel): - model_config = ConfigDict( - extra="forbid", - ) - adcp_version: Annotated[ - Optional[str], - Field( - description="AdCP schema version for this request", - pattern="^\\d+\\.\\d+\\.\\d+$", - ), - ] = "1.6.0" - creatives: Annotated[ - list[Creative], - Field( - description="Array of creative assets to sync (create or update)", - max_length=100, - ), - ] - patch: Annotated[ - Optional[bool], - Field( - description="When true, only provided fields are updated (partial update). When false, entire creative is replaced (full upsert)." - ), - ] = False - assignments: Annotated[ - Optional[dict[str, list[str]]], - Field(description="Optional bulk assignment of creatives to packages"), - ] = None - delete_missing: Annotated[ - Optional[bool], - Field( - description="When true, creatives not included in this sync will be archived. Use with caution for full library replacement." - ), - ] = False - dry_run: Annotated[ - Optional[bool], - Field( - description="When true, preview changes without applying them. Returns what would be created/updated/deleted." - ), - ] = False - validation_mode: Annotated[ - Optional[ValidationMode], - Field( - description="Validation strictness. 'strict' fails entire sync on any validation error. 'lenient' processes valid creatives and reports errors." - ), - ] = "strict" - push_notification_config: Annotated[ - Optional[PushNotificationConfig], - Field( - description="Webhook configuration for asynchronous task notifications. Uses A2A-compatible PushNotificationConfig structure. Supports Bearer tokens (simple) or HMAC signatures (production-recommended).", - title="Push Notification Config", - ), - ] = None diff --git a/src/creative_agent/schemas_generated/_schemas_v1_media_buy_sync_creatives_response_json.py b/src/creative_agent/schemas_generated/_schemas_v1_media_buy_sync_creatives_response_json.py deleted file mode 100644 index 1874b07..0000000 --- a/src/creative_agent/schemas_generated/_schemas_v1_media_buy_sync_creatives_response_json.py +++ /dev/null @@ -1,125 +0,0 @@ -# generated by datamodel-codegen: -# filename: _schemas_v1_media-buy_sync-creatives-response_json.json - -from __future__ import annotations - -from enum import Enum -from typing import Annotated, Optional - -from pydantic import AnyUrl, AwareDatetime, BaseModel, ConfigDict, Field - - -class Status(Enum): - submitted = "submitted" - working = "working" - input_required = "input-required" - completed = "completed" - canceled = "canceled" - failed = "failed" - rejected = "rejected" - auth_required = "auth-required" - unknown = "unknown" - - -class Action(Enum): - created = "created" - updated = "updated" - unchanged = "unchanged" - failed = "failed" - deleted = "deleted" - - -class Creative(BaseModel): - model_config = ConfigDict( - extra="forbid", - ) - creative_id: Annotated[str, Field(description="Creative ID from the request")] - action: Annotated[Action, Field(description="Action taken for this creative")] - platform_id: Annotated[ - Optional[str], - Field(description="Platform-specific ID assigned to the creative"), - ] = None - changes: Annotated[ - Optional[list[str]], - Field( - description="Field names that were modified (only present when action='updated')" - ), - ] = None - errors: Annotated[ - Optional[list[str]], - Field( - description="Validation or processing errors (only present when action='failed')" - ), - ] = None - warnings: Annotated[ - Optional[list[str]], Field(description="Non-fatal warnings about this creative") - ] = None - preview_url: Annotated[ - Optional[AnyUrl], - Field( - description="Preview URL for generative creatives (only present for generative formats)" - ), - ] = None - expires_at: Annotated[ - Optional[AwareDatetime], - Field( - description="ISO 8601 timestamp when preview link expires (only present when preview_url exists)" - ), - ] = None - assigned_to: Annotated[ - Optional[list[str]], - Field( - description="Package IDs this creative was successfully assigned to (only present when assignments were requested)" - ), - ] = None - assignment_errors: Annotated[ - Optional[dict[str, str]], - Field( - description="Assignment errors by package ID (only present when assignment failures occurred)" - ), - ] = None - - -class SyncCreativesResponse(BaseModel): - model_config = ConfigDict( - extra="forbid", - ) - adcp_version: Annotated[ - str, - Field( - description="AdCP schema version used for this response", - pattern="^\\d+\\.\\d+\\.\\d+$", - ), - ] - message: Annotated[ - str, - Field( - description="Human-readable result message (e.g., 'Synced 3 creatives: 2 created, 1 updated')" - ), - ] - context_id: Annotated[ - Optional[str], - Field( - description="Context ID for tracking async operations and conversational approval workflows" - ), - ] = None - status: Annotated[ - Status, - Field( - description="Standardized task status values based on A2A TaskState enum. Indicates the current state of any AdCP operation.", - title="Task Status", - ), - ] - task_id: Annotated[ - Optional[str], - Field( - description="Unique identifier for tracking this async operation (present for submitted/working status)" - ), - ] = None - dry_run: Annotated[ - Optional[bool], - Field(description="Whether this was a dry run (no actual changes made)"), - ] = None - creatives: Annotated[ - list[Creative], Field(description="Results for each creative processed") - ] diff --git a/src/creative_agent/schemas_generated/_schemas_v1_media_buy_update_media_buy_request_json.py b/src/creative_agent/schemas_generated/_schemas_v1_media_buy_update_media_buy_request_json.py deleted file mode 100644 index 2e982f7..0000000 --- a/src/creative_agent/schemas_generated/_schemas_v1_media_buy_update_media_buy_request_json.py +++ /dev/null @@ -1,500 +0,0 @@ -# generated by datamodel-codegen: -# filename: _schemas_v1_media-buy_update-media-buy-request_json.json - -from __future__ import annotations - -from enum import Enum -from typing import Annotated, Optional, Union - -from pydantic import AnyUrl, AwareDatetime, BaseModel, ConfigDict, Field, RootModel - - -class GeoCountryAnyOfItem(RootModel[str]): - root: Annotated[str, Field(pattern="^[A-Z]{2}$")] - - -class FrequencyCap(BaseModel): - model_config = ConfigDict( - extra="forbid", - ) - suppress_minutes: Annotated[ - float, Field(description="Minutes to suppress after impression", ge=0.0) - ] - - -class TargetingOverlay(BaseModel): - model_config = ConfigDict( - extra="forbid", - ) - geo_country_any_of: Annotated[ - Optional[list[GeoCountryAnyOfItem]], - Field( - description="Restrict delivery to specific countries (ISO codes). Use for regulatory compliance or RCT testing." - ), - ] = None - geo_region_any_of: Annotated[ - Optional[list[str]], - Field( - description="Restrict delivery to specific regions/states. Use for regulatory compliance or RCT testing." - ), - ] = None - geo_metro_any_of: Annotated[ - Optional[list[str]], - Field( - description="Restrict delivery to specific metro areas (DMA codes). Use for regulatory compliance or RCT testing." - ), - ] = None - geo_postal_code_any_of: Annotated[ - Optional[list[str]], - Field( - description="Restrict delivery to specific postal/ZIP codes. Use for regulatory compliance or RCT testing." - ), - ] = None - frequency_cap: Annotated[ - Optional[FrequencyCap], - Field( - description="Frequency capping settings for package-level application", - title="Frequency Cap", - ), - ] = None - - -class Packages(BaseModel): - model_config = ConfigDict( - extra="forbid", - ) - package_id: Annotated[str, Field(description="Publisher's ID of package to update")] - buyer_ref: Annotated[ - Optional[str], Field(description="Buyer's reference for the package to update") - ] = None - budget: Annotated[ - Optional[float], - Field( - description="Updated budget allocation for this package in the currency specified by the pricing option", - ge=0.0, - ), - ] = None - active: Annotated[ - Optional[bool], Field(description="Pause/resume specific package") - ] = None - targeting_overlay: Annotated[ - Optional[TargetingOverlay], - Field( - description="Optional geographic refinements for media buys. Most targeting should be expressed in the brief and handled by the publisher. These fields are primarily for geographic restrictions (RCT testing, regulatory compliance).", - title="Targeting Overlay", - ), - ] = None - creative_ids: Annotated[ - Optional[list[str]], Field(description="Update creative assignments") - ] = None - - -class TargetingOverlay6(BaseModel): - model_config = ConfigDict( - extra="forbid", - ) - geo_country_any_of: Annotated[ - Optional[list[GeoCountryAnyOfItem]], - Field( - description="Restrict delivery to specific countries (ISO codes). Use for regulatory compliance or RCT testing." - ), - ] = None - geo_region_any_of: Annotated[ - Optional[list[str]], - Field( - description="Restrict delivery to specific regions/states. Use for regulatory compliance or RCT testing." - ), - ] = None - geo_metro_any_of: Annotated[ - Optional[list[str]], - Field( - description="Restrict delivery to specific metro areas (DMA codes). Use for regulatory compliance or RCT testing." - ), - ] = None - geo_postal_code_any_of: Annotated[ - Optional[list[str]], - Field( - description="Restrict delivery to specific postal/ZIP codes. Use for regulatory compliance or RCT testing." - ), - ] = None - frequency_cap: Annotated[ - Optional[FrequencyCap], - Field( - description="Frequency capping settings for package-level application", - title="Frequency Cap", - ), - ] = None - - -class Packages5(BaseModel): - model_config = ConfigDict( - extra="forbid", - ) - package_id: Annotated[ - Optional[str], Field(description="Publisher's ID of package to update") - ] = None - buyer_ref: Annotated[ - str, Field(description="Buyer's reference for the package to update") - ] - budget: Annotated[ - Optional[float], - Field( - description="Updated budget allocation for this package in the currency specified by the pricing option", - ge=0.0, - ), - ] = None - active: Annotated[ - Optional[bool], Field(description="Pause/resume specific package") - ] = None - targeting_overlay: Annotated[ - Optional[TargetingOverlay6], - Field( - description="Optional geographic refinements for media buys. Most targeting should be expressed in the brief and handled by the publisher. These fields are primarily for geographic restrictions (RCT testing, regulatory compliance).", - title="Targeting Overlay", - ), - ] = None - creative_ids: Annotated[ - Optional[list[str]], Field(description="Update creative assignments") - ] = None - - -class Scheme(Enum): - bearer = "Bearer" - hmac_sha256 = "HMAC-SHA256" - - -class Authentication(BaseModel): - model_config = ConfigDict( - extra="forbid", - ) - schemes: Annotated[ - list[Scheme], - Field( - description="Array of authentication schemes. Supported: ['Bearer'] for simple token auth, ['HMAC-SHA256'] for signature verification (recommended for production)", - max_length=1, - min_length=1, - ), - ] - credentials: Annotated[ - str, - Field( - description="Credentials for authentication. For Bearer: token sent in Authorization header. For HMAC-SHA256: shared secret used to generate signature. Minimum 32 characters. Exchanged out-of-band during onboarding.", - min_length=32, - ), - ] - - -class PushNotificationConfig(BaseModel): - model_config = ConfigDict( - extra="forbid", - ) - url: Annotated[ - AnyUrl, Field(description="Webhook endpoint URL for task status notifications") - ] - token: Annotated[ - Optional[str], - Field( - description="Optional client-provided token for webhook validation. Echoed back in webhook payload to validate request authenticity.", - min_length=16, - ), - ] = None - authentication: Annotated[ - Authentication, - Field( - description="Authentication configuration for webhook delivery (A2A-compatible)" - ), - ] - - -class UpdateMediaBuyRequest1(BaseModel): - model_config = ConfigDict( - extra="forbid", - ) - adcp_version: Annotated[ - Optional[str], - Field( - description="AdCP schema version for this request", - pattern="^\\d+\\.\\d+\\.\\d+$", - ), - ] = "1.6.0" - media_buy_id: Annotated[ - str, Field(description="Publisher's ID of the media buy to update") - ] - buyer_ref: Annotated[ - Optional[str], - Field(description="Buyer's reference for the media buy to update"), - ] = None - active: Annotated[ - Optional[bool], Field(description="Pause/resume the entire media buy") - ] = None - start_time: Annotated[ - Optional[Union[str, AwareDatetime]], - Field( - description="Campaign start timing: 'asap' or ISO 8601 date-time", - title="Start Timing", - ), - ] = None - end_time: Annotated[ - Optional[AwareDatetime], - Field(description="New end date/time in ISO 8601 format"), - ] = None - budget: Annotated[ - Optional[float], - Field( - description="Updated total budget for this media buy. Currency is determined by the pricing_option_id selected in each package.", - ge=0.0, - ), - ] = None - packages: Annotated[ - Optional[list[Union[Packages, Packages5]]], - Field(description="Package-specific updates"), - ] = None - push_notification_config: Annotated[ - Optional[PushNotificationConfig], - Field( - description="Webhook configuration for asynchronous task notifications. Uses A2A-compatible PushNotificationConfig structure. Supports Bearer tokens (simple) or HMAC signatures (production-recommended).", - title="Push Notification Config", - ), - ] = None - - -class TargetingOverlay7(BaseModel): - model_config = ConfigDict( - extra="forbid", - ) - geo_country_any_of: Annotated[ - Optional[list[GeoCountryAnyOfItem]], - Field( - description="Restrict delivery to specific countries (ISO codes). Use for regulatory compliance or RCT testing." - ), - ] = None - geo_region_any_of: Annotated[ - Optional[list[str]], - Field( - description="Restrict delivery to specific regions/states. Use for regulatory compliance or RCT testing." - ), - ] = None - geo_metro_any_of: Annotated[ - Optional[list[str]], - Field( - description="Restrict delivery to specific metro areas (DMA codes). Use for regulatory compliance or RCT testing." - ), - ] = None - geo_postal_code_any_of: Annotated[ - Optional[list[str]], - Field( - description="Restrict delivery to specific postal/ZIP codes. Use for regulatory compliance or RCT testing." - ), - ] = None - frequency_cap: Annotated[ - Optional[FrequencyCap], - Field( - description="Frequency capping settings for package-level application", - title="Frequency Cap", - ), - ] = None - - -class Packages6(BaseModel): - model_config = ConfigDict( - extra="forbid", - ) - package_id: Annotated[str, Field(description="Publisher's ID of package to update")] - buyer_ref: Annotated[ - Optional[str], Field(description="Buyer's reference for the package to update") - ] = None - budget: Annotated[ - Optional[float], - Field( - description="Updated budget allocation for this package in the currency specified by the pricing option", - ge=0.0, - ), - ] = None - active: Annotated[ - Optional[bool], Field(description="Pause/resume specific package") - ] = None - targeting_overlay: Annotated[ - Optional[TargetingOverlay7], - Field( - description="Optional geographic refinements for media buys. Most targeting should be expressed in the brief and handled by the publisher. These fields are primarily for geographic restrictions (RCT testing, regulatory compliance).", - title="Targeting Overlay", - ), - ] = None - creative_ids: Annotated[ - Optional[list[str]], Field(description="Update creative assignments") - ] = None - - -class TargetingOverlay8(BaseModel): - model_config = ConfigDict( - extra="forbid", - ) - geo_country_any_of: Annotated[ - Optional[list[GeoCountryAnyOfItem]], - Field( - description="Restrict delivery to specific countries (ISO codes). Use for regulatory compliance or RCT testing." - ), - ] = None - geo_region_any_of: Annotated[ - Optional[list[str]], - Field( - description="Restrict delivery to specific regions/states. Use for regulatory compliance or RCT testing." - ), - ] = None - geo_metro_any_of: Annotated[ - Optional[list[str]], - Field( - description="Restrict delivery to specific metro areas (DMA codes). Use for regulatory compliance or RCT testing." - ), - ] = None - geo_postal_code_any_of: Annotated[ - Optional[list[str]], - Field( - description="Restrict delivery to specific postal/ZIP codes. Use for regulatory compliance or RCT testing." - ), - ] = None - frequency_cap: Annotated[ - Optional[FrequencyCap], - Field( - description="Frequency capping settings for package-level application", - title="Frequency Cap", - ), - ] = None - - -class Packages7(BaseModel): - model_config = ConfigDict( - extra="forbid", - ) - package_id: Annotated[ - Optional[str], Field(description="Publisher's ID of package to update") - ] = None - buyer_ref: Annotated[ - str, Field(description="Buyer's reference for the package to update") - ] - budget: Annotated[ - Optional[float], - Field( - description="Updated budget allocation for this package in the currency specified by the pricing option", - ge=0.0, - ), - ] = None - active: Annotated[ - Optional[bool], Field(description="Pause/resume specific package") - ] = None - targeting_overlay: Annotated[ - Optional[TargetingOverlay8], - Field( - description="Optional geographic refinements for media buys. Most targeting should be expressed in the brief and handled by the publisher. These fields are primarily for geographic restrictions (RCT testing, regulatory compliance).", - title="Targeting Overlay", - ), - ] = None - creative_ids: Annotated[ - Optional[list[str]], Field(description="Update creative assignments") - ] = None - - -class Authentication5(BaseModel): - model_config = ConfigDict( - extra="forbid", - ) - schemes: Annotated[ - list[Scheme], - Field( - description="Array of authentication schemes. Supported: ['Bearer'] for simple token auth, ['HMAC-SHA256'] for signature verification (recommended for production)", - max_length=1, - min_length=1, - ), - ] - credentials: Annotated[ - str, - Field( - description="Credentials for authentication. For Bearer: token sent in Authorization header. For HMAC-SHA256: shared secret used to generate signature. Minimum 32 characters. Exchanged out-of-band during onboarding.", - min_length=32, - ), - ] - - -class PushNotificationConfig3(BaseModel): - model_config = ConfigDict( - extra="forbid", - ) - url: Annotated[ - AnyUrl, Field(description="Webhook endpoint URL for task status notifications") - ] - token: Annotated[ - Optional[str], - Field( - description="Optional client-provided token for webhook validation. Echoed back in webhook payload to validate request authenticity.", - min_length=16, - ), - ] = None - authentication: Annotated[ - Authentication5, - Field( - description="Authentication configuration for webhook delivery (A2A-compatible)" - ), - ] - - -class UpdateMediaBuyRequest2(BaseModel): - model_config = ConfigDict( - extra="forbid", - ) - adcp_version: Annotated[ - Optional[str], - Field( - description="AdCP schema version for this request", - pattern="^\\d+\\.\\d+\\.\\d+$", - ), - ] = "1.6.0" - media_buy_id: Annotated[ - Optional[str], Field(description="Publisher's ID of the media buy to update") - ] = None - buyer_ref: Annotated[ - str, Field(description="Buyer's reference for the media buy to update") - ] - active: Annotated[ - Optional[bool], Field(description="Pause/resume the entire media buy") - ] = None - start_time: Annotated[ - Optional[Union[str, AwareDatetime]], - Field( - description="Campaign start timing: 'asap' or ISO 8601 date-time", - title="Start Timing", - ), - ] = None - end_time: Annotated[ - Optional[AwareDatetime], - Field(description="New end date/time in ISO 8601 format"), - ] = None - budget: Annotated[ - Optional[float], - Field( - description="Updated total budget for this media buy. Currency is determined by the pricing_option_id selected in each package.", - ge=0.0, - ), - ] = None - packages: Annotated[ - Optional[list[Union[Packages6, Packages7]]], - Field(description="Package-specific updates"), - ] = None - push_notification_config: Annotated[ - Optional[PushNotificationConfig3], - Field( - description="Webhook configuration for asynchronous task notifications. Uses A2A-compatible PushNotificationConfig structure. Supports Bearer tokens (simple) or HMAC signatures (production-recommended).", - title="Push Notification Config", - ), - ] = None - - -class UpdateMediaBuyRequest( - RootModel[Union[UpdateMediaBuyRequest1, UpdateMediaBuyRequest2]] -): - root: Annotated[ - Union[UpdateMediaBuyRequest1, UpdateMediaBuyRequest2], - Field( - description="Request parameters for updating campaign and package settings", - title="Update Media Buy Request", - ), - ] diff --git a/src/creative_agent/schemas_generated/_schemas_v1_media_buy_update_media_buy_response_json.py b/src/creative_agent/schemas_generated/_schemas_v1_media_buy_update_media_buy_response_json.py deleted file mode 100644 index 772c6cb..0000000 --- a/src/creative_agent/schemas_generated/_schemas_v1_media_buy_update_media_buy_response_json.py +++ /dev/null @@ -1,101 +0,0 @@ -# generated by datamodel-codegen: -# filename: _schemas_v1_media-buy_update-media-buy-response_json.json - -from __future__ import annotations - -from enum import Enum -from typing import Annotated, Any, Optional - -from pydantic import AwareDatetime, BaseModel, ConfigDict, Field - - -class Status(Enum): - submitted = "submitted" - working = "working" - input_required = "input-required" - completed = "completed" - canceled = "canceled" - failed = "failed" - rejected = "rejected" - auth_required = "auth-required" - unknown = "unknown" - - -class AffectedPackage(BaseModel): - model_config = ConfigDict( - extra="forbid", - ) - package_id: Annotated[str, Field(description="Publisher's package identifier")] - buyer_ref: Annotated[str, Field(description="Buyer's reference for the package")] - - -class Error(BaseModel): - model_config = ConfigDict( - extra="forbid", - ) - code: Annotated[str, Field(description="Error code for programmatic handling")] - message: Annotated[str, Field(description="Human-readable error message")] - field: Annotated[ - Optional[str], - Field( - description="Field path associated with the error (e.g., 'packages[0].targeting')" - ), - ] = None - suggestion: Annotated[ - Optional[str], Field(description="Suggested fix for the error") - ] = None - retry_after: Annotated[ - Optional[float], - Field(description="Seconds to wait before retrying the operation", ge=0.0), - ] = None - details: Annotated[ - Optional[Any], Field(description="Additional task-specific error details") - ] = None - - -class UpdateMediaBuyResponse(BaseModel): - model_config = ConfigDict( - extra="forbid", - ) - adcp_version: Annotated[ - str, - Field( - description="AdCP schema version used for this response", - pattern="^\\d+\\.\\d+\\.\\d+$", - ), - ] - status: Annotated[ - Status, - Field( - description="Standardized task status values based on A2A TaskState enum. Indicates the current state of any AdCP operation.", - title="Task Status", - ), - ] - task_id: Annotated[ - Optional[str], - Field( - description="Unique identifier for tracking this async operation (present for submitted/working status)" - ), - ] = None - media_buy_id: Annotated[ - str, Field(description="Publisher's identifier for the media buy") - ] - buyer_ref: Annotated[ - str, Field(description="Buyer's reference identifier for the media buy") - ] - implementation_date: Annotated[ - Optional[AwareDatetime], - Field( - description="ISO 8601 timestamp when changes take effect (null if pending approval)" - ), - ] = None - affected_packages: Annotated[ - Optional[list[AffectedPackage]], - Field(description="Array of packages that were modified"), - ] = None - errors: Annotated[ - Optional[list[Error]], - Field( - description="Task-specific errors and warnings (e.g., partial update failures)" - ), - ] = None diff --git a/src/creative_agent/schemas_generated/_schemas_v1_pricing_options_cpc_option_json.py b/src/creative_agent/schemas_generated/_schemas_v1_pricing_options_cpc_option_json.py deleted file mode 100644 index 8d6fa7b..0000000 --- a/src/creative_agent/schemas_generated/_schemas_v1_pricing_options_cpc_option_json.py +++ /dev/null @@ -1,37 +0,0 @@ -# generated by datamodel-codegen: -# filename: _schemas_v1_pricing-options_cpc-option_json.json - -from __future__ import annotations - -from typing import Annotated, Literal, Optional - -from pydantic import BaseModel, ConfigDict, Field - - -class CpcPricingOption(BaseModel): - model_config = ConfigDict( - extra="forbid", - ) - pricing_option_id: Annotated[ - str, - Field( - description="Unique identifier for this pricing option within the product (e.g., 'cpc_usd_fixed')" - ), - ] - pricing_model: Annotated[Literal["cpc"], Field(description="Cost per click")] - rate: Annotated[float, Field(description="Fixed CPC rate (cost per click)", ge=0.0)] - currency: Annotated[ - str, - Field( - description="ISO 4217 currency code", - examples=["USD", "EUR", "GBP", "JPY"], - pattern="^[A-Z]{3}$", - ), - ] - min_spend_per_package: Annotated[ - Optional[float], - Field( - description="Minimum spend requirement per package using this pricing option, in the specified currency", - ge=0.0, - ), - ] = None diff --git a/src/creative_agent/schemas_generated/_schemas_v1_pricing_options_cpcv_option_json.py b/src/creative_agent/schemas_generated/_schemas_v1_pricing_options_cpcv_option_json.py deleted file mode 100644 index 77f6a66..0000000 --- a/src/creative_agent/schemas_generated/_schemas_v1_pricing_options_cpcv_option_json.py +++ /dev/null @@ -1,41 +0,0 @@ -# generated by datamodel-codegen: -# filename: _schemas_v1_pricing-options_cpcv-option_json.json - -from __future__ import annotations - -from typing import Annotated, Literal, Optional - -from pydantic import BaseModel, ConfigDict, Field - - -class CpcvPricingOption(BaseModel): - model_config = ConfigDict( - extra="forbid", - ) - pricing_option_id: Annotated[ - str, - Field( - description="Unique identifier for this pricing option within the product (e.g., 'cpcv_usd_guaranteed')" - ), - ] - pricing_model: Annotated[ - Literal["cpcv"], Field(description="Cost per completed view (100% completion)") - ] - rate: Annotated[ - float, Field(description="Fixed CPCV rate (cost per 100% completion)", ge=0.0) - ] - currency: Annotated[ - str, - Field( - description="ISO 4217 currency code", - examples=["USD", "EUR", "GBP", "JPY"], - pattern="^[A-Z]{3}$", - ), - ] - min_spend_per_package: Annotated[ - Optional[float], - Field( - description="Minimum spend requirement per package using this pricing option, in the specified currency", - ge=0.0, - ), - ] = None diff --git a/src/creative_agent/schemas_generated/_schemas_v1_pricing_options_cpm_auction_option_json.py b/src/creative_agent/schemas_generated/_schemas_v1_pricing_options_cpm_auction_option_json.py deleted file mode 100644 index 6169faf..0000000 --- a/src/creative_agent/schemas_generated/_schemas_v1_pricing_options_cpm_auction_option_json.py +++ /dev/null @@ -1,64 +0,0 @@ -# generated by datamodel-codegen: -# filename: _schemas_v1_pricing-options_cpm-auction-option_json.json - -from __future__ import annotations - -from typing import Annotated, Literal, Optional - -from pydantic import BaseModel, ConfigDict, Field - - -class PriceGuidance(BaseModel): - floor: Annotated[ - float, - Field( - description="Minimum bid price - publisher will reject bids under this value", - ge=0.0, - ), - ] - p25: Annotated[ - Optional[float], Field(description="25th percentile winning price", ge=0.0) - ] = None - p50: Annotated[ - Optional[float], Field(description="Median winning price", ge=0.0) - ] = None - p75: Annotated[ - Optional[float], Field(description="75th percentile winning price", ge=0.0) - ] = None - p90: Annotated[ - Optional[float], Field(description="90th percentile winning price", ge=0.0) - ] = None - - -class CpmAuctionPricingOption(BaseModel): - model_config = ConfigDict( - extra="forbid", - ) - pricing_option_id: Annotated[ - str, - Field( - description="Unique identifier for this pricing option within the product (e.g., 'cpm_usd_auction')" - ), - ] - pricing_model: Annotated[ - Literal["cpm"], Field(description="Cost per 1,000 impressions") - ] - currency: Annotated[ - str, - Field( - description="ISO 4217 currency code", - examples=["USD", "EUR", "GBP", "JPY"], - pattern="^[A-Z]{3}$", - ), - ] - price_guidance: Annotated[ - PriceGuidance, - Field(description="Pricing guidance for auction-based CPM bidding"), - ] - min_spend_per_package: Annotated[ - Optional[float], - Field( - description="Minimum spend requirement per package using this pricing option, in the specified currency", - ge=0.0, - ), - ] = None diff --git a/src/creative_agent/schemas_generated/_schemas_v1_pricing_options_cpm_fixed_option_json.py b/src/creative_agent/schemas_generated/_schemas_v1_pricing_options_cpm_fixed_option_json.py deleted file mode 100644 index 037f005..0000000 --- a/src/creative_agent/schemas_generated/_schemas_v1_pricing_options_cpm_fixed_option_json.py +++ /dev/null @@ -1,41 +0,0 @@ -# generated by datamodel-codegen: -# filename: _schemas_v1_pricing-options_cpm-fixed-option_json.json - -from __future__ import annotations - -from typing import Annotated, Literal, Optional - -from pydantic import BaseModel, ConfigDict, Field - - -class CpmFixedRatePricingOption(BaseModel): - model_config = ConfigDict( - extra="forbid", - ) - pricing_option_id: Annotated[ - str, - Field( - description="Unique identifier for this pricing option within the product (e.g., 'cpm_usd_guaranteed')" - ), - ] - pricing_model: Annotated[ - Literal["cpm"], Field(description="Cost per 1,000 impressions") - ] - rate: Annotated[ - float, Field(description="Fixed CPM rate (cost per 1,000 impressions)", ge=0.0) - ] - currency: Annotated[ - str, - Field( - description="ISO 4217 currency code", - examples=["USD", "EUR", "GBP", "JPY"], - pattern="^[A-Z]{3}$", - ), - ] - min_spend_per_package: Annotated[ - Optional[float], - Field( - description="Minimum spend requirement per package using this pricing option, in the specified currency", - ge=0.0, - ), - ] = None diff --git a/src/creative_agent/schemas_generated/_schemas_v1_pricing_options_cpp_option_json.py b/src/creative_agent/schemas_generated/_schemas_v1_pricing_options_cpp_option_json.py deleted file mode 100644 index a66350c..0000000 --- a/src/creative_agent/schemas_generated/_schemas_v1_pricing_options_cpp_option_json.py +++ /dev/null @@ -1,64 +0,0 @@ -# generated by datamodel-codegen: -# filename: _schemas_v1_pricing-options_cpp-option_json.json - -from __future__ import annotations - -from typing import Annotated, Literal, Optional - -from pydantic import BaseModel, ConfigDict, Field - - -class Parameters(BaseModel): - model_config = ConfigDict( - extra="forbid", - ) - demographic: Annotated[ - str, - Field( - description="Target demographic in Nielsen format: P/M/W/A/C + age range. Examples: P18-49 (Persons 18-49), M25-54 (Men 25-54), W35+ (Women 35+), A18-34 (Adults 18-34), C2-11 (Children 2-11)", - pattern="^[PMWAC][0-9]{2}(-[0-9]{2}|\\+)$", - ), - ] - min_points: Annotated[ - Optional[float], - Field(description="Minimum GRPs/TRPs required for this pricing option", ge=0.0), - ] = None - - -class CppPricingOption(BaseModel): - model_config = ConfigDict( - extra="forbid", - ) - pricing_option_id: Annotated[ - str, - Field( - description="Unique identifier for this pricing option within the product (e.g., 'cpp_usd_p18-49')" - ), - ] - pricing_model: Annotated[ - Literal["cpp"], Field(description="Cost per Gross Rating Point") - ] - rate: Annotated[ - float, Field(description="Fixed CPP rate (cost per rating point)", ge=0.0) - ] - currency: Annotated[ - str, - Field( - description="ISO 4217 currency code", - examples=["USD", "EUR", "GBP", "JPY"], - pattern="^[A-Z]{3}$", - ), - ] - parameters: Annotated[ - Parameters, - Field( - description="CPP-specific parameters for demographic targeting and GRP requirements" - ), - ] - min_spend_per_package: Annotated[ - Optional[float], - Field( - description="Minimum spend requirement per package using this pricing option, in the specified currency", - ge=0.0, - ), - ] = None diff --git a/src/creative_agent/schemas_generated/_schemas_v1_pricing_options_cpv_option_json.py b/src/creative_agent/schemas_generated/_schemas_v1_pricing_options_cpv_option_json.py deleted file mode 100644 index bb13444..0000000 --- a/src/creative_agent/schemas_generated/_schemas_v1_pricing_options_cpv_option_json.py +++ /dev/null @@ -1,74 +0,0 @@ -# generated by datamodel-codegen: -# filename: _schemas_v1_pricing-options_cpv-option_json.json - -from __future__ import annotations - -from typing import Annotated, Literal, Optional, Union - -from pydantic import BaseModel, ConfigDict, Field, RootModel - - -class ViewThreshold(RootModel[float]): - root: Annotated[ - float, - Field( - description="Percentage completion threshold for CPV pricing (0.0 to 1.0, e.g., 0.5 = 50% completion)", - ge=0.0, - le=1.0, - ), - ] - - -class ViewThreshold11(BaseModel): - model_config = ConfigDict( - extra="forbid", - ) - duration_seconds: Annotated[ - int, - Field( - description="Seconds of viewing required (e.g., 30 for YouTube-style '30 seconds = view')", - ge=1, - ), - ] - - -class Parameters(BaseModel): - model_config = ConfigDict( - extra="forbid", - ) - view_threshold: Union[ViewThreshold, ViewThreshold11] - - -class CpvPricingOption(BaseModel): - model_config = ConfigDict( - extra="forbid", - ) - pricing_option_id: Annotated[ - str, - Field( - description="Unique identifier for this pricing option within the product (e.g., 'cpv_usd_50pct')" - ), - ] - pricing_model: Annotated[ - Literal["cpv"], Field(description="Cost per view at threshold") - ] - rate: Annotated[float, Field(description="Fixed CPV rate (cost per view)", ge=0.0)] - currency: Annotated[ - str, - Field( - description="ISO 4217 currency code", - examples=["USD", "EUR", "GBP", "JPY"], - pattern="^[A-Z]{3}$", - ), - ] - parameters: Annotated[ - Parameters, - Field(description="CPV-specific parameters defining the view threshold"), - ] - min_spend_per_package: Annotated[ - Optional[float], - Field( - description="Minimum spend requirement per package using this pricing option, in the specified currency", - ge=0.0, - ), - ] = None diff --git a/src/creative_agent/schemas_generated/_schemas_v1_pricing_options_flat_rate_option_json.py b/src/creative_agent/schemas_generated/_schemas_v1_pricing_options_flat_rate_option_json.py deleted file mode 100644 index 7aabb95..0000000 --- a/src/creative_agent/schemas_generated/_schemas_v1_pricing_options_flat_rate_option_json.py +++ /dev/null @@ -1,101 +0,0 @@ -# generated by datamodel-codegen: -# filename: _schemas_v1_pricing-options_flat-rate-option_json.json - -from __future__ import annotations - -from typing import Annotated, Literal, Optional - -from pydantic import BaseModel, ConfigDict, Field - - -class Parameters(BaseModel): - model_config = ConfigDict( - extra="forbid", - ) - duration_hours: Annotated[ - Optional[float], - Field( - description="Duration in hours for time-based flat rate pricing (DOOH)", - ge=0.0, - ), - ] = None - sov_percentage: Annotated[ - Optional[float], - Field( - description="Guaranteed share of voice as percentage (DOOH, 0-100)", - ge=0.0, - le=100.0, - ), - ] = None - loop_duration_seconds: Annotated[ - Optional[int], - Field(description="Duration of ad loop rotation in seconds (DOOH)", ge=1), - ] = None - min_plays_per_hour: Annotated[ - Optional[int], - Field( - description="Minimum number of times ad plays per hour (DOOH frequency guarantee)", - ge=0, - ), - ] = None - venue_package: Annotated[ - Optional[str], - Field( - description="Named venue package identifier for DOOH (e.g., 'times_square_network', 'airport_terminals')" - ), - ] = None - estimated_impressions: Annotated[ - Optional[int], - Field( - description="Estimated impressions for this flat rate option (informational, commonly used with SOV or time-based DOOH)", - ge=0, - ), - ] = None - daypart: Annotated[ - Optional[str], - Field( - description="Specific daypart for time-based pricing (e.g., 'morning_commute', 'evening_prime', 'overnight')" - ), - ] = None - - -class FlatRatePricingOption(BaseModel): - model_config = ConfigDict( - extra="forbid", - ) - pricing_option_id: Annotated[ - str, - Field( - description="Unique identifier for this pricing option within the product (e.g., 'flat_rate_usd_24h_takeover')" - ), - ] - pricing_model: Annotated[ - Literal["flat_rate"], - Field(description="Fixed cost regardless of delivery volume"), - ] - rate: Annotated[float, Field(description="Flat rate cost", ge=0.0)] - currency: Annotated[ - str, - Field( - description="ISO 4217 currency code", - examples=["USD", "EUR", "GBP", "JPY"], - pattern="^[A-Z]{3}$", - ), - ] - is_fixed: Annotated[ - Literal[True], - Field( - description="Whether this is a fixed rate (true) or auction-based (false)" - ), - ] - parameters: Annotated[ - Optional[Parameters], - Field(description="Flat rate parameters for DOOH and time-based campaigns"), - ] = None - min_spend_per_package: Annotated[ - Optional[float], - Field( - description="Minimum spend requirement per package using this pricing option, in the specified currency", - ge=0.0, - ), - ] = None diff --git a/src/creative_agent/schemas_generated/_schemas_v1_signals_activate_signal_request_json.py b/src/creative_agent/schemas_generated/_schemas_v1_signals_activate_signal_request_json.py deleted file mode 100644 index b93e46b..0000000 --- a/src/creative_agent/schemas_generated/_schemas_v1_signals_activate_signal_request_json.py +++ /dev/null @@ -1,31 +0,0 @@ -# generated by datamodel-codegen: -# filename: _schemas_v1_signals_activate-signal-request_json.json - -from __future__ import annotations - -from typing import Annotated, Optional - -from pydantic import BaseModel, ConfigDict, Field - - -class ActivateSignalRequest(BaseModel): - model_config = ConfigDict( - extra="forbid", - ) - adcp_version: Annotated[ - Optional[str], - Field( - description="AdCP schema version for this request", - pattern="^\\d+\\.\\d+\\.\\d+$", - ), - ] = "1.5.0" - signal_agent_segment_id: Annotated[ - str, Field(description="The universal identifier for the signal to activate") - ] - platform: Annotated[str, Field(description="The target platform for activation")] - account: Annotated[ - Optional[str], - Field( - description="Account identifier (required for account-specific activation)" - ), - ] = None diff --git a/src/creative_agent/schemas_generated/_schemas_v1_signals_activate_signal_response_json.py b/src/creative_agent/schemas_generated/_schemas_v1_signals_activate_signal_response_json.py deleted file mode 100644 index 4a62c26..0000000 --- a/src/creative_agent/schemas_generated/_schemas_v1_signals_activate_signal_response_json.py +++ /dev/null @@ -1,75 +0,0 @@ -# generated by datamodel-codegen: -# filename: _schemas_v1_signals_activate-signal-response_json.json - -from __future__ import annotations - -from enum import Enum -from typing import Annotated, Any, Optional - -from pydantic import AwareDatetime, BaseModel, ConfigDict, Field - - -class Status(Enum): - pending = "pending" - processing = "processing" - deployed = "deployed" - failed = "failed" - - -class Error(BaseModel): - model_config = ConfigDict( - extra="forbid", - ) - code: Annotated[str, Field(description="Error code for programmatic handling")] - message: Annotated[str, Field(description="Human-readable error message")] - field: Annotated[ - Optional[str], - Field( - description="Field path associated with the error (e.g., 'packages[0].targeting')" - ), - ] = None - suggestion: Annotated[ - Optional[str], Field(description="Suggested fix for the error") - ] = None - retry_after: Annotated[ - Optional[float], - Field(description="Seconds to wait before retrying the operation", ge=0.0), - ] = None - details: Annotated[ - Optional[Any], Field(description="Additional task-specific error details") - ] = None - - -class ActivateSignalResponse(BaseModel): - model_config = ConfigDict( - extra="forbid", - ) - adcp_version: Annotated[ - str, - Field( - description="AdCP schema version used for this response", - pattern="^\\d+\\.\\d+\\.\\d+$", - ), - ] - task_id: Annotated[ - str, Field(description="Unique identifier for tracking the activation") - ] - status: Annotated[Status, Field(description="Current status")] - decisioning_platform_segment_id: Annotated[ - Optional[str], - Field(description="The platform-specific ID to use once activated"), - ] = None - estimated_activation_duration_minutes: Annotated[ - Optional[float], - Field(description="Estimated time to complete (optional)", ge=0.0), - ] = None - deployed_at: Annotated[ - Optional[AwareDatetime], - Field(description="Timestamp when activation completed (optional)"), - ] = None - errors: Annotated[ - Optional[list[Error]], - Field( - description="Task-specific errors and warnings (e.g., activation failures, platform issues)" - ), - ] = None diff --git a/src/creative_agent/schemas_generated/_schemas_v1_signals_get_signals_request_json.py b/src/creative_agent/schemas_generated/_schemas_v1_signals_get_signals_request_json.py deleted file mode 100644 index 8d3c62e..0000000 --- a/src/creative_agent/schemas_generated/_schemas_v1_signals_get_signals_request_json.py +++ /dev/null @@ -1,89 +0,0 @@ -# generated by datamodel-codegen: -# filename: _schemas_v1_signals_get-signals-request_json.json - -from __future__ import annotations - -from enum import Enum -from typing import Annotated, Optional, Union - -from pydantic import BaseModel, ConfigDict, Field, RootModel - - -class Account(BaseModel): - model_config = ConfigDict( - extra="forbid", - ) - platform: Annotated[str, Field(description="Platform identifier")] - account: Annotated[str, Field(description="Account identifier on that platform")] - - -class Country(RootModel[str]): - root: Annotated[str, Field(pattern="^[A-Z]{2}$")] - - -class DeliverTo(BaseModel): - model_config = ConfigDict( - extra="forbid", - ) - platforms: Annotated[ - Union[str, list[str]], - Field(description="Target platforms for signal deployment"), - ] - accounts: Annotated[ - Optional[list[Account]], - Field(description="Specific platform-account combinations"), - ] = None - countries: Annotated[ - list[Country], - Field(description="Countries where signals will be used (ISO codes)"), - ] - - -class CatalogType(Enum): - marketplace = "marketplace" - custom = "custom" - owned = "owned" - - -class Filters(BaseModel): - model_config = ConfigDict( - extra="forbid", - ) - catalog_types: Annotated[ - Optional[list[CatalogType]], Field(description="Filter by catalog type") - ] = None - data_providers: Annotated[ - Optional[list[str]], Field(description="Filter by specific data providers") - ] = None - max_cpm: Annotated[ - Optional[float], Field(description="Maximum CPM price filter", ge=0.0) - ] = None - min_coverage_percentage: Annotated[ - Optional[float], - Field(description="Minimum coverage requirement", ge=0.0, le=100.0), - ] = None - - -class GetSignalsRequest(BaseModel): - model_config = ConfigDict( - extra="forbid", - ) - adcp_version: Annotated[ - Optional[str], - Field( - description="AdCP schema version for this request", - pattern="^\\d+\\.\\d+\\.\\d+$", - ), - ] = "1.5.0" - signal_spec: Annotated[ - str, Field(description="Natural language description of the desired signals") - ] - deliver_to: Annotated[ - DeliverTo, Field(description="Where the signals need to be delivered") - ] - filters: Annotated[ - Optional[Filters], Field(description="Filters to refine results") - ] = None - max_results: Annotated[ - Optional[int], Field(description="Maximum number of results to return", ge=1) - ] = None diff --git a/src/creative_agent/schemas_generated/_schemas_v1_signals_get_signals_response_json.py b/src/creative_agent/schemas_generated/_schemas_v1_signals_get_signals_response_json.py deleted file mode 100644 index c9ffd4e..0000000 --- a/src/creative_agent/schemas_generated/_schemas_v1_signals_get_signals_response_json.py +++ /dev/null @@ -1,116 +0,0 @@ -# generated by datamodel-codegen: -# filename: _schemas_v1_signals_get-signals-response_json.json - -from __future__ import annotations - -from enum import Enum -from typing import Annotated, Any, Optional - -from pydantic import BaseModel, ConfigDict, Field - - -class SignalType(Enum): - marketplace = "marketplace" - custom = "custom" - owned = "owned" - - -class Scope(Enum): - platform_wide = "platform-wide" - account_specific = "account-specific" - - -class Deployment(BaseModel): - model_config = ConfigDict( - extra="forbid", - ) - platform: Annotated[str, Field(description="Platform name")] - account: Annotated[ - Optional[str], Field(description="Specific account if applicable") - ] = None - is_live: Annotated[bool, Field(description="Whether signal is currently active")] - scope: Annotated[Scope, Field(description="Deployment scope")] - decisioning_platform_segment_id: Annotated[ - Optional[str], Field(description="Platform-specific segment ID") - ] = None - estimated_activation_duration_minutes: Annotated[ - Optional[float], Field(description="Time to activate if not live", ge=0.0) - ] = None - - -class Pricing(BaseModel): - model_config = ConfigDict( - extra="forbid", - ) - cpm: Annotated[float, Field(description="Cost per thousand impressions", ge=0.0)] - currency: Annotated[str, Field(description="Currency code", pattern="^[A-Z]{3}$")] - - -class Signal(BaseModel): - model_config = ConfigDict( - extra="forbid", - ) - signal_agent_segment_id: Annotated[ - str, Field(description="Unique identifier for the signal") - ] - name: Annotated[str, Field(description="Human-readable signal name")] - description: Annotated[str, Field(description="Detailed signal description")] - signal_type: Annotated[SignalType, Field(description="Type of signal")] - data_provider: Annotated[str, Field(description="Name of the data provider")] - coverage_percentage: Annotated[ - float, Field(description="Percentage of audience coverage", ge=0.0, le=100.0) - ] - deployments: Annotated[ - list[Deployment], Field(description="Array of platform deployments") - ] - pricing: Annotated[Pricing, Field(description="Pricing information")] - - -class Error(BaseModel): - model_config = ConfigDict( - extra="forbid", - ) - code: Annotated[str, Field(description="Error code for programmatic handling")] - message: Annotated[str, Field(description="Human-readable error message")] - field: Annotated[ - Optional[str], - Field( - description="Field path associated with the error (e.g., 'packages[0].targeting')" - ), - ] = None - suggestion: Annotated[ - Optional[str], Field(description="Suggested fix for the error") - ] = None - retry_after: Annotated[ - Optional[float], - Field(description="Seconds to wait before retrying the operation", ge=0.0), - ] = None - details: Annotated[ - Optional[Any], Field(description="Additional task-specific error details") - ] = None - - -class GetSignalsResponse(BaseModel): - model_config = ConfigDict( - extra="forbid", - ) - adcp_version: Annotated[ - str, - Field( - description="AdCP schema version used for this response", - pattern="^\\d+\\.\\d+\\.\\d+$", - ), - ] - message: Annotated[ - str, Field(description="Human-readable summary of the signal discovery results") - ] - context_id: Annotated[ - str, Field(description="Session continuity identifier for follow-up requests") - ] - signals: Annotated[list[Signal], Field(description="Array of matching signals")] - errors: Annotated[ - Optional[list[Error]], - Field( - description="Task-specific errors and warnings (e.g., signal discovery or pricing issues)" - ), - ] = None diff --git a/tests/schema_compliance/__init__.py b/tests/schema_compliance/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/tests/schema_compliance/test_format_schema_compliance.py b/tests/schema_compliance/test_format_schema_compliance.py new file mode 100644 index 0000000..ab296e4 --- /dev/null +++ b/tests/schema_compliance/test_format_schema_compliance.py @@ -0,0 +1,133 @@ +""" +Test that our format responses actually match the AdCP schemas. + +When schemas change, these tests ensure our code stays in sync. +""" + +import pytest +from pydantic import ValidationError + +from src.creative_agent.data.standard_formats import STANDARD_FORMATS +from src.creative_agent.schemas import CreativeFormat, ListCreativeFormatsResponse + + +def test_all_standard_formats_validate_against_schema(): + """Every format in STANDARD_FORMATS must validate against the Format schema.""" + errors = [] + + for format_obj in STANDARD_FORMATS: + try: + # Convert Pydantic model to dict and validate + format_dict = format_obj.model_dump(mode="json", by_alias=True, exclude_none=True) + CreativeFormat.model_validate(format_dict) + except ValidationError as e: + errors.append(f"Format {format_obj.format_id} failed validation:\n{e}") + + if errors: + pytest.fail("\n\n".join(errors)) + + +def test_list_creative_formats_response_validates(): + """The response from list_creative_formats must validate against schema.""" + from src.creative_agent.data.standard_formats import AGENT_CAPABILITIES, AGENT_NAME + + # Build the response structure that list_creative_formats returns + response_data = { + "formats": [fmt.model_dump(mode="json", by_alias=True, exclude_none=True) for fmt in STANDARD_FORMATS], + "creative_agents": [ + { + "agent_url": "https://creative.adcontextprotocol.org", + "agent_name": AGENT_NAME, + "capabilities": AGENT_CAPABILITIES, + } + ], + } + + # Validate against schema + try: + ListCreativeFormatsResponse.model_validate(response_data) + except ValidationError as e: + pytest.fail(f"list_creative_formats response failed schema validation:\n{e}") + + +def test_format_has_required_fields(): + """Ensure all formats have required fields per schema.""" + required_fields = {"format_id", "name", "type"} + + for format_obj in STANDARD_FORMATS: + format_dict = format_obj.model_dump(mode="json", by_alias=True, exclude_none=True) + missing = required_fields - set(format_dict.keys()) + if missing: + pytest.fail(f"Format {format_obj.format_id} missing required fields: {missing}") + + +def test_output_format_ids_are_strings(): + """ + Verify that output_format_ids use string format IDs (per schema). + + Note: Format.output_format_ids uses strings (same agent assumed), + while Product.format_ids uses structured {agent_url, id} objects. + """ + for format_obj in STANDARD_FORMATS: + format_dict = format_obj.model_dump(mode="json", by_alias=True, exclude_none=True) + # Check output_format_ids if present + if "output_format_ids" in format_dict: + output_ids = format_dict["output_format_ids"] + if output_ids: # Skip if empty list + # Each should be a string per Format schema + for idx, output_id in enumerate(output_ids): + if not isinstance(output_id, str): + pytest.fail( + f"Format {format_obj.format_id} output_format_ids[{idx}] is not a string: {output_id}. " + "Per schema, output_format_ids items should be strings (format_id within same agent)." + ) + + +def test_asset_requirements_match_schema(): + """Verify assets_required field structure matches schema.""" + for format_obj in STANDARD_FORMATS: + format_dict = format_obj.model_dump(mode="json", by_alias=True, exclude_none=True) + if "assets_required" not in format_dict: + continue + + for idx, asset_req in enumerate(format_dict["assets_required"]): + # Check if it's a repeatable group + if "repeatable" in asset_req: + required_group_fields = {"asset_group_id", "repeatable", "min_count", "max_count", "assets"} + missing = required_group_fields - set(asset_req.keys()) + if missing: + pytest.fail( + f"Format {format_obj.format_id} asset_required[{idx}] is repeatable but missing: {missing}" + ) + else: + # Individual asset + required_asset_fields = {"asset_id", "asset_type"} + missing = required_asset_fields - set(asset_req.keys()) + if missing: + pytest.fail( + f"Format {format_obj.format_id} asset_required[{idx}] missing required fields: {missing}" + ) + + +def test_enum_values_match_schema(): + """Verify enum values match what's in the schema.""" + valid_types = {"audio", "video", "display", "native", "dooh", "rich_media", "universal"} + valid_categories = {"standard", "custom"} + + for format_obj in STANDARD_FORMATS: + format_dict = format_obj.model_dump(mode="json", by_alias=True, exclude_none=True) + # Check type enum + if "type" in format_dict: + if format_dict["type"] not in valid_types: + pytest.fail( + f"Format {format_obj.format_id} has invalid type '{format_dict['type']}'. " + f"Valid types: {valid_types}" + ) + + # Check category enum + if "category" in format_dict: + if format_dict["category"] not in valid_categories: + pytest.fail( + f"Format {format_obj.format_id} has invalid category '{format_dict['category']}'. " + f"Valid categories: {valid_categories}" + ) diff --git a/tests/schemas/v1/_schemas_v1_core_budget_json.json b/tests/schemas/v1/_schemas_v1_core_budget_json.json deleted file mode 100644 index e08ed53..0000000 --- a/tests/schemas/v1/_schemas_v1_core_budget_json.json +++ /dev/null @@ -1,32 +0,0 @@ -{ - "$schema": "http://json-schema.org/draft-07/schema#", - "$id": "/schemas/v1/core/budget.json", - "title": "Budget", - "description": "Budget configuration for a media buy or package", - "type": "object", - "properties": { - "total": { - "type": "number", - "description": "Total budget amount", - "minimum": 0 - }, - "currency": { - "type": "string", - "description": "ISO 4217 currency code", - "pattern": "^[A-Z]{3}$", - "examples": [ - "USD", - "EUR", - "GBP" - ] - }, - "pacing": { - "$ref": "/schemas/v1/enums/pacing.json" - } - }, - "required": [ - "total", - "currency" - ], - "additionalProperties": false -} diff --git a/tests/schemas/v1/_schemas_v1_core_creative-manifest_json.json b/tests/schemas/v1/_schemas_v1_core_creative-manifest_json.json new file mode 100644 index 0000000..ba3757d --- /dev/null +++ b/tests/schemas/v1/_schemas_v1_core_creative-manifest_json.json @@ -0,0 +1,514 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$id": "/schemas/v1/core/creative-manifest.json", + "title": "Creative Manifest", + "description": "Complete specification of a creative with all assets needed for rendering in a specific format. Each asset is typed according to its asset_role from the format specification and contains the actual content/URL that fulfills the format requirements.", + "type": "object", + "properties": { + "format_id": { + "$ref": "/schemas/v1/core/format-id.json", + "description": "Format identifier this manifest is for" + }, + "promoted_offering": { + "type": "string", + "description": "Product name or offering being advertised. Maps to promoted_offerings in create_media_buy request to associate creative with the product being promoted." + }, + "assets": { + "type": "object", + "description": "Map of asset roles (from format spec) to actual asset content. Each key is an asset_role defined by the format (e.g., 'hero_image', 'logo', 'headline', 'video_file', 'vast_tag').", + "patternProperties": { + "^[a-z0-9_]+$": { + "oneOf": [ + { + "type": "object", + "description": "Image asset with hosted URL", + "properties": { + "asset_type": { + "type": "string", + "const": "image" + }, + "url": { + "type": "string", + "format": "uri", + "description": "URL to hosted image asset" + }, + "width": { + "type": "integer", + "minimum": 1, + "description": "Image width in pixels" + }, + "height": { + "type": "integer", + "minimum": 1, + "description": "Image height in pixels" + }, + "format": { + "type": "string", + "enum": [ + "jpg", + "jpeg", + "png", + "gif", + "webp", + "svg" + ], + "description": "Image file format" + }, + "file_size": { + "type": "integer", + "minimum": 0, + "description": "File size in bytes" + }, + "alt": { + "type": "string", + "description": "Alternative text for accessibility" + } + }, + "required": [ + "asset_type", + "url", + "width", + "height" + ], + "additionalProperties": false + }, + { + "type": "object", + "description": "Video asset with hosted URL", + "properties": { + "asset_type": { + "type": "string", + "const": "video" + }, + "url": { + "type": "string", + "format": "uri", + "description": "URL to hosted video asset" + }, + "width": { + "type": "integer", + "minimum": 1, + "description": "Video width in pixels" + }, + "height": { + "type": "integer", + "minimum": 1, + "description": "Video height in pixels" + }, + "duration_seconds": { + "type": "number", + "minimum": 0, + "description": "Video duration in seconds" + }, + "format": { + "type": "string", + "enum": [ + "mp4", + "webm", + "mov" + ], + "description": "Video container format" + }, + "codec": { + "type": "string", + "enum": [ + "h264", + "h265", + "vp8", + "vp9", + "av1" + ], + "description": "Video codec" + }, + "bitrate_mbps": { + "type": "number", + "minimum": 0, + "description": "Video bitrate in Mbps" + }, + "file_size": { + "type": "integer", + "minimum": 0, + "description": "File size in bytes" + }, + "aspect_ratio": { + "type": "string", + "pattern": "^\\d+:\\d+$", + "description": "Aspect ratio (e.g., '16:9', '9:16')" + } + }, + "required": [ + "asset_type", + "url", + "width", + "height", + "duration_seconds" + ], + "additionalProperties": false + }, + { + "type": "object", + "description": "Audio asset with hosted URL", + "properties": { + "asset_type": { + "type": "string", + "const": "audio" + }, + "url": { + "type": "string", + "format": "uri", + "description": "URL to hosted audio asset" + }, + "duration_seconds": { + "type": "number", + "minimum": 0, + "description": "Audio duration in seconds" + }, + "format": { + "type": "string", + "enum": [ + "mp3", + "aac", + "m4a", + "wav", + "ogg" + ], + "description": "Audio file format" + }, + "codec": { + "type": "string", + "enum": [ + "mp3", + "aac", + "opus", + "vorbis" + ], + "description": "Audio codec" + }, + "bitrate_kbps": { + "type": "number", + "minimum": 0, + "description": "Audio bitrate in Kbps" + }, + "sample_rate_hz": { + "type": "integer", + "enum": [ + 22050, + 44100, + 48000, + 96000 + ], + "description": "Sample rate in Hz" + }, + "channels": { + "type": "string", + "enum": [ + "mono", + "stereo", + "5.1", + "7.1" + ], + "description": "Audio channel configuration" + }, + "file_size": { + "type": "integer", + "minimum": 0, + "description": "File size in bytes" + } + }, + "required": [ + "asset_type", + "url", + "duration_seconds" + ], + "additionalProperties": false + }, + { + "type": "object", + "description": "VAST XML tag for third-party video serving", + "properties": { + "asset_type": { + "type": "string", + "const": "vast_tag" + }, + "content": { + "type": "string", + "description": "Complete VAST XML content" + }, + "vast_version": { + "type": "string", + "enum": [ + "2.0", + "3.0", + "4.0", + "4.1", + "4.2" + ], + "description": "VAST specification version" + }, + "vpaid_enabled": { + "type": "boolean", + "description": "Whether VPAID is used" + }, + "duration_seconds": { + "type": "number", + "minimum": 0, + "description": "Expected video duration in seconds" + } + }, + "required": [ + "asset_type", + "content", + "vast_version" + ], + "additionalProperties": false + }, + { + "type": "object", + "description": "Text content asset", + "properties": { + "asset_type": { + "type": "string", + "const": "text" + }, + "content": { + "type": "string", + "description": "Text content" + }, + "length": { + "type": "integer", + "minimum": 0, + "description": "Character count" + }, + "format": { + "type": "string", + "enum": [ + "plain", + "html", + "markdown" + ], + "default": "plain", + "description": "Text format" + } + }, + "required": [ + "asset_type", + "content" + ], + "additionalProperties": false + }, + { + "type": "object", + "description": "URL asset for clickthrough, tracking, etc.", + "properties": { + "asset_type": { + "type": "string", + "const": "url" + }, + "url": { + "type": "string", + "format": "uri", + "description": "The URL" + }, + "purpose": { + "type": "string", + "enum": [ + "clickthrough", + "landing_page", + "tracking_pixel", + "impression_tracker" + ], + "description": "Purpose of this URL" + } + }, + "required": [ + "asset_type", + "url" + ], + "additionalProperties": false + }, + { + "type": "object", + "description": "Webhook for server-side dynamic content rendering", + "properties": { + "asset_type": { + "type": "string", + "const": "webhook" + }, + "url": { + "type": "string", + "format": "uri", + "description": "Webhook URL to call for dynamic content" + }, + "method": { + "type": "string", + "enum": [ + "GET", + "POST" + ], + "default": "POST" + }, + "timeout_ms": { + "type": "integer", + "minimum": 10, + "maximum": 5000, + "default": 500 + }, + "supported_macros": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Universal macros that can be passed to webhook" + }, + "required_macros": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Universal macros that must be provided" + }, + "response_type": { + "type": "string", + "enum": [ + "html", + "json", + "xml", + "javascript" + ] + }, + "security": { + "type": "object", + "properties": { + "method": { + "type": "string", + "enum": [ + "hmac_sha256", + "api_key", + "none" + ] + }, + "hmac_header": { + "type": "string" + }, + "api_key_header": { + "type": "string" + } + }, + "required": [ + "method" + ] + }, + "fallback_required": { + "type": "boolean", + "default": true + } + }, + "required": [ + "asset_type", + "url", + "response_type", + "security" + ], + "additionalProperties": false + }, + { + "type": "object", + "description": "HTML5 creative asset", + "properties": { + "asset_type": { + "type": "string", + "const": "html" + }, + "content": { + "type": "string", + "description": "Complete HTML content" + }, + "url": { + "type": "string", + "format": "uri", + "description": "URL to externally hosted HTML file" + }, + "width": { + "type": "integer", + "minimum": 1, + "description": "Ad width in pixels" + }, + "height": { + "type": "integer", + "minimum": 1, + "description": "Ad height in pixels" + }, + "file_size": { + "type": "integer", + "minimum": 0, + "description": "Total file size in bytes" + } + }, + "required": [ + "asset_type" + ], + "oneOf": [ + { + "required": [ + "content" + ] + }, + { + "required": [ + "url" + ] + } + ], + "additionalProperties": false + }, + { + "type": "object", + "description": "JavaScript code asset", + "properties": { + "asset_type": { + "type": "string", + "const": "javascript" + }, + "content": { + "type": "string", + "description": "JavaScript code content" + }, + "url": { + "type": "string", + "format": "uri", + "description": "URL to external JavaScript file" + }, + "inline": { + "type": "boolean", + "description": "Whether code should be inlined vs external script tag" + } + }, + "required": [ + "asset_type" + ], + "oneOf": [ + { + "required": [ + "content" + ] + }, + { + "required": [ + "url" + ] + } + ], + "additionalProperties": false + } + ] + } + }, + "additionalProperties": false + } + }, + "required": [ + "format_id", + "assets" + ], + "additionalProperties": false +} diff --git a/tests/schemas/v1/_schemas_v1_core_delivery-metrics_json.json b/tests/schemas/v1/_schemas_v1_core_delivery-metrics_json.json deleted file mode 100644 index efd6623..0000000 --- a/tests/schemas/v1/_schemas_v1_core_delivery-metrics_json.json +++ /dev/null @@ -1,176 +0,0 @@ -{ - "$schema": "http://json-schema.org/draft-07/schema#", - "$id": "/schemas/v1/core/delivery-metrics.json", - "title": "Delivery Metrics", - "description": "Standard delivery metrics that can be reported at media buy, package, or creative level", - "type": "object", - "properties": { - "impressions": { - "type": "number", - "description": "Impressions delivered", - "minimum": 0 - }, - "spend": { - "type": "number", - "description": "Amount spent", - "minimum": 0 - }, - "clicks": { - "type": "number", - "description": "Total clicks", - "minimum": 0 - }, - "ctr": { - "type": "number", - "description": "Click-through rate (clicks/impressions)", - "minimum": 0, - "maximum": 1 - }, - "views": { - "type": "number", - "description": "Views at threshold (for CPV)", - "minimum": 0 - }, - "completed_views": { - "type": "number", - "description": "100% completions (for CPCV)", - "minimum": 0 - }, - "video_completions": { - "type": "number", - "description": "DEPRECATED: Use completed_views instead", - "minimum": 0 - }, - "completion_rate": { - "type": "number", - "description": "Completion rate (completed_views/impressions)", - "minimum": 0, - "maximum": 1 - }, - "conversions": { - "type": "number", - "description": "Conversions (reserved for future CPA pricing support)", - "minimum": 0 - }, - "leads": { - "type": "number", - "description": "Leads generated (reserved for future CPL pricing support)", - "minimum": 0 - }, - "grps": { - "type": "number", - "description": "Gross Rating Points delivered (for CPP)", - "minimum": 0 - }, - "reach": { - "type": "number", - "description": "Unique reach - units depend on measurement provider (e.g., individuals, households, devices, cookies). See delivery_measurement.provider for methodology.", - "minimum": 0 - }, - "frequency": { - "type": "number", - "description": "Average frequency per individual (typically measured over campaign duration, but can vary by measurement provider)", - "minimum": 0 - }, - "quartile_data": { - "type": "object", - "description": "Video quartile completion data", - "properties": { - "q1_views": { - "type": "number", - "description": "25% completion views", - "minimum": 0 - }, - "q2_views": { - "type": "number", - "description": "50% completion views", - "minimum": 0 - }, - "q3_views": { - "type": "number", - "description": "75% completion views", - "minimum": 0 - }, - "q4_views": { - "type": "number", - "description": "100% completion views", - "minimum": 0 - } - } - }, - "dooh_metrics": { - "type": "object", - "description": "DOOH-specific metrics (only included for DOOH campaigns)", - "properties": { - "loop_plays": { - "type": "integer", - "description": "Number of times ad played in rotation", - "minimum": 0 - }, - "screens_used": { - "type": "integer", - "description": "Number of unique screens displaying the ad", - "minimum": 0 - }, - "screen_time_seconds": { - "type": "integer", - "description": "Total display time in seconds", - "minimum": 0 - }, - "sov_achieved": { - "type": "number", - "description": "Actual share of voice delivered (0.0 to 1.0)", - "minimum": 0, - "maximum": 1 - }, - "calculation_notes": { - "type": "string", - "description": "Explanation of how DOOH impressions were calculated" - }, - "venue_breakdown": { - "type": "array", - "description": "Per-venue performance breakdown", - "items": { - "type": "object", - "properties": { - "venue_id": { - "type": "string", - "description": "Venue identifier" - }, - "venue_name": { - "type": "string", - "description": "Human-readable venue name" - }, - "venue_type": { - "type": "string", - "description": "Venue type (e.g., 'airport', 'transit', 'retail', 'billboard')" - }, - "impressions": { - "type": "integer", - "description": "Impressions delivered at this venue", - "minimum": 0 - }, - "loop_plays": { - "type": "integer", - "description": "Loop plays at this venue", - "minimum": 0 - }, - "screens_used": { - "type": "integer", - "description": "Number of screens used at this venue", - "minimum": 0 - } - }, - "required": [ - "venue_id", - "impressions" - ], - "additionalProperties": false - } - } - }, - "additionalProperties": false - } - }, - "additionalProperties": true -} diff --git a/tests/schemas/v1/_schemas_v1_core_frequency-cap_json.json b/tests/schemas/v1/_schemas_v1_core_frequency-cap_json.json deleted file mode 100644 index 3710095..0000000 --- a/tests/schemas/v1/_schemas_v1_core_frequency-cap_json.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "$schema": "http://json-schema.org/draft-07/schema#", - "$id": "/schemas/v1/core/frequency-cap.json", - "title": "Frequency Cap", - "description": "Frequency capping settings for package-level application", - "type": "object", - "properties": { - "suppress_minutes": { - "type": "number", - "description": "Minutes to suppress after impression", - "minimum": 0 - } - }, - "required": [ - "suppress_minutes" - ], - "additionalProperties": false -} diff --git a/tests/schemas/v1/_schemas_v1_core_measurement_json.json b/tests/schemas/v1/_schemas_v1_core_measurement_json.json deleted file mode 100644 index 6885f37..0000000 --- a/tests/schemas/v1/_schemas_v1_core_measurement_json.json +++ /dev/null @@ -1,48 +0,0 @@ -{ - "$schema": "http://json-schema.org/draft-07/schema#", - "$id": "/schemas/v1/core/measurement.json", - "title": "Measurement", - "description": "Measurement capabilities included with a product", - "type": "object", - "properties": { - "type": { - "type": "string", - "description": "Type of measurement", - "examples": [ - "incremental_sales_lift", - "brand_lift", - "foot_traffic" - ] - }, - "attribution": { - "type": "string", - "description": "Attribution methodology", - "examples": [ - "deterministic_purchase", - "probabilistic" - ] - }, - "window": { - "type": "string", - "description": "Attribution window", - "examples": [ - "30_days", - "7_days" - ] - }, - "reporting": { - "type": "string", - "description": "Reporting frequency and format", - "examples": [ - "weekly_dashboard", - "real_time_api" - ] - } - }, - "required": [ - "type", - "attribution", - "reporting" - ], - "additionalProperties": false -} diff --git a/tests/schemas/v1/_schemas_v1_core_media-buy_json.json b/tests/schemas/v1/_schemas_v1_core_media-buy_json.json deleted file mode 100644 index 3a96502..0000000 --- a/tests/schemas/v1/_schemas_v1_core_media-buy_json.json +++ /dev/null @@ -1,59 +0,0 @@ -{ - "$schema": "http://json-schema.org/draft-07/schema#", - "$id": "/schemas/v1/core/media-buy.json", - "title": "Media Buy", - "description": "Represents a purchased advertising campaign", - "type": "object", - "properties": { - "media_buy_id": { - "type": "string", - "description": "Publisher's unique identifier for the media buy" - }, - "buyer_ref": { - "type": "string", - "description": "Buyer's reference identifier for this media buy" - }, - "status": { - "$ref": "/schemas/v1/enums/media-buy-status.json" - }, - "promoted_offering": { - "type": "string", - "description": "Description of advertiser and what is being promoted" - }, - "total_budget": { - "type": "number", - "description": "Total budget amount", - "minimum": 0 - }, - "packages": { - "type": "array", - "description": "Array of packages within this media buy", - "items": { - "$ref": "/schemas/v1/core/package.json" - } - }, - "creative_deadline": { - "type": "string", - "format": "date-time", - "description": "ISO 8601 timestamp for creative upload deadline" - }, - "created_at": { - "type": "string", - "format": "date-time", - "description": "Creation timestamp" - }, - "updated_at": { - "type": "string", - "format": "date-time", - "description": "Last update timestamp" - } - }, - "required": [ - "media_buy_id", - "status", - "promoted_offering", - "total_budget", - "packages" - ], - "additionalProperties": false -} diff --git a/tests/schemas/v1/_schemas_v1_core_package_json.json b/tests/schemas/v1/_schemas_v1_core_package_json.json deleted file mode 100644 index dae365d..0000000 --- a/tests/schemas/v1/_schemas_v1_core_package_json.json +++ /dev/null @@ -1,56 +0,0 @@ -{ - "$schema": "http://json-schema.org/draft-07/schema#", - "$id": "/schemas/v1/core/package.json", - "title": "Package", - "description": "A specific product within a media buy (line item)", - "type": "object", - "properties": { - "package_id": { - "type": "string", - "description": "Publisher's unique identifier for the package" - }, - "buyer_ref": { - "type": "string", - "description": "Buyer's reference identifier for this package" - }, - "product_id": { - "type": "string", - "description": "ID of the product this package is based on" - }, - "budget": { - "type": "number", - "description": "Budget allocation for this package in the currency specified by the pricing option", - "minimum": 0 - }, - "impressions": { - "type": "number", - "description": "Impression goal for this package", - "minimum": 0 - }, - "targeting_overlay": { - "$ref": "/schemas/v1/core/targeting.json" - }, - "creative_assignments": { - "type": "array", - "description": "Creative assets assigned to this package", - "items": { - "$ref": "/schemas/v1/core/creative-assignment.json" - } - }, - "formats_to_provide": { - "type": "array", - "description": "Format IDs that creative assets will be provided for this package", - "items": { - "type": "string" - } - }, - "status": { - "$ref": "/schemas/v1/enums/package-status.json" - } - }, - "required": [ - "package_id", - "status" - ], - "additionalProperties": false -} diff --git a/tests/schemas/v1/_schemas_v1_core_pricing-option_json.json b/tests/schemas/v1/_schemas_v1_core_pricing-option_json.json deleted file mode 100644 index 7e88efc..0000000 --- a/tests/schemas/v1/_schemas_v1_core_pricing-option_json.json +++ /dev/null @@ -1,29 +0,0 @@ -{ - "$schema": "http://json-schema.org/draft-07/schema#", - "$id": "/schemas/v1/core/pricing-option.json", - "title": "Pricing Option", - "description": "A pricing model option offered by a publisher for a product. Each pricing model has its own schema with model-specific requirements.", - "oneOf": [ - { - "$ref": "/schemas/v1/pricing-options/cpm-fixed-option.json" - }, - { - "$ref": "/schemas/v1/pricing-options/cpm-auction-option.json" - }, - { - "$ref": "/schemas/v1/pricing-options/cpc-option.json" - }, - { - "$ref": "/schemas/v1/pricing-options/cpcv-option.json" - }, - { - "$ref": "/schemas/v1/pricing-options/cpv-option.json" - }, - { - "$ref": "/schemas/v1/pricing-options/cpp-option.json" - }, - { - "$ref": "/schemas/v1/pricing-options/flat-rate-option.json" - } - ] -} diff --git a/tests/schemas/v1/_schemas_v1_core_product_json.json b/tests/schemas/v1/_schemas_v1_core_product_json.json deleted file mode 100644 index 87807e1..0000000 --- a/tests/schemas/v1/_schemas_v1_core_product_json.json +++ /dev/null @@ -1,124 +0,0 @@ -{ - "$schema": "http://json-schema.org/draft-07/schema#", - "$id": "/schemas/v1/core/product.json", - "title": "Product", - "description": "Represents available advertising inventory", - "type": "object", - "properties": { - "product_id": { - "type": "string", - "description": "Unique identifier for the product" - }, - "name": { - "type": "string", - "description": "Human-readable product name" - }, - "description": { - "type": "string", - "description": "Detailed description of the product and its inventory" - }, - "properties": { - "type": "array", - "description": "Array of advertising properties covered by this product for adagents.json validation", - "items": { - "$ref": "/schemas/v1/core/property.json" - }, - "minItems": 1 - }, - "property_tags": { - "type": "array", - "description": "Tags identifying groups of properties covered by this product (use list_authorized_properties to get full property details)", - "items": { - "type": "string", - "pattern": "^[a-z0-9_]+$", - "description": "Lowercase tag with underscores (e.g., 'local_radio', 'premium_content')" - }, - "minItems": 1 - }, - "format_ids": { - "type": "array", - "description": "Array of supported creative format IDs - use list_creative_formats to get full format details", - "items": { - "type": "string", - "description": "Format ID referencing a format from list_creative_formats" - } - }, - "delivery_type": { - "$ref": "/schemas/v1/enums/delivery-type.json" - }, - "pricing_options": { - "type": "array", - "description": "Available pricing models for this product", - "items": { - "$ref": "/schemas/v1/core/pricing-option.json" - }, - "minItems": 1 - }, - "estimated_exposures": { - "type": "integer", - "description": "Estimated exposures/impressions for guaranteed products", - "minimum": 0 - }, - "measurement": { - "$ref": "/schemas/v1/core/measurement.json" - }, - "delivery_measurement": { - "type": "object", - "description": "Measurement provider and methodology for delivery metrics. The buyer accepts the declared provider as the source of truth for the buy. REQUIRED for all products.", - "properties": { - "provider": { - "type": "string", - "description": "Measurement provider(s) used for this product (e.g., 'Google Ad Manager with IAS viewability', 'Nielsen DAR', 'Geopath for DOOH impressions')" - }, - "notes": { - "type": "string", - "description": "Additional details about measurement methodology in plain language (e.g., 'MRC-accredited viewability. 50% in-view for 1s display / 2s video', 'Panel-based demographic measurement updated monthly')" - } - }, - "required": [ - "provider" - ] - }, - "reporting_capabilities": { - "$ref": "/schemas/v1/core/reporting-capabilities.json" - }, - "creative_policy": { - "$ref": "/schemas/v1/core/creative-policy.json" - }, - "is_custom": { - "type": "boolean", - "description": "Whether this is a custom product" - }, - "brief_relevance": { - "type": "string", - "description": "Explanation of why this product matches the brief (only included when brief is provided)" - }, - "expires_at": { - "type": "string", - "format": "date-time", - "description": "Expiration timestamp for custom products" - } - }, - "oneOf": [ - { - "required": [ - "properties" - ] - }, - { - "required": [ - "property_tags" - ] - } - ], - "required": [ - "product_id", - "name", - "description", - "format_ids", - "delivery_type", - "delivery_measurement", - "pricing_options" - ], - "additionalProperties": false -} diff --git a/tests/schemas/v1/_schemas_v1_core_promoted-offerings_json.json b/tests/schemas/v1/_schemas_v1_core_promoted-offerings_json.json new file mode 100644 index 0000000..6fdeb1f --- /dev/null +++ b/tests/schemas/v1/_schemas_v1_core_promoted-offerings_json.json @@ -0,0 +1,110 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$id": "/schemas/v1/core/promoted-offerings.json", + "title": "Promoted Offerings", + "description": "Complete offering specification combining brand manifest, product selectors, and asset filters. Provides all context needed for creative generation about what is being promoted.", + "type": "object", + "properties": { + "brand_manifest": { + "$ref": "/schemas/v1/core/brand-manifest-ref.json", + "description": "Brand information manifest containing assets, themes, and guidelines. Can be provided inline or as a URL reference to a hosted manifest." + }, + "product_selectors": { + "$ref": "/schemas/v1/core/promoted-products.json", + "description": "Selectors to choose which products/offerings from the brand manifest product catalog to promote" + }, + "offerings": { + "type": "array", + "description": "Inline offerings for campaigns without a product catalog. Each offering has a name, description, and associated assets.", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "description": "Offering name (e.g., 'Winter Sale', 'New Product Launch')" + }, + "description": { + "type": "string", + "description": "Description of what's being offered" + }, + "assets": { + "type": "array", + "description": "Assets specific to this offering", + "items": { + "type": "object", + "description": "Asset definition using standard asset structure", + "additionalProperties": true + } + } + }, + "required": [ + "name" + ], + "additionalProperties": false + } + }, + "asset_selectors": { + "type": "object", + "description": "Selectors to choose specific assets from the brand manifest", + "properties": { + "tags": { + "type": "array", + "description": "Select assets with specific tags (e.g., ['holiday', 'premium'])", + "items": { + "type": "string" + } + }, + "asset_types": { + "type": "array", + "description": "Filter by asset type (e.g., ['image', 'video'])", + "items": { + "type": "string", + "enum": [ + "image", + "video", + "audio", + "text", + "html", + "css", + "javascript" + ] + } + }, + "exclude_tags": { + "type": "array", + "description": "Exclude assets with these tags", + "items": { + "type": "string" + } + } + }, + "additionalProperties": false + } + }, + "required": [ + "brand_manifest" + ], + "additionalProperties": false, + "examples": [ + { + "brand_manifest": { + "url": "https://brand.com" + }, + "product_selectors": { + "manifest_skus": [ + "SKU-123", + "SKU-456" + ] + }, + "asset_selectors": { + "tags": [ + "holiday" + ], + "asset_types": [ + "image", + "video" + ] + } + } + ] +} diff --git a/tests/schemas/v1/_schemas_v1_core_promoted-products_json.json b/tests/schemas/v1/_schemas_v1_core_promoted-products_json.json new file mode 100644 index 0000000..b3cb1e9 --- /dev/null +++ b/tests/schemas/v1/_schemas_v1_core_promoted-products_json.json @@ -0,0 +1,67 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$id": "/schemas/v1/core/promoted-products.json", + "title": "Promoted Products", + "description": "Specification of products or offerings being promoted in a campaign. Supports multiple selection methods from the brand manifest that can be combined using UNION (OR) logic. When multiple selection methods are provided, products matching ANY of the criteria are selected (logical OR, not AND).", + "type": "object", + "properties": { + "manifest_skus": { + "type": "array", + "description": "Direct product SKU references from the brand manifest product catalog", + "items": { + "type": "string" + } + }, + "manifest_tags": { + "type": "array", + "description": "Select products by tags from the brand manifest product catalog (e.g., 'organic', 'sauces', 'holiday')", + "items": { + "type": "string" + } + }, + "manifest_category": { + "type": "string", + "description": "Select products from a specific category in the brand manifest product catalog (e.g., 'beverages/soft-drinks', 'food/sauces')" + }, + "manifest_query": { + "type": "string", + "description": "Natural language query to select products from the brand manifest (e.g., 'all Kraft Heinz pasta sauces', 'organic products under $20')" + } + }, + "additionalProperties": false, + "examples": [ + { + "description": "Direct SKU selection for specific products from brand manifest", + "data": { + "manifest_skus": [ + "SKU-12345", + "SKU-67890" + ] + } + }, + { + "description": "UNION selection: products tagged 'organic' OR 'sauces' OR in 'food/condiments' category from brand manifest", + "data": { + "manifest_tags": [ + "organic", + "sauces" + ], + "manifest_category": "food/condiments" + } + }, + { + "description": "Natural language product selection from brand manifest", + "data": { + "manifest_query": "all Kraft Heinz pasta sauces under $5" + } + }, + { + "description": "Select products by tags", + "data": { + "manifest_tags": [ + "holiday" + ] + } + } + ] +} diff --git a/tests/schemas/v1/_schemas_v1_core_property_json.json b/tests/schemas/v1/_schemas_v1_core_property_json.json deleted file mode 100644 index 180c82f..0000000 --- a/tests/schemas/v1/_schemas_v1_core_property_json.json +++ /dev/null @@ -1,70 +0,0 @@ -{ - "$schema": "http://json-schema.org/draft-07/schema#", - "$id": "/schemas/v1/core/property.json", - "title": "Property", - "description": "An advertising property that can be validated via adagents.json", - "type": "object", - "properties": { - "property_type": { - "type": "string", - "enum": [ - "website", - "mobile_app", - "ctv_app", - "dooh", - "podcast", - "radio", - "streaming_audio" - ], - "description": "Type of advertising property" - }, - "name": { - "type": "string", - "description": "Human-readable property name" - }, - "identifiers": { - "type": "array", - "description": "Array of identifiers for this property", - "items": { - "type": "object", - "properties": { - "type": { - "type": "string", - "description": "Type of identifier (e.g., 'domain', 'bundle_id', 'roku_store_id', 'podcast_guid')" - }, - "value": { - "type": "string", - "description": "The identifier value. For domain type: 'example.com' matches www.example.com and m.example.com only; 'subdomain.example.com' matches that specific subdomain; '*.example.com' matches all subdomains" - } - }, - "required": [ - "type", - "value" - ], - "additionalProperties": false - }, - "minItems": 1 - }, - "tags": { - "type": "array", - "description": "Tags for categorization and grouping (e.g., network membership, content categories)", - "items": { - "type": "string", - "pattern": "^[a-z0-9_]+$", - "description": "Lowercase tag with underscores (e.g., 'conde_nast_network', 'premium_content')" - }, - "uniqueItems": true - }, - "publisher_domain": { - "type": "string", - "description": "Domain where adagents.json should be checked for authorization validation" - } - }, - "required": [ - "property_type", - "name", - "identifiers", - "publisher_domain" - ], - "additionalProperties": false -} diff --git a/tests/schemas/v1/_schemas_v1_core_push-notification-config_json.json b/tests/schemas/v1/_schemas_v1_core_push-notification-config_json.json deleted file mode 100644 index 494c9dc..0000000 --- a/tests/schemas/v1/_schemas_v1_core_push-notification-config_json.json +++ /dev/null @@ -1,53 +0,0 @@ -{ - "$schema": "http://json-schema.org/draft-07/schema#", - "$id": "/schemas/v1/core/push-notification-config.json", - "title": "Push Notification Config", - "description": "Webhook configuration for asynchronous task notifications. Uses A2A-compatible PushNotificationConfig structure. Supports Bearer tokens (simple) or HMAC signatures (production-recommended).", - "type": "object", - "properties": { - "url": { - "type": "string", - "format": "uri", - "description": "Webhook endpoint URL for task status notifications" - }, - "token": { - "type": "string", - "description": "Optional client-provided token for webhook validation. Echoed back in webhook payload to validate request authenticity.", - "minLength": 16 - }, - "authentication": { - "type": "object", - "description": "Authentication configuration for webhook delivery (A2A-compatible)", - "properties": { - "schemes": { - "type": "array", - "description": "Array of authentication schemes. Supported: ['Bearer'] for simple token auth, ['HMAC-SHA256'] for signature verification (recommended for production)", - "items": { - "type": "string", - "enum": [ - "Bearer", - "HMAC-SHA256" - ] - }, - "minItems": 1, - "maxItems": 1 - }, - "credentials": { - "type": "string", - "description": "Credentials for authentication. For Bearer: token sent in Authorization header. For HMAC-SHA256: shared secret used to generate signature. Minimum 32 characters. Exchanged out-of-band during onboarding.", - "minLength": 32 - } - }, - "required": [ - "schemes", - "credentials" - ], - "additionalProperties": false - } - }, - "required": [ - "url", - "authentication" - ], - "additionalProperties": false -} diff --git a/tests/schemas/v1/_schemas_v1_core_reporting-capabilities_json.json b/tests/schemas/v1/_schemas_v1_core_reporting-capabilities_json.json deleted file mode 100644 index 37cf37b..0000000 --- a/tests/schemas/v1/_schemas_v1_core_reporting-capabilities_json.json +++ /dev/null @@ -1,87 +0,0 @@ -{ - "$schema": "http://json-schema.org/draft-07/schema#", - "$id": "/schemas/v1/core/reporting-capabilities.json", - "title": "Reporting Capabilities", - "description": "Reporting capabilities available for a product", - "type": "object", - "properties": { - "available_reporting_frequencies": { - "type": "array", - "description": "Supported reporting frequency options", - "items": { - "type": "string", - "enum": [ - "hourly", - "daily", - "monthly" - ] - }, - "minItems": 1, - "uniqueItems": true - }, - "expected_delay_minutes": { - "type": "integer", - "description": "Expected delay in minutes before reporting data becomes available (e.g., 240 for 4-hour delay)", - "minimum": 0, - "examples": [ - 240, - 300, - 1440 - ] - }, - "timezone": { - "type": "string", - "description": "Timezone for reporting periods. Use 'UTC' or IANA timezone (e.g., 'America/New_York'). Critical for daily/monthly frequency alignment.", - "examples": [ - "UTC", - "America/New_York", - "Europe/London", - "America/Los_Angeles" - ] - }, - "supports_webhooks": { - "type": "boolean", - "description": "Whether this product supports webhook-based reporting notifications" - }, - "available_metrics": { - "type": "array", - "description": "Metrics available in reporting. Impressions and spend are always implicitly included.", - "items": { - "type": "string", - "enum": [ - "impressions", - "spend", - "clicks", - "ctr", - "video_completions", - "completion_rate", - "conversions", - "viewability", - "engagement_rate" - ] - }, - "uniqueItems": true, - "examples": [ - [ - "impressions", - "spend", - "clicks", - "video_completions" - ], - [ - "impressions", - "spend", - "conversions" - ] - ] - } - }, - "required": [ - "available_reporting_frequencies", - "expected_delay_minutes", - "timezone", - "supports_webhooks", - "available_metrics" - ], - "additionalProperties": false -} diff --git a/tests/schemas/v1/_schemas_v1_core_start-timing_json.json b/tests/schemas/v1/_schemas_v1_core_start-timing_json.json deleted file mode 100644 index 389646f..0000000 --- a/tests/schemas/v1/_schemas_v1_core_start-timing_json.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "$schema": "http://json-schema.org/draft-07/schema#", - "$id": "/schemas/v1/core/start-timing.json", - "title": "Start Timing", - "description": "Campaign start timing: 'asap' or ISO 8601 date-time", - "oneOf": [ - { - "type": "string", - "const": "asap", - "description": "Start campaign as soon as possible" - }, - { - "type": "string", - "format": "date-time", - "description": "Scheduled start date/time in ISO 8601 format" - } - ] -} diff --git a/tests/schemas/v1/_schemas_v1_core_targeting_json.json b/tests/schemas/v1/_schemas_v1_core_targeting_json.json deleted file mode 100644 index 0cc7217..0000000 --- a/tests/schemas/v1/_schemas_v1_core_targeting_json.json +++ /dev/null @@ -1,42 +0,0 @@ -{ - "$schema": "http://json-schema.org/draft-07/schema#", - "$id": "/schemas/v1/core/targeting.json", - "title": "Targeting Overlay", - "description": "Optional geographic refinements for media buys. Most targeting should be expressed in the brief and handled by the publisher. These fields are primarily for geographic restrictions (RCT testing, regulatory compliance).", - "type": "object", - "properties": { - "geo_country_any_of": { - "type": "array", - "description": "Restrict delivery to specific countries (ISO codes). Use for regulatory compliance or RCT testing.", - "items": { - "type": "string", - "pattern": "^[A-Z]{2}$" - } - }, - "geo_region_any_of": { - "type": "array", - "description": "Restrict delivery to specific regions/states. Use for regulatory compliance or RCT testing.", - "items": { - "type": "string" - } - }, - "geo_metro_any_of": { - "type": "array", - "description": "Restrict delivery to specific metro areas (DMA codes). Use for regulatory compliance or RCT testing.", - "items": { - "type": "string" - } - }, - "geo_postal_code_any_of": { - "type": "array", - "description": "Restrict delivery to specific postal/ZIP codes. Use for regulatory compliance or RCT testing.", - "items": { - "type": "string" - } - }, - "frequency_cap": { - "$ref": "/schemas/v1/core/frequency-cap.json" - } - }, - "additionalProperties": false -} diff --git a/tests/schemas/v1/_schemas_v1_creative_asset-types_index_json.json b/tests/schemas/v1/_schemas_v1_creative_asset-types_index_json.json new file mode 100644 index 0000000..12f74cc --- /dev/null +++ b/tests/schemas/v1/_schemas_v1_creative_asset-types_index_json.json @@ -0,0 +1,95 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$id": "/schemas/v1/creative/asset-types/index.json", + "title": "AdCP Asset Type Definitions Registry", + "description": "Standardized definitions for all asset types used in AdCP creative manifests. These asset types are used when providing actual creative content that fulfills format requirements.", + "version": "1.0.0", + "lastUpdated": "2025-10-08", + "asset_types": { + "image": { + "description": "Static image asset (JPG, PNG, GIF, WebP, SVG)", + "schema": "/schemas/v1/creative/asset-types/image.json", + "typical_use": "Hero images, logos, product photos, backgrounds" + }, + "video": { + "description": "Hosted video file asset (MP4, WebM, MOV)", + "schema": "/schemas/v1/creative/asset-types/video.json", + "typical_use": "Video ads, product demos, brand stories" + }, + "audio": { + "description": "Audio file asset (MP3, AAC, M4A, WAV, OGG)", + "schema": "/schemas/v1/creative/asset-types/audio.json", + "typical_use": "Audio ads for streaming, podcasts, radio" + }, + "vast_tag": { + "description": "VAST XML tag for third-party video ad serving", + "schema": "/schemas/v1/creative/asset-types/vast_tag.json", + "typical_use": "Third-party served video ads with VAST 2.0-4.2" + }, + "text": { + "description": "Text content asset (plain, HTML, markdown)", + "schema": "/schemas/v1/creative/asset-types/text.json", + "typical_use": "Headlines, descriptions, CTAs, body copy, disclaimers" + }, + "url": { + "description": "URL asset for clickthrough, tracking, landing pages", + "schema": "/schemas/v1/creative/asset-types/url.json", + "typical_use": "Clickthrough URLs, tracking pixels, impression trackers" + }, + "html": { + "description": "HTML5 creative asset for interactive ads", + "schema": "/schemas/v1/creative/asset-types/html.json", + "typical_use": "HTML5 display banners, rich media, interactive ads" + }, + "webhook": { + "description": "Server-side webhook for dynamic creative rendering", + "schema": "/schemas/v1/creative/asset-types/webhook.json", + "typical_use": "DCO (Dynamic Creative Optimization), real-time personalization, server-side rendering" + }, + "javascript": { + "description": "JavaScript code for dynamic creative logic", + "schema": "/schemas/v1/creative/asset-types/javascript.json", + "typical_use": "Third-party tags, custom interaction logic, analytics" + } + }, + "common_properties": { + "asset_id": { + "description": "Unique identifier for this asset within the format (maps to asset_role in format spec)", + "type": "string", + "pattern": "^[a-z0-9_]+$", + "examples": [ + "hero_image", + "logo", + "headline", + "video_file", + "vast_tag", + "cta_text" + ] + }, + "asset_type": { + "description": "The type of asset - determines which schema and properties apply", + "type": "string", + "enum": [ + "image", + "video", + "audio", + "vast_tag", + "text", + "url", + "html", + "webhook", + "javascript" + ] + }, + "required": { + "description": "Whether this asset is mandatory for the creative format", + "type": "boolean", + "note": "This field is in format specs, not creative manifests" + } + }, + "usage_notes": { + "format_specs": "Format specifications define what asset_roles are needed (e.g., 'hero_image', 'logo'). Each asset_role specifies its asset_type and requirements.", + "creative_manifests": "Creative manifests provide actual assets mapped by asset_role. Each asset must have an asset_type field and type-specific properties.", + "example_flow": "Format says 'hero_image' must be asset_type 'image' with width 1200, height 627. Manifest provides hero_image with asset_type 'image', url 'https://...', width 1200, height 627." + } +} diff --git a/tests/schemas/v1/_schemas_v1_creative_list-creative-formats-request_json.json b/tests/schemas/v1/_schemas_v1_creative_list-creative-formats-request_json.json new file mode 100644 index 0000000..732c700 --- /dev/null +++ b/tests/schemas/v1/_schemas_v1_creative_list-creative-formats-request_json.json @@ -0,0 +1,67 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$id": "/schemas/v1/creative/list-creative-formats-request.json", + "title": "List Creative Formats Request (Creative Agent)", + "description": "Request parameters for discovering creative formats provided by this creative agent", + "type": "object", + "properties": { + "format_ids": { + "type": "array", + "description": "Return only these specific format IDs", + "items": { + "type": "string" + } + }, + "type": { + "type": "string", + "description": "Filter by format type (technical categories with distinct requirements)", + "enum": [ + "audio", + "video", + "display", + "dooh" + ] + }, + "asset_types": { + "type": "array", + "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.", + "items": { + "type": "string", + "enum": [ + "image", + "video", + "audio", + "text", + "html", + "javascript", + "url" + ] + } + }, + "max_width": { + "type": "integer", + "description": "Maximum width in pixels (inclusive). Returns formats with width <= this value. Omit for responsive/fluid formats." + }, + "max_height": { + "type": "integer", + "description": "Maximum height in pixels (inclusive). Returns formats with height <= this value. Omit for responsive/fluid formats." + }, + "min_width": { + "type": "integer", + "description": "Minimum width in pixels (inclusive). Returns formats with width >= this value." + }, + "min_height": { + "type": "integer", + "description": "Minimum height in pixels (inclusive). Returns formats with height >= this value." + }, + "is_responsive": { + "type": "boolean", + "description": "Filter for responsive formats that adapt to container size. When true, returns formats without fixed dimensions." + }, + "name_search": { + "type": "string", + "description": "Search for formats by name (case-insensitive partial match)" + } + }, + "additionalProperties": false +} diff --git a/tests/schemas/v1/_schemas_v1_media-buy_list-creative-formats-response_json.json b/tests/schemas/v1/_schemas_v1_creative_list-creative-formats-response_json.json similarity index 88% rename from tests/schemas/v1/_schemas_v1_media-buy_list-creative-formats-response_json.json rename to tests/schemas/v1/_schemas_v1_creative_list-creative-formats-response_json.json index 170ba09..8ddd85d 100644 --- a/tests/schemas/v1/_schemas_v1_media-buy_list-creative-formats-response_json.json +++ b/tests/schemas/v1/_schemas_v1_creative_list-creative-formats-response_json.json @@ -1,8 +1,8 @@ { "$schema": "http://json-schema.org/draft-07/schema#", - "$id": "/schemas/v1/media-buy/list-creative-formats-response.json", - "title": "List Creative Formats Response", - "description": "Response payload for list_creative_formats task", + "$id": "/schemas/v1/creative/list-creative-formats-response.json", + "title": "List Creative Formats Response (Creative Agent)", + "description": "Response payload for list_creative_formats task from creative agent - returns full format definitions", "type": "object", "properties": { "status": { @@ -52,7 +52,7 @@ }, "errors": { "type": "array", - "description": "Task-specific errors and warnings (e.g., format availability issues)", + "description": "Task-specific errors and warnings", "items": { "$ref": "/schemas/v1/core/error.json" } diff --git a/tests/schemas/v1/_schemas_v1_creative_preview-creative-request_json.json b/tests/schemas/v1/_schemas_v1_creative_preview-creative-request_json.json new file mode 100644 index 0000000..22b3a82 --- /dev/null +++ b/tests/schemas/v1/_schemas_v1_creative_preview-creative-request_json.json @@ -0,0 +1,58 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$id": "/schemas/v1/creative/preview-creative-request.json", + "title": "Preview Creative Request", + "description": "Request to generate a preview of a creative manifest in a specific format", + "type": "object", + "properties": { + "format_id": { + "$ref": "/schemas/v1/core/format-id.json", + "description": "Format identifier for rendering the preview" + }, + "creative_manifest": { + "$ref": "/schemas/v1/core/creative-manifest.json", + "description": "Complete creative manifest with all required assets" + }, + "inputs": { + "type": "array", + "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.", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "description": "Human-readable name for this input set (e.g., 'Sunny morning on mobile', 'Evening podcast ad', 'Desktop dark mode')" + }, + "macros": { + "type": "object", + "description": "Macro values to use for this preview. Supports all universal macros from the format's supported_macros list. See docs/media-buy/creatives/universal-macros.md for available macros.", + "additionalProperties": { + "type": "string" + } + }, + "context_description": { + "type": "string", + "description": "Natural language description of the context for AI-generated content (e.g., 'User just searched for running shoes', 'Podcast discussing weather patterns', 'Article about electric vehicles')" + } + }, + "required": [ + "name" + ], + "additionalProperties": false + } + }, + "template_id": { + "type": "string", + "description": "Specific template ID for custom format rendering" + }, + "promoted_offerings": { + "$ref": "/schemas/v1/core/promoted-offerings.json", + "description": "Complete offering specification for dynamic creative previews - includes brand manifest, product selectors, inline offerings, and asset filters" + } + }, + "required": [ + "format_id", + "creative_manifest" + ], + "additionalProperties": false +} diff --git a/tests/schemas/v1/_schemas_v1_creative_preview-creative-response_json.json b/tests/schemas/v1/_schemas_v1_creative_preview-creative-response_json.json new file mode 100644 index 0000000..10188eb --- /dev/null +++ b/tests/schemas/v1/_schemas_v1_creative_preview-creative-response_json.json @@ -0,0 +1,136 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$id": "/schemas/v1/creative/preview-creative-response.json", + "title": "Preview Creative Response", + "description": "Response containing preview links for a creative. Each preview URL returns an HTML page that can be embedded in an iframe to display the rendered creative.", + "type": "object", + "properties": { + "previews": { + "type": "array", + "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.", + "items": { + "type": "object", + "properties": { + "preview_url": { + "type": "string", + "format": "uri", + "description": "URL to an HTML page that renders this preview variant. Can be embedded in an iframe. Handles all rendering complexity internally (images, video players, audio players, interactive content, etc.)." + }, + "input": { + "type": "object", + "description": "The input parameters that generated this preview variant. Echoes back the request input or shows defaults used.", + "properties": { + "name": { + "type": "string", + "description": "Human-readable name for this variant" + }, + "macros": { + "type": "object", + "description": "Macro values applied to this variant", + "additionalProperties": { + "type": "string" + } + }, + "context_description": { + "type": "string", + "description": "Context description applied to this variant" + } + }, + "required": [ + "name" + ] + }, + "hints": { + "type": "object", + "description": "Optional optimization hints for clients. Clients MUST support HTML rendering regardless of hints. These enable optimizations like preloading appropriate codecs or sizing iframes.", + "properties": { + "primary_media_type": { + "type": "string", + "enum": [ + "image", + "video", + "audio", + "interactive" + ], + "description": "Primary media type contained in the preview (for optimization only)" + }, + "estimated_dimensions": { + "type": "object", + "description": "Estimated rendered dimensions (may differ from actual responsive rendering)", + "properties": { + "width": { + "type": "number", + "minimum": 0 + }, + "height": { + "type": "number", + "minimum": 0 + } + }, + "required": [ + "width", + "height" + ] + }, + "estimated_duration_seconds": { + "type": "number", + "minimum": 0, + "description": "Estimated duration for video/audio content (for optimization only)" + }, + "contains_audio": { + "type": "boolean", + "description": "Whether the preview contains audio (helps with autoplay policies)" + }, + "requires_interaction": { + "type": "boolean", + "description": "Whether the preview requires user interaction to fully experience" + } + } + }, + "embedding": { + "type": "object", + "description": "Optional security and embedding metadata for safe iframe integration", + "properties": { + "recommended_sandbox": { + "type": "string", + "description": "Recommended iframe sandbox attribute value (e.g., 'allow-scripts allow-same-origin')" + }, + "requires_https": { + "type": "boolean", + "description": "Whether the preview requires HTTPS for secure embedding" + }, + "supports_fullscreen": { + "type": "boolean", + "description": "Whether the preview supports fullscreen mode" + }, + "csp_policy": { + "type": "string", + "description": "Content Security Policy requirements for embedding" + } + } + } + }, + "required": [ + "preview_url", + "input" + ] + }, + "minItems": 1 + }, + "interactive_url": { + "type": "string", + "format": "uri", + "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." + }, + "expires_at": { + "type": "string", + "format": "date-time", + "description": "ISO 8601 timestamp when preview links expire" + } + }, + "required": [ + "previews", + "expires_at" + ], + "additionalProperties": false +} diff --git a/tests/schemas/v1/_schemas_v1_enums_identifier-types_json.json b/tests/schemas/v1/_schemas_v1_enums_identifier-types_json.json new file mode 100644 index 0000000..556e6ab --- /dev/null +++ b/tests/schemas/v1/_schemas_v1_enums_identifier-types_json.json @@ -0,0 +1,34 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$id": "/schemas/v1/enums/identifier-types.json", + "title": "Property Identifier Types", + "description": "Valid identifier types for property identification across different media types", + "type": "string", + "enum": [ + "domain", + "subdomain", + "network_id", + "ios_bundle", + "android_package", + "apple_app_store_id", + "google_play_id", + "roku_store_id", + "fire_tv_asin", + "samsung_app_id", + "apple_tv_bundle", + "bundle_id", + "venue_id", + "screen_id", + "openooh_venue_type", + "rss_url", + "apple_podcast_id", + "spotify_show_id", + "podcast_guid" + ], + "examples": [ + "domain", + "ios_bundle", + "venue_id", + "apple_podcast_id" + ] +} diff --git a/tests/schemas/v1/_schemas_v1_enums_snippet-type_json.json b/tests/schemas/v1/_schemas_v1_enums_snippet-type_json.json index cfc482d..1632acb 100644 --- a/tests/schemas/v1/_schemas_v1_enums_snippet-type_json.json +++ b/tests/schemas/v1/_schemas_v1_enums_snippet-type_json.json @@ -21,36 +21,12 @@ "daast_url": "DAAST (Digital Audio Ad Serving Template) URL for audio advertisements" }, "examples": [ - { - "type": "vast_xml", - "description": "Inline VAST XML", - "snippet": "Sample Ad..." - }, - { - "type": "vast_url", - "description": "VAST endpoint URL", - "snippet": "https://ads.example.com/vast?campaign=12345&placement=video" - }, - { - "type": "html", - "description": "HTML display ad", - "snippet": "
\"Ad\"/
" - }, - { - "type": "javascript", - "description": "JavaScript ad tag", - "snippet": "" - }, - { - "type": "iframe", - "description": "iFrame ad tag", - "snippet": "" - }, - { - "type": "daast_url", - "description": "DAAST audio ad URL", - "snippet": "https://audio-ads.example.com/daast?campaign=audio123" - } + "vast_xml", + "vast_url", + "html", + "javascript", + "iframe", + "daast_url" ], "usage": { "vast_xml": { diff --git a/tests/schemas/v1/_schemas_v1_media-buy_add-creative-assets-request_json.json b/tests/schemas/v1/_schemas_v1_media-buy_add-creative-assets-request_json.json deleted file mode 100644 index 922bf00..0000000 --- a/tests/schemas/v1/_schemas_v1_media-buy_add-creative-assets-request_json.json +++ /dev/null @@ -1,40 +0,0 @@ -{ - "$schema": "http://json-schema.org/draft-07/schema#", - "$id": "/schemas/v1/media-buy/add-creative-assets-request.json", - "title": "Add Creative Assets Request", - "description": "Request parameters for uploading creative assets", - "type": "object", - "properties": { - "media_buy_id": { - "type": "string", - "description": "Publisher's ID of the media buy to add creatives to" - }, - "buyer_ref": { - "type": "string", - "description": "Buyer's reference for the media buy" - }, - "assets": { - "type": "array", - "description": "Array of creative assets to upload", - "items": { - "$ref": "/schemas/v1/core/creative-asset.json" - } - } - }, - "required": [ - "assets" - ], - "oneOf": [ - { - "required": [ - "media_buy_id" - ] - }, - { - "required": [ - "buyer_ref" - ] - } - ], - "additionalProperties": false -} diff --git a/tests/schemas/v1/_schemas_v1_media-buy_add-creative-assets-response_json.json b/tests/schemas/v1/_schemas_v1_media-buy_add-creative-assets-response_json.json deleted file mode 100644 index 1359bff..0000000 --- a/tests/schemas/v1/_schemas_v1_media-buy_add-creative-assets-response_json.json +++ /dev/null @@ -1,92 +0,0 @@ -{ - "$schema": "http://json-schema.org/draft-07/schema#", - "$id": "/schemas/v1/media-buy/add-creative-assets-response.json", - "title": "Add Creative Assets Response", - "description": "Response payload for add_creative_assets task", - "type": "object", - "properties": { - "asset_statuses": { - "type": "array", - "description": "Array of status information for each uploaded asset", - "items": { - "type": "object", - "properties": { - "creative_id": { - "type": "string", - "description": "The creative ID from the request" - }, - "status": { - "$ref": "/schemas/v1/enums/creative-status.json" - }, - "platform_id": { - "type": "string", - "description": "Platform-specific ID assigned to the creative" - }, - "review_feedback": { - "type": "string", - "description": "Feedback from platform review (if any)" - }, - "suggested_adaptations": { - "type": "array", - "description": "Array of recommended format adaptations", - "items": { - "type": "object", - "properties": { - "adaptation_id": { - "type": "string", - "description": "Unique identifier for this adaptation" - }, - "format_id": { - "type": "string", - "description": "Target format ID for the adaptation" - }, - "name": { - "type": "string", - "description": "Suggested name for the adapted creative" - }, - "description": { - "type": "string", - "description": "What this adaptation does" - }, - "changes_summary": { - "type": "array", - "description": "List of changes that will be made", - "items": { - "type": "string" - } - }, - "rationale": { - "type": "string", - "description": "Why this adaptation is recommended" - }, - "estimated_performance_lift": { - "type": "number", - "description": "Expected performance improvement (percentage)", - "minimum": 0 - } - }, - "required": [ - "adaptation_id", - "format_id", - "name", - "description", - "changes_summary", - "rationale" - ], - "additionalProperties": false - } - } - }, - "required": [ - "creative_id", - "status" - ], - "additionalProperties": false - } - } - }, - "required": [ - "asset_statuses" - ], - "additionalProperties": false -} diff --git a/tests/schemas/v1/_schemas_v1_media-buy_create-media-buy-request_json.json b/tests/schemas/v1/_schemas_v1_media-buy_create-media-buy-request_json.json deleted file mode 100644 index cded121..0000000 --- a/tests/schemas/v1/_schemas_v1_media-buy_create-media-buy-request_json.json +++ /dev/null @@ -1,89 +0,0 @@ -{ - "$schema": "http://json-schema.org/draft-07/schema#", - "$id": "/schemas/v1/media-buy/create-media-buy-request.json", - "title": "Create Media Buy Request", - "description": "Request parameters for creating a media buy", - "type": "object", - "properties": { - "adcp_version": { - "type": "string", - "description": "AdCP schema version for this request", - "pattern": "^\\d+\\.\\d+\\.\\d+$", - "default": "1.6.1" - }, - "buyer_ref": { - "type": "string", - "description": "Buyer's reference identifier for this media buy" - }, - "packages": { - "type": "array", - "description": "Array of package configurations", - "items": { - "$ref": "/schemas/v1/media-buy/package-request.json" - } - }, - "brand_manifest": { - "$ref": "/schemas/v1/core/brand-manifest-ref.json", - "description": "Brand information manifest serving as the namespace and identity for this media buy. Provides brand context, assets, and product catalog. Can be provided inline or as a URL reference to a hosted manifest. Can be cached and reused across multiple requests." - }, - "promoted_offering": { - "type": "string", - "description": "DEPRECATED: Use brand_manifest instead. Legacy field for describing what is being promoted." - }, - "po_number": { - "type": "string", - "description": "Purchase order number for tracking" - }, - "start_time": { - "$ref": "/schemas/v1/core/start-timing.json" - }, - "end_time": { - "type": "string", - "format": "date-time", - "description": "Campaign end date/time in ISO 8601 format" - }, - "budget": { - "type": "number", - "description": "Total budget for this media buy. Currency is determined by the pricing_option_id selected in each package.", - "minimum": 0 - }, - "reporting_webhook": { - "allOf": [ - { - "$ref": "/schemas/v1/core/push-notification-config.json" - }, - { - "type": "object", - "description": "Optional webhook configuration for automated reporting delivery. Uses push_notification_config structure with additional reporting-specific fields.", - "properties": { - "reporting_frequency": { - "type": "string", - "enum": ["hourly", "daily", "monthly"], - "description": "Frequency for automated reporting delivery. Must be supported by all products in the media buy." - }, - "requested_metrics": { - "type": "array", - "description": "Optional list of metrics to include in webhook notifications. If omitted, all available metrics are included. Must be subset of product's available_metrics.", - "items": { - "type": "string", - "enum": ["impressions", "spend", "clicks", "ctr", "video_completions", "completion_rate", "conversions", "viewability", "engagement_rate"] - }, - "uniqueItems": true - } - }, - "required": ["reporting_frequency"] - } - ] - } - }, - "required": ["buyer_ref", "packages", "start_time", "end_time", "budget"], - "oneOf": [ - { - "required": ["promoted_offering"] - }, - { - "required": ["brand_manifest"] - } - ], - "additionalProperties": false -} diff --git a/tests/schemas/v1/_schemas_v1_media-buy_create-media-buy-response_json.json b/tests/schemas/v1/_schemas_v1_media-buy_create-media-buy-response_json.json deleted file mode 100644 index 0d5c0c8..0000000 --- a/tests/schemas/v1/_schemas_v1_media-buy_create-media-buy-response_json.json +++ /dev/null @@ -1,71 +0,0 @@ -{ - "$schema": "http://json-schema.org/draft-07/schema#", - "$id": "/schemas/v1/media-buy/create-media-buy-response.json", - "title": "Create Media Buy Response", - "description": "Response payload for create_media_buy task", - "type": "object", - "properties": { - "adcp_version": { - "type": "string", - "description": "AdCP schema version used for this response", - "pattern": "^\\d+\\.\\d+\\.\\d+$", - "default": "1.6.1" - }, - "status": { - "$ref": "/schemas/v1/enums/task-status.json", - "description": "Current task state - 'completed' for immediate success, 'working' for operations under 120s, 'submitted' for long-running operations, 'input-required' if approval needed" - }, - "task_id": { - "type": "string", - "description": "Unique identifier for tracking this async operation (present for submitted/working status)" - }, - "media_buy_id": { - "type": "string", - "description": "Publisher's unique identifier for the created media buy" - }, - "buyer_ref": { - "type": "string", - "description": "Buyer's reference identifier for this media buy" - }, - "creative_deadline": { - "type": "string", - "format": "date-time", - "description": "ISO 8601 timestamp for creative upload deadline" - }, - "packages": { - "type": "array", - "description": "Array of created packages", - "items": { - "type": "object", - "properties": { - "package_id": { - "type": "string", - "description": "Publisher's unique identifier for the package" - }, - "buyer_ref": { - "type": "string", - "description": "Buyer's reference identifier for the package" - } - }, - "required": [ - "package_id", - "buyer_ref" - ], - "additionalProperties": false - } - }, - "errors": { - "type": "array", - "description": "Task-specific errors and warnings (e.g., partial package creation failures)", - "items": { - "$ref": "/schemas/v1/core/error.json" - } - } - }, - "required": [ - "adcp_version", - "status", - "buyer_ref" - ], - "additionalProperties": false -} diff --git a/tests/schemas/v1/_schemas_v1_media-buy_get-media-buy-delivery-request_json.json b/tests/schemas/v1/_schemas_v1_media-buy_get-media-buy-delivery-request_json.json deleted file mode 100644 index edc1328..0000000 --- a/tests/schemas/v1/_schemas_v1_media-buy_get-media-buy-delivery-request_json.json +++ /dev/null @@ -1,69 +0,0 @@ -{ - "$schema": "http://json-schema.org/draft-07/schema#", - "$id": "/schemas/v1/media-buy/get-media-buy-delivery-request.json", - "title": "Get Media Buy Delivery Request", - "description": "Request parameters for retrieving comprehensive delivery metrics", - "type": "object", - "properties": { - "adcp_version": { - "type": "string", - "description": "AdCP schema version for this request", - "pattern": "^\\d+\\.\\d+\\.\\d+$", - "default": "1.6.0" - }, - "media_buy_ids": { - "type": "array", - "description": "Array of publisher media buy IDs to get delivery data for", - "items": { - "type": "string" - } - }, - "buyer_refs": { - "type": "array", - "description": "Array of buyer reference IDs to get delivery data for", - "items": { - "type": "string" - } - }, - "status_filter": { - "oneOf": [ - { - "type": "string", - "enum": [ - "active", - "pending", - "paused", - "completed", - "failed", - "all" - ] - }, - { - "type": "array", - "items": { - "type": "string", - "enum": [ - "active", - "pending", - "paused", - "completed", - "failed" - ] - } - } - ], - "description": "Filter by status. Can be a single status or array of statuses" - }, - "start_date": { - "type": "string", - "pattern": "^\\d{4}-\\d{2}-\\d{2}$", - "description": "Start date for reporting period (YYYY-MM-DD)" - }, - "end_date": { - "type": "string", - "pattern": "^\\d{4}-\\d{2}-\\d{2}$", - "description": "End date for reporting period (YYYY-MM-DD)" - } - }, - "additionalProperties": false -} diff --git a/tests/schemas/v1/_schemas_v1_media-buy_get-media-buy-delivery-response_json.json b/tests/schemas/v1/_schemas_v1_media-buy_get-media-buy-delivery-response_json.json deleted file mode 100644 index dd338a5..0000000 --- a/tests/schemas/v1/_schemas_v1_media-buy_get-media-buy-delivery-response_json.json +++ /dev/null @@ -1,257 +0,0 @@ -{ - "$schema": "http://json-schema.org/draft-07/schema#", - "$id": "/schemas/v1/media-buy/get-media-buy-delivery-response.json", - "title": "Get Media Buy Delivery Response", - "description": "Response payload for get_media_buy_delivery task", - "type": "object", - "properties": { - "adcp_version": { - "type": "string", - "description": "AdCP schema version used for this response", - "pattern": "^\\d+\\.\\d+\\.\\d+$" - }, - "notification_type": { - "type": "string", - "enum": [ - "scheduled", - "final", - "delayed", - "adjusted" - ], - "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" - }, - "partial_data": { - "type": "boolean", - "description": "Indicates if any media buys in this webhook have missing/delayed data (only present in webhook deliveries)" - }, - "unavailable_count": { - "type": "integer", - "minimum": 0, - "description": "Number of media buys with reporting_delayed or failed status (only present in webhook deliveries when partial_data is true)" - }, - "sequence_number": { - "type": "integer", - "minimum": 1, - "description": "Sequential notification number (only present in webhook deliveries, starts at 1)" - }, - "next_expected_at": { - "type": "string", - "format": "date-time", - "description": "ISO 8601 timestamp for next expected notification (only present in webhook deliveries when notification_type is not 'final')" - }, - "reporting_period": { - "type": "object", - "description": "Date range for the report. All periods use UTC timezone.", - "properties": { - "start": { - "type": "string", - "format": "date-time", - "description": "ISO 8601 start timestamp in UTC (e.g., 2024-02-05T00:00:00Z)" - }, - "end": { - "type": "string", - "format": "date-time", - "description": "ISO 8601 end timestamp in UTC (e.g., 2024-02-05T23:59:59Z)" - } - }, - "required": [ - "start", - "end" - ], - "additionalProperties": false - }, - "currency": { - "type": "string", - "description": "ISO 4217 currency code", - "pattern": "^[A-Z]{3}$" - }, - "aggregated_totals": { - "type": "object", - "description": "Combined metrics across all returned media buys. Only included in API responses (get_media_buy_delivery), not in webhook notifications.", - "properties": { - "impressions": { - "type": "number", - "description": "Total impressions delivered across all media buys", - "minimum": 0 - }, - "spend": { - "type": "number", - "description": "Total amount spent across all media buys", - "minimum": 0 - }, - "clicks": { - "type": "number", - "description": "Total clicks across all media buys (if applicable)", - "minimum": 0 - }, - "video_completions": { - "type": "number", - "description": "Total video completions across all media buys (if applicable)", - "minimum": 0 - }, - "media_buy_count": { - "type": "integer", - "description": "Number of media buys included in the response", - "minimum": 0 - } - }, - "required": [ - "impressions", - "spend", - "media_buy_count" - ], - "additionalProperties": false - }, - "media_buy_deliveries": { - "type": "array", - "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.", - "items": { - "type": "object", - "properties": { - "media_buy_id": { - "type": "string", - "description": "Publisher's media buy identifier" - }, - "buyer_ref": { - "type": "string", - "description": "Buyer's reference identifier for this media buy" - }, - "status": { - "type": "string", - "description": "Current media buy status. In webhook context, reporting_delayed indicates data temporarily unavailable.", - "enum": [ - "pending", - "active", - "paused", - "completed", - "failed", - "reporting_delayed" - ] - }, - "message": { - "type": "string", - "description": "Human-readable message (typically present when status is reporting_delayed or failed)" - }, - "expected_availability": { - "type": "string", - "format": "date-time", - "description": "When delayed data is expected to be available (only present when status is reporting_delayed)" - }, - "is_adjusted": { - "type": "boolean", - "description": "Indicates this delivery contains updated data for a previously reported period. Buyer should replace previous period data with these totals." - }, - "pricing_model": { - "$ref": "/schemas/v1/enums/pricing-model.json", - "description": "Pricing model used for this media buy" - }, - "totals": { - "allOf": [ - { - "$ref": "/schemas/v1/core/delivery-metrics.json" - }, - { - "type": "object", - "description": "Aggregate metrics for this media buy across all packages", - "properties": { - "effective_rate": { - "type": "number", - "description": "Effective rate paid per unit based on pricing_model (e.g., actual CPM for 'cpm', actual cost per completed view for 'cpcv', actual cost per point for 'cpp')", - "minimum": 0 - } - }, - "required": [ - "spend" - ] - } - ] - }, - "by_package": { - "type": "array", - "description": "Metrics broken down by package", - "items": { - "allOf": [ - { - "$ref": "/schemas/v1/core/delivery-metrics.json" - }, - { - "type": "object", - "properties": { - "package_id": { - "type": "string", - "description": "Publisher's package identifier" - }, - "buyer_ref": { - "type": "string", - "description": "Buyer's reference identifier for this package" - }, - "pacing_index": { - "type": "number", - "description": "Delivery pace (1.0 = on track, <1.0 = behind, >1.0 = ahead)", - "minimum": 0 - } - }, - "required": [ - "package_id", - "spend" - ] - } - ] - } - }, - "daily_breakdown": { - "type": "array", - "description": "Day-by-day delivery", - "items": { - "type": "object", - "properties": { - "date": { - "type": "string", - "pattern": "^\\d{4}-\\d{2}-\\d{2}$", - "description": "Date (YYYY-MM-DD)" - }, - "impressions": { - "type": "number", - "description": "Daily impressions", - "minimum": 0 - }, - "spend": { - "type": "number", - "description": "Daily spend", - "minimum": 0 - } - }, - "required": [ - "date", - "impressions", - "spend" - ], - "additionalProperties": false - } - } - }, - "required": [ - "media_buy_id", - "status", - "totals", - "by_package" - ], - "additionalProperties": false - } - }, - "errors": { - "type": "array", - "description": "Task-specific errors and warnings (e.g., missing delivery data, reporting platform issues)", - "items": { - "$ref": "/schemas/v1/core/error.json" - } - } - }, - "required": [ - "adcp_version", - "reporting_period", - "currency", - "media_buy_deliveries" - ], - "additionalProperties": false -} diff --git a/tests/schemas/v1/_schemas_v1_media-buy_get-products-request_json.json b/tests/schemas/v1/_schemas_v1_media-buy_get-products-request_json.json deleted file mode 100644 index 3598302..0000000 --- a/tests/schemas/v1/_schemas_v1_media-buy_get-products-request_json.json +++ /dev/null @@ -1,74 +0,0 @@ -{ - "$schema": "http://json-schema.org/draft-07/schema#", - "$id": "/schemas/v1/media-buy/get-products-request.json", - "title": "Get Products Request", - "description": "Request parameters for discovering available advertising products", - "type": "object", - "properties": { - "adcp_version": { - "type": "string", - "description": "AdCP schema version for this request", - "pattern": "^\\d+\\.\\d+\\.\\d+$", - "default": "1.6.0" - }, - "brief": { - "type": "string", - "description": "Natural language description of campaign requirements" - }, - "promoted_offering": { - "type": "string", - "description": "DEPRECATED: Use brand_manifest instead. Legacy field for describing what is being promoted." - }, - "brand_manifest": { - "$ref": "/schemas/v1/core/brand-manifest-ref.json", - "description": "Brand information manifest providing brand context, assets, and product catalog. Can be provided inline or as a URL reference to a hosted manifest." - }, - "filters": { - "type": "object", - "description": "Structured filters for product discovery", - "properties": { - "delivery_type": { - "$ref": "/schemas/v1/enums/delivery-type.json" - }, - "is_fixed_price": { - "type": "boolean", - "description": "Filter for fixed price vs auction products" - }, - "format_types": { - "type": "array", - "description": "Filter by format types", - "items": { - "type": "string", - "enum": ["video", "display", "audio"] - } - }, - "format_ids": { - "type": "array", - "description": "Filter by specific format IDs", - "items": { - "type": "string" - } - }, - "standard_formats_only": { - "type": "boolean", - "description": "Only return products accepting IAB standard formats" - }, - "min_exposures": { - "type": "integer", - "description": "Minimum exposures/impressions needed for measurement validity", - "minimum": 1 - } - }, - "additionalProperties": false - } - }, - "oneOf": [ - { - "required": ["promoted_offering"] - }, - { - "required": ["brand_manifest"] - } - ], - "additionalProperties": false -} diff --git a/tests/schemas/v1/_schemas_v1_media-buy_get-products-response_json.json b/tests/schemas/v1/_schemas_v1_media-buy_get-products-response_json.json deleted file mode 100644 index 39805e5..0000000 --- a/tests/schemas/v1/_schemas_v1_media-buy_get-products-response_json.json +++ /dev/null @@ -1,39 +0,0 @@ -{ - "$schema": "http://json-schema.org/draft-07/schema#", - "$id": "/schemas/v1/media-buy/get-products-response.json", - "title": "Get Products Response", - "description": "Response payload for get_products task", - "type": "object", - "properties": { - "adcp_version": { - "type": "string", - "description": "AdCP schema version used for this response", - "pattern": "^\\d+\\.\\d+\\.\\d+$", - "default": "1.6.0" - }, - "status": { - "$ref": "/schemas/v1/enums/task-status.json", - "description": "Current task state", - "default": "completed" - }, - "products": { - "type": "array", - "description": "Array of matching products", - "items": { - "$ref": "/schemas/v1/core/product.json" - } - }, - "errors": { - "type": "array", - "description": "Task-specific errors and warnings (e.g., product filtering issues)", - "items": { - "$ref": "/schemas/v1/core/error.json" - } - } - }, - "required": [ - "adcp_version", - "products" - ], - "additionalProperties": false -} diff --git a/tests/schemas/v1/_schemas_v1_media-buy_list-authorized-properties-request_json.json b/tests/schemas/v1/_schemas_v1_media-buy_list-authorized-properties-request_json.json deleted file mode 100644 index a66987c..0000000 --- a/tests/schemas/v1/_schemas_v1_media-buy_list-authorized-properties-request_json.json +++ /dev/null @@ -1,25 +0,0 @@ -{ - "$schema": "http://json-schema.org/draft-07/schema#", - "$id": "/schemas/v1/media-buy/list-authorized-properties-request.json", - "title": "List Authorized Properties Request", - "description": "Request parameters for discovering all properties this agent is authorized to represent", - "type": "object", - "properties": { - "adcp_version": { - "type": "string", - "description": "AdCP schema version for this request", - "pattern": "^\\d+\\.\\d+\\.\\d+$", - "default": "1.0.0" - }, - "tags": { - "type": "array", - "description": "Filter properties by specific tags (optional)", - "items": { - "type": "string", - "pattern": "^[a-z0-9_]+$", - "description": "Tag to filter by (e.g., 'local_radio', 'premium_content')" - } - } - }, - "additionalProperties": false -} diff --git a/tests/schemas/v1/_schemas_v1_media-buy_list-authorized-properties-response_json.json b/tests/schemas/v1/_schemas_v1_media-buy_list-authorized-properties-response_json.json deleted file mode 100644 index 8fba693..0000000 --- a/tests/schemas/v1/_schemas_v1_media-buy_list-authorized-properties-response_json.json +++ /dev/null @@ -1,78 +0,0 @@ -{ - "$schema": "http://json-schema.org/draft-07/schema#", - "$id": "/schemas/v1/media-buy/list-authorized-properties-response.json", - "title": "List Authorized Properties Response", - "description": "Response payload for list_authorized_properties task", - "type": "object", - "properties": { - "adcp_version": { - "type": "string", - "description": "AdCP schema version used for this response", - "pattern": "^\\d+\\.\\d+\\.\\d+$" - }, - "properties": { - "type": "array", - "description": "Array of all properties this agent is authorized to represent", - "items": { - "$ref": "/schemas/v1/core/property.json" - } - }, - "tags": { - "type": "object", - "description": "Metadata for each tag referenced by properties", - "additionalProperties": { - "type": "object", - "properties": { - "name": { - "type": "string", - "description": "Human-readable name for this tag" - }, - "description": { - "type": "string", - "description": "Description of what this tag represents" - } - }, - "required": [ - "name", - "description" - ], - "additionalProperties": false - } - }, - "primary_channels": { - "type": "array", - "description": "Primary advertising channels represented in this property portfolio. Helps buying agents quickly filter relevance.", - "items": { - "$ref": "/schemas/v1/enums/channels.json" - }, - "minItems": 1 - }, - "primary_countries": { - "type": "array", - "description": "Primary countries (ISO 3166-1 alpha-2 codes) where properties are concentrated. Helps buying agents quickly filter relevance.", - "items": { - "type": "string", - "pattern": "^[A-Z]{2}$" - }, - "minItems": 1 - }, - "portfolio_description": { - "type": "string", - "description": "Markdown-formatted description of the property portfolio, including inventory types, audience characteristics, and special features.", - "minLength": 1, - "maxLength": 5000 - }, - "errors": { - "type": "array", - "description": "Task-specific errors and warnings (e.g., property availability issues)", - "items": { - "$ref": "/schemas/v1/core/error.json" - } - } - }, - "required": [ - "adcp_version", - "properties" - ], - "additionalProperties": false -} diff --git a/tests/schemas/v1/_schemas_v1_media-buy_list-creative-formats-request_json.json b/tests/schemas/v1/_schemas_v1_media-buy_list-creative-formats-request_json.json deleted file mode 100644 index 1a1d742..0000000 --- a/tests/schemas/v1/_schemas_v1_media-buy_list-creative-formats-request_json.json +++ /dev/null @@ -1,57 +0,0 @@ -{ - "$schema": "http://json-schema.org/draft-07/schema#", - "$id": "/schemas/v1/media-buy/list-creative-formats-request.json", - "title": "List Creative Formats Request", - "description": "Request parameters for discovering supported creative formats", - "type": "object", - "properties": { - "adcp_version": { - "type": "string", - "description": "AdCP schema version for this request", - "pattern": "^\\d+\\.\\d+\\.\\d+$", - "default": "1.6.0" - }, - "format_ids": { - "type": "array", - "description": "Return only these specific format IDs (e.g., from get_products response)", - "items": { - "type": "string" - } - }, - "type": { - "type": "string", - "description": "Filter by format type (technical categories with distinct requirements)", - "enum": [ - "audio", - "video", - "display", - "dooh" - ] - }, - "asset_types": { - "type": "array", - "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.", - "items": { - "type": "string", - "enum": [ - "image", - "video", - "audio", - "text", - "html", - "javascript", - "url" - ] - } - }, - "dimensions": { - "type": "string", - "description": "Filter to formats with specific dimensions (e.g., '300x250', '728x90'). Useful with asset_types to find specific sizes like '300x250 JavaScript'" - }, - "name_search": { - "type": "string", - "description": "Search for formats by name (case-insensitive partial match)" - } - }, - "additionalProperties": false -} diff --git a/tests/schemas/v1/_schemas_v1_media-buy_list-creatives-request_json.json b/tests/schemas/v1/_schemas_v1_media-buy_list-creatives-request_json.json deleted file mode 100644 index d949f60..0000000 --- a/tests/schemas/v1/_schemas_v1_media-buy_list-creatives-request_json.json +++ /dev/null @@ -1,244 +0,0 @@ -{ - "$schema": "http://json-schema.org/draft-07/schema#", - "$id": "/schemas/v1/media-buy/list-creatives-request.json", - "title": "List Creatives Request", - "description": "Request parameters for querying creative assets from the centralized library with filtering, sorting, and pagination", - "type": "object", - "properties": { - "adcp_version": { - "type": "string", - "description": "AdCP schema version for this request", - "pattern": "^\\d+\\.\\d+\\.\\d+$", - "default": "1.6.0" - }, - "filters": { - "type": "object", - "description": "Filter criteria for querying creatives", - "properties": { - "format": { - "type": "string", - "description": "Filter by creative format type (e.g., video, audio, display)" - }, - "formats": { - "type": "array", - "description": "Filter by multiple creative format types", - "items": { - "type": "string" - } - }, - "status": { - "$ref": "/schemas/v1/enums/creative-status.json", - "description": "Filter by creative approval status" - }, - "statuses": { - "type": "array", - "description": "Filter by multiple creative statuses", - "items": { - "$ref": "/schemas/v1/enums/creative-status.json" - } - }, - "tags": { - "type": "array", - "description": "Filter by creative tags (all tags must match)", - "items": { - "type": "string" - } - }, - "tags_any": { - "type": "array", - "description": "Filter by creative tags (any tag must match)", - "items": { - "type": "string" - } - }, - "name_contains": { - "type": "string", - "description": "Filter by creative names containing this text (case-insensitive)" - }, - "creative_ids": { - "type": "array", - "description": "Filter by specific creative IDs", - "items": { - "type": "string" - }, - "maxItems": 100 - }, - "created_after": { - "type": "string", - "format": "date-time", - "description": "Filter creatives created after this date (ISO 8601)" - }, - "created_before": { - "type": "string", - "format": "date-time", - "description": "Filter creatives created before this date (ISO 8601)" - }, - "updated_after": { - "type": "string", - "format": "date-time", - "description": "Filter creatives last updated after this date (ISO 8601)" - }, - "updated_before": { - "type": "string", - "format": "date-time", - "description": "Filter creatives last updated before this date (ISO 8601)" - }, - "assigned_to_package": { - "type": "string", - "description": "Filter creatives assigned to this specific package" - }, - "assigned_to_packages": { - "type": "array", - "description": "Filter creatives assigned to any of these packages", - "items": { - "type": "string" - } - }, - "unassigned": { - "type": "boolean", - "description": "Filter for unassigned creatives when true, assigned creatives when false" - }, - "snippet_type": { - "$ref": "/schemas/v1/enums/snippet-type.json", - "description": "Filter by third-party snippet type" - }, - "has_performance_data": { - "type": "boolean", - "description": "Filter creatives that have performance data when true" - } - }, - "additionalProperties": false - }, - "sort": { - "type": "object", - "description": "Sorting parameters", - "properties": { - "field": { - "type": "string", - "enum": [ - "created_date", - "updated_date", - "name", - "status", - "assignment_count", - "performance_score" - ], - "default": "created_date", - "description": "Field to sort by" - }, - "direction": { - "type": "string", - "enum": [ - "asc", - "desc" - ], - "default": "desc", - "description": "Sort direction" - } - }, - "additionalProperties": false - }, - "pagination": { - "type": "object", - "description": "Pagination parameters", - "properties": { - "limit": { - "type": "integer", - "minimum": 1, - "maximum": 100, - "default": 50, - "description": "Maximum number of creatives to return" - }, - "offset": { - "type": "integer", - "minimum": 0, - "default": 0, - "description": "Number of creatives to skip" - } - }, - "additionalProperties": false - }, - "include_assignments": { - "type": "boolean", - "default": true, - "description": "Include package assignment information in response" - }, - "include_performance": { - "type": "boolean", - "default": false, - "description": "Include aggregated performance metrics in response" - }, - "include_sub_assets": { - "type": "boolean", - "default": false, - "description": "Include sub-assets (for carousel/native formats) in response" - }, - "fields": { - "type": "array", - "description": "Specific fields to include in response (omit for all fields)", - "items": { - "type": "string", - "enum": [ - "creative_id", - "name", - "format", - "status", - "created_date", - "updated_date", - "tags", - "assignments", - "performance", - "sub_assets" - ] - } - } - }, - "additionalProperties": false, - "examples": [ - { - "description": "List all approved video creatives", - "data": { - "filters": { - "format": "video", - "status": "approved" - } - } - }, - { - "description": "Search for Nike creatives with performance data", - "data": { - "filters": { - "name_contains": "nike", - "has_performance_data": true - }, - "include_performance": true - } - }, - { - "description": "Get unassigned creatives for assignment", - "data": { - "filters": { - "unassigned": true - }, - "sort": { - "field": "created_date", - "direction": "desc" - }, - "pagination": { - "limit": 20 - } - } - }, - { - "description": "Lightweight list with minimal fields", - "data": { - "fields": [ - "creative_id", - "name", - "status" - ], - "include_assignments": false - } - } - ] -} diff --git a/tests/schemas/v1/_schemas_v1_media-buy_list-creatives-response_json.json b/tests/schemas/v1/_schemas_v1_media-buy_list-creatives-response_json.json deleted file mode 100644 index 33551ff..0000000 --- a/tests/schemas/v1/_schemas_v1_media-buy_list-creatives-response_json.json +++ /dev/null @@ -1,439 +0,0 @@ -{ - "$schema": "http://json-schema.org/draft-07/schema#", - "$id": "/schemas/v1/media-buy/list-creatives-response.json", - "title": "List Creatives Response", - "description": "Response from creative library query with filtered results, metadata, and optional enriched data", - "type": "object", - "properties": { - "adcp_version": { - "type": "string", - "description": "AdCP schema version used for this response", - "pattern": "^\\d+\\.\\d+\\.\\d+$" - }, - "message": { - "type": "string", - "description": "Human-readable result message" - }, - "context_id": { - "type": "string", - "description": "Context ID for tracking related operations" - }, - "query_summary": { - "type": "object", - "description": "Summary of the query that was executed", - "properties": { - "total_matching": { - "type": "integer", - "description": "Total number of creatives matching filters (across all pages)", - "minimum": 0 - }, - "returned": { - "type": "integer", - "description": "Number of creatives returned in this response", - "minimum": 0 - }, - "filters_applied": { - "type": "array", - "description": "List of filters that were applied to the query", - "items": { - "type": "string" - } - }, - "sort_applied": { - "type": "object", - "description": "Sort order that was applied", - "properties": { - "field": { - "type": "string" - }, - "direction": { - "type": "string", - "enum": [ - "asc", - "desc" - ] - } - } - } - }, - "required": [ - "total_matching", - "returned" - ], - "additionalProperties": false - }, - "pagination": { - "type": "object", - "description": "Pagination information for navigating results", - "properties": { - "limit": { - "type": "integer", - "description": "Maximum number of results requested", - "minimum": 1 - }, - "offset": { - "type": "integer", - "description": "Number of results skipped", - "minimum": 0 - }, - "has_more": { - "type": "boolean", - "description": "Whether more results are available" - }, - "total_pages": { - "type": "integer", - "description": "Total number of pages available", - "minimum": 0 - }, - "current_page": { - "type": "integer", - "description": "Current page number (1-based)", - "minimum": 1 - } - }, - "required": [ - "limit", - "offset", - "has_more" - ], - "additionalProperties": false - }, - "creatives": { - "type": "array", - "description": "Array of creative assets matching the query", - "items": { - "type": "object", - "properties": { - "creative_id": { - "type": "string", - "description": "Unique identifier for the creative" - }, - "name": { - "type": "string", - "description": "Human-readable creative name" - }, - "format": { - "type": "string", - "description": "Creative format type" - }, - "status": { - "$ref": "/schemas/v1/enums/creative-status.json", - "description": "Current approval status of the creative" - }, - "created_date": { - "type": "string", - "format": "date-time", - "description": "When the creative was uploaded to the library" - }, - "updated_date": { - "type": "string", - "format": "date-time", - "description": "When the creative was last modified" - }, - "media_url": { - "type": "string", - "format": "uri", - "description": "URL of the creative file (for hosted assets)" - }, - "snippet": { - "type": "string", - "description": "Third-party tag, VAST XML, or code snippet (for third-party assets)" - }, - "snippet_type": { - "$ref": "/schemas/v1/enums/snippet-type.json", - "description": "Type of snippet content" - }, - "click_url": { - "type": "string", - "format": "uri", - "description": "Landing page URL for the creative" - }, - "duration": { - "type": "number", - "description": "Duration in milliseconds (for video/audio)", - "minimum": 0 - }, - "width": { - "type": "number", - "description": "Width in pixels (for video/display)", - "minimum": 0 - }, - "height": { - "type": "number", - "description": "Height in pixels (for video/display)", - "minimum": 0 - }, - "tags": { - "type": "array", - "description": "User-defined tags for organization and searchability", - "items": { - "type": "string" - } - }, - "assignments": { - "type": "object", - "description": "Current package assignments (included when include_assignments=true)", - "properties": { - "assignment_count": { - "type": "integer", - "description": "Total number of active package assignments", - "minimum": 0 - }, - "assigned_packages": { - "type": "array", - "description": "List of packages this creative is assigned to", - "items": { - "type": "object", - "properties": { - "package_id": { - "type": "string", - "description": "Package identifier" - }, - "package_name": { - "type": "string", - "description": "Human-readable package name" - }, - "assigned_date": { - "type": "string", - "format": "date-time", - "description": "When this assignment was created" - }, - "status": { - "type": "string", - "enum": [ - "active", - "paused", - "ended" - ], - "description": "Status of this specific assignment" - } - }, - "required": [ - "package_id", - "assigned_date", - "status" - ], - "additionalProperties": false - } - } - }, - "required": [ - "assignment_count" - ], - "additionalProperties": false - }, - "performance": { - "type": "object", - "description": "Aggregated performance metrics (included when include_performance=true)", - "properties": { - "impressions": { - "type": "integer", - "description": "Total impressions across all assignments", - "minimum": 0 - }, - "clicks": { - "type": "integer", - "description": "Total clicks across all assignments", - "minimum": 0 - }, - "ctr": { - "type": "number", - "description": "Click-through rate (clicks/impressions)", - "minimum": 0, - "maximum": 1 - }, - "conversion_rate": { - "type": "number", - "description": "Conversion rate across all assignments", - "minimum": 0, - "maximum": 1 - }, - "performance_score": { - "type": "number", - "description": "Aggregated performance score (0-100)", - "minimum": 0, - "maximum": 100 - }, - "last_updated": { - "type": "string", - "format": "date-time", - "description": "When performance data was last updated" - } - }, - "required": [ - "last_updated" - ], - "additionalProperties": false - }, - "sub_assets": { - "type": "array", - "description": "Sub-assets for multi-asset formats (included when include_sub_assets=true)", - "items": { - "$ref": "/schemas/v1/core/sub-asset.json" - } - } - }, - "required": [ - "creative_id", - "name", - "format", - "status", - "created_date", - "updated_date" - ], - "additionalProperties": false - } - }, - "format_summary": { - "type": "object", - "description": "Breakdown of creatives by format type", - "patternProperties": { - "^[a-zA-Z0-9_-]+$": { - "type": "integer", - "description": "Number of creatives with this format", - "minimum": 0 - } - }, - "additionalProperties": false - }, - "status_summary": { - "type": "object", - "description": "Breakdown of creatives by status", - "properties": { - "approved": { - "type": "integer", - "description": "Number of approved creatives", - "minimum": 0 - }, - "pending_review": { - "type": "integer", - "description": "Number of creatives pending review", - "minimum": 0 - }, - "rejected": { - "type": "integer", - "description": "Number of rejected creatives", - "minimum": 0 - }, - "archived": { - "type": "integer", - "description": "Number of archived creatives", - "minimum": 0 - } - }, - "additionalProperties": false - } - }, - "required": [ - "adcp_version", - "message", - "query_summary", - "pagination", - "creatives" - ], - "additionalProperties": false, - "examples": [ - { - "description": "Successful library query with results", - "data": { - "adcp_version": "1.5.0", - "message": "Found 3 creatives matching your query", - "context_id": "ctx_list_456789", - "query_summary": { - "total_matching": 3, - "returned": 3, - "filters_applied": [ - "format=video", - "status=approved" - ], - "sort_applied": { - "field": "created_date", - "direction": "desc" - } - }, - "pagination": { - "limit": 50, - "offset": 0, - "has_more": false, - "total_pages": 1, - "current_page": 1 - }, - "creatives": [ - { - "creative_id": "hero_video_30s", - "name": "Brand Hero Video 30s", - "format": "video_30s_vast", - "status": "approved", - "created_date": "2024-01-15T10:30:00Z", - "updated_date": "2024-01-15T14:20:00Z", - "snippet": "https://vast.example.com/video/123", - "snippet_type": "vast_url", - "click_url": "https://example.com/products", - "duration": 30000, - "width": 1920, - "height": 1080, - "tags": [ - "q1_2024", - "video", - "brand_awareness" - ] - } - ], - "format_summary": { - "video_30s_vast": 2, - "display_300x250": 1 - }, - "status_summary": { - "approved": 3, - "pending_review": 0, - "rejected": 0, - "archived": 0 - } - } - }, - { - "description": "Query with assignments and performance data", - "data": { - "adcp_version": "1.5.0", - "message": "Found 1 creative with performance data", - "query_summary": { - "total_matching": 1, - "returned": 1 - }, - "pagination": { - "limit": 50, - "offset": 0, - "has_more": false - }, - "creatives": [ - { - "creative_id": "hero_video_30s", - "name": "Brand Hero Video 30s", - "format": "video_30s_vast", - "status": "approved", - "created_date": "2024-01-15T10:30:00Z", - "updated_date": "2024-01-15T14:20:00Z", - "assignments": { - "assignment_count": 2, - "assigned_packages": [ - { - "package_id": "pkg_ctv_001", - "package_name": "CTV Prime Time", - "assigned_date": "2024-01-16T09:00:00Z", - "status": "active" - } - ] - }, - "performance": { - "impressions": 150000, - "clicks": 1200, - "ctr": 0.008, - "performance_score": 85.2, - "last_updated": "2024-01-20T12:00:00Z" - } - } - ] - } - } - ] -} diff --git a/tests/schemas/v1/_schemas_v1_media-buy_package-request_json.json b/tests/schemas/v1/_schemas_v1_media-buy_package-request_json.json deleted file mode 100644 index e730c27..0000000 --- a/tests/schemas/v1/_schemas_v1_media-buy_package-request_json.json +++ /dev/null @@ -1,102 +0,0 @@ -{ - "$schema": "http://json-schema.org/draft-07/schema#", - "$id": "/schemas/v1/media-buy/package-request.json", - "title": "Package Request", - "description": "Package configuration for media buy creation", - "oneOf": [ - { - "type": "object", - "description": "Package with explicit format IDs", - "properties": { - "buyer_ref": { - "type": "string", - "description": "Buyer's reference identifier for this package" - }, - "products": { - "type": "array", - "description": "Array of product IDs to include in this package", - "items": { - "type": "string" - } - }, - "format_ids": { - "type": "array", - "description": "Array of format IDs that will be used for this package - must be supported by all products", - "items": { - "type": "string", - "description": "Format ID referencing a format from list_creative_formats" - } - }, - "budget": { - "$ref": "/schemas/v1/core/budget.json" - }, - "targeting_overlay": { - "$ref": "/schemas/v1/core/targeting.json" - }, - "creative_ids": { - "type": "array", - "description": "Creative IDs to assign to this package at creation time", - "items": { - "type": "string" - } - } - }, - "required": [ - "buyer_ref", - "products", - "format_ids" - ], - "not": { - "required": [ - "format_selection" - ] - }, - "additionalProperties": false - }, - { - "type": "object", - "description": "Package with dynamic format selection", - "properties": { - "buyer_ref": { - "type": "string", - "description": "Buyer's reference identifier for this package" - }, - "products": { - "type": "array", - "description": "Array of product IDs to include in this package", - "items": { - "type": "string" - } - }, - "format_selection": { - "type": "object", - "description": "Dynamic format selection criteria" - }, - "budget": { - "$ref": "/schemas/v1/core/budget.json" - }, - "targeting_overlay": { - "$ref": "/schemas/v1/core/targeting.json" - }, - "creative_ids": { - "type": "array", - "description": "Creative IDs to assign to this package at creation time", - "items": { - "type": "string" - } - } - }, - "required": [ - "buyer_ref", - "products", - "format_selection" - ], - "not": { - "required": [ - "format_ids" - ] - }, - "additionalProperties": false - } - ] -} diff --git a/tests/schemas/v1/_schemas_v1_media-buy_sync-creatives-request_json.json b/tests/schemas/v1/_schemas_v1_media-buy_sync-creatives-request_json.json deleted file mode 100644 index 5974e44..0000000 --- a/tests/schemas/v1/_schemas_v1_media-buy_sync-creatives-request_json.json +++ /dev/null @@ -1,138 +0,0 @@ -{ - "$schema": "http://json-schema.org/draft-07/schema#", - "$id": "/schemas/v1/media-buy/sync-creatives-request.json", - "title": "Sync Creatives Request", - "description": "Request parameters for syncing creative assets with upsert semantics - supports bulk operations, patch updates, and assignment management", - "type": "object", - "properties": { - "adcp_version": { - "type": "string", - "description": "AdCP schema version for this request", - "pattern": "^\\d+\\.\\d+\\.\\d+$", - "default": "1.6.0" - }, - "creatives": { - "type": "array", - "description": "Array of creative assets to sync (create or update)", - "items": { - "$ref": "/schemas/v1/core/creative-asset.json" - }, - "maxItems": 100 - }, - "patch": { - "type": "boolean", - "default": false, - "description": "When true, only provided fields are updated (partial update). When false, entire creative is replaced (full upsert)." - }, - "assignments": { - "type": "object", - "description": "Optional bulk assignment of creatives to packages", - "patternProperties": { - "^[a-zA-Z0-9_-]+$": { - "type": "array", - "description": "Array of package IDs to assign this creative to", - "items": { - "type": "string" - } - } - }, - "additionalProperties": false - }, - "delete_missing": { - "type": "boolean", - "default": false, - "description": "When true, creatives not included in this sync will be archived. Use with caution for full library replacement." - }, - "dry_run": { - "type": "boolean", - "default": false, - "description": "When true, preview changes without applying them. Returns what would be created/updated/deleted." - }, - "validation_mode": { - "type": "string", - "enum": [ - "strict", - "lenient" - ], - "default": "strict", - "description": "Validation strictness. 'strict' fails entire sync on any validation error. 'lenient' processes valid creatives and reports errors." - }, - "push_notification_config": { - "$ref": "/schemas/v1/core/push-notification-config.json", - "description": "Optional webhook configuration for async sync notifications. Publisher will send webhook when sync completes if operation takes longer than immediate response time (typically for large bulk operations or manual approval/HITL)." - } - }, - "required": [ - "creatives" - ], - "additionalProperties": false, - "examples": [ - { - "description": "Full sync with hosted video creative", - "data": { - "creatives": [ - { - "creative_id": "hero_video_30s", - "name": "Brand Hero Video 30s", - "format_id": { - "agent_url": "https://creative.adcontextprotocol.org", - "id": "video_standard_30s" - }, - "assets": { - "video": { - "asset_type": "video", - "url": "https://cdn.example.com/hero-video.mp4", - "width": 1920, - "height": 1080, - "duration_ms": 30000 - } - }, - "tags": [ - "q1_2024", - "video" - ] - } - ], - "assignments": { - "hero_video_30s": [ - "pkg_ctv_001", - "pkg_ctv_002" - ] - } - } - }, - { - "description": "Generative creative with approval", - "data": { - "creatives": [ - { - "creative_id": "holiday_hero", - "name": "Holiday Campaign Hero", - "format_id": { - "agent_url": "https://publisher.com/.well-known/adcp/sales", - "id": "premium_bespoke_display" - }, - "assets": { - "promoted_offerings": { - "asset_type": "promoted_offerings", - "url": "https://retailer.com", - "colors": { - "primary": "#C41E3A", - "secondary": "#165B33" - } - }, - "generation_prompt": { - "asset_type": "text", - "content": "Create a warm, festive holiday campaign featuring winter products" - } - }, - "tags": [ - "holiday", - "q4_2024" - ] - } - ] - } - } - ] -} diff --git a/tests/schemas/v1/_schemas_v1_media-buy_sync-creatives-response_json.json b/tests/schemas/v1/_schemas_v1_media-buy_sync-creatives-response_json.json deleted file mode 100644 index 2a01698..0000000 --- a/tests/schemas/v1/_schemas_v1_media-buy_sync-creatives-response_json.json +++ /dev/null @@ -1,124 +0,0 @@ -{ - "$schema": "http://json-schema.org/draft-07/schema#", - "$id": "/schemas/v1/media-buy/sync-creatives-response.json", - "title": "Sync Creatives Response", - "description": "Response from creative sync operation with results for each creative", - "type": "object", - "properties": { - "adcp_version": { - "type": "string", - "description": "AdCP schema version used for this response", - "pattern": "^\\d+\\.\\d+\\.\\d+$" - }, - "message": { - "type": "string", - "description": "Human-readable result message (e.g., 'Synced 3 creatives: 2 created, 1 updated')" - }, - "context_id": { - "type": "string", - "description": "Context ID for tracking async operations and conversational approval workflows" - }, - "status": { - "$ref": "/schemas/v1/enums/task-status.json", - "description": "Current task state - 'completed' for immediate success, 'working' for operations under 120s, 'submitted' for long-running operations", - "default": "completed" - }, - "task_id": { - "type": "string", - "description": "Unique identifier for tracking this async operation (present for submitted/working status)" - }, - "dry_run": { - "type": "boolean", - "description": "Whether this was a dry run (no actual changes made)" - }, - "creatives": { - "type": "array", - "description": "Results for each creative processed", - "items": { - "type": "object", - "properties": { - "creative_id": { - "type": "string", - "description": "Creative ID from the request" - }, - "action": { - "type": "string", - "enum": [ - "created", - "updated", - "unchanged", - "failed", - "deleted" - ], - "description": "Action taken for this creative" - }, - "platform_id": { - "type": "string", - "description": "Platform-specific ID assigned to the creative" - }, - "changes": { - "type": "array", - "description": "Field names that were modified (only present when action='updated')", - "items": { - "type": "string" - } - }, - "errors": { - "type": "array", - "description": "Validation or processing errors (only present when action='failed')", - "items": { - "type": "string" - } - }, - "warnings": { - "type": "array", - "description": "Non-fatal warnings about this creative", - "items": { - "type": "string" - } - }, - "preview_url": { - "type": "string", - "format": "uri", - "description": "Preview URL for generative creatives (only present for generative formats)" - }, - "expires_at": { - "type": "string", - "format": "date-time", - "description": "ISO 8601 timestamp when preview link expires (only present when preview_url exists)" - }, - "assigned_to": { - "type": "array", - "description": "Package IDs this creative was successfully assigned to (only present when assignments were requested)", - "items": { - "type": "string" - } - }, - "assignment_errors": { - "type": "object", - "description": "Assignment errors by package ID (only present when assignment failures occurred)", - "patternProperties": { - "^[a-zA-Z0-9_-]+$": { - "type": "string", - "description": "Error message for this package assignment" - } - }, - "additionalProperties": false - } - }, - "required": [ - "creative_id", - "action" - ], - "additionalProperties": false - } - } - }, - "required": [ - "adcp_version", - "message", - "status", - "creatives" - ], - "additionalProperties": false -} diff --git a/tests/schemas/v1/_schemas_v1_media-buy_update-media-buy-request_json.json b/tests/schemas/v1/_schemas_v1_media-buy_update-media-buy-request_json.json deleted file mode 100644 index 3cf5193..0000000 --- a/tests/schemas/v1/_schemas_v1_media-buy_update-media-buy-request_json.json +++ /dev/null @@ -1,106 +0,0 @@ -{ - "$schema": "http://json-schema.org/draft-07/schema#", - "$id": "/schemas/v1/media-buy/update-media-buy-request.json", - "title": "Update Media Buy Request", - "description": "Request parameters for updating campaign and package settings", - "type": "object", - "properties": { - "adcp_version": { - "type": "string", - "description": "AdCP schema version for this request", - "pattern": "^\\d+\\.\\d+\\.\\d+$", - "default": "1.6.0" - }, - "media_buy_id": { - "type": "string", - "description": "Publisher's ID of the media buy to update" - }, - "buyer_ref": { - "type": "string", - "description": "Buyer's reference for the media buy to update" - }, - "active": { - "type": "boolean", - "description": "Pause/resume the entire media buy" - }, - "start_time": { - "$ref": "/schemas/v1/core/start-timing.json" - }, - "end_time": { - "type": "string", - "format": "date-time", - "description": "New end date/time in ISO 8601 format" - }, - "budget": { - "type": "number", - "description": "Updated total budget for this media buy. Currency is determined by the pricing_option_id selected in each package.", - "minimum": 0 - }, - "packages": { - "type": "array", - "description": "Package-specific updates", - "items": { - "type": "object", - "properties": { - "package_id": { - "type": "string", - "description": "Publisher's ID of package to update" - }, - "buyer_ref": { - "type": "string", - "description": "Buyer's reference for the package to update" - }, - "budget": { - "type": "number", - "description": "Updated budget allocation for this package in the currency specified by the pricing option", - "minimum": 0 - }, - "active": { - "type": "boolean", - "description": "Pause/resume specific package" - }, - "targeting_overlay": { - "$ref": "/schemas/v1/core/targeting.json" - }, - "creative_ids": { - "type": "array", - "description": "Update creative assignments", - "items": { - "type": "string" - } - } - }, - "oneOf": [ - { - "required": [ - "package_id" - ] - }, - { - "required": [ - "buyer_ref" - ] - } - ], - "additionalProperties": false - } - }, - "push_notification_config": { - "$ref": "/schemas/v1/core/push-notification-config.json", - "description": "Optional webhook configuration for async update notifications. Publisher will send webhook when update completes if operation takes longer than immediate response time." - } - }, - "oneOf": [ - { - "required": [ - "media_buy_id" - ] - }, - { - "required": [ - "buyer_ref" - ] - } - ], - "additionalProperties": false -} diff --git a/tests/schemas/v1/_schemas_v1_media-buy_update-media-buy-response_json.json b/tests/schemas/v1/_schemas_v1_media-buy_update-media-buy-response_json.json deleted file mode 100644 index ebd3d13..0000000 --- a/tests/schemas/v1/_schemas_v1_media-buy_update-media-buy-response_json.json +++ /dev/null @@ -1,74 +0,0 @@ -{ - "$schema": "http://json-schema.org/draft-07/schema#", - "$id": "/schemas/v1/media-buy/update-media-buy-response.json", - "title": "Update Media Buy Response", - "description": "Response payload for update_media_buy task", - "type": "object", - "properties": { - "adcp_version": { - "type": "string", - "description": "AdCP schema version used for this response", - "pattern": "^\\d+\\.\\d+\\.\\d+$" - }, - "status": { - "$ref": "/schemas/v1/enums/task-status.json", - "description": "Current task state - 'completed' for immediate success, 'working' for operations under 120s, 'submitted' for long-running operations, 'input-required' if approval needed" - }, - "task_id": { - "type": "string", - "description": "Unique identifier for tracking this async operation (present for submitted/working status)" - }, - "media_buy_id": { - "type": "string", - "description": "Publisher's identifier for the media buy" - }, - "buyer_ref": { - "type": "string", - "description": "Buyer's reference identifier for the media buy" - }, - "implementation_date": { - "type": [ - "string", - "null" - ], - "format": "date-time", - "description": "ISO 8601 timestamp when changes take effect (null if pending approval)" - }, - "affected_packages": { - "type": "array", - "description": "Array of packages that were modified", - "items": { - "type": "object", - "properties": { - "package_id": { - "type": "string", - "description": "Publisher's package identifier" - }, - "buyer_ref": { - "type": "string", - "description": "Buyer's reference for the package" - } - }, - "required": [ - "package_id", - "buyer_ref" - ], - "additionalProperties": false - } - }, - "errors": { - "type": "array", - "description": "Task-specific errors and warnings (e.g., partial update failures)", - "items": { - "$ref": "/schemas/v1/core/error.json" - } - } - }, - "required": [ - "adcp_version", - "status", - "media_buy_id", - "buyer_ref" - ], - "additionalProperties": false -} diff --git a/tests/schemas/v1/_schemas_v1_pricing-options_cpc-option_json.json b/tests/schemas/v1/_schemas_v1_pricing-options_cpc-option_json.json deleted file mode 100644 index 0114da7..0000000 --- a/tests/schemas/v1/_schemas_v1_pricing-options_cpc-option_json.json +++ /dev/null @@ -1,36 +0,0 @@ -{ - "$schema": "http://json-schema.org/draft-07/schema#", - "$id": "/schemas/v1/pricing-options/cpc-option.json", - "title": "CPC Pricing Option", - "description": "Cost Per Click fixed-rate pricing for performance-driven advertising campaigns", - "type": "object", - "properties": { - "pricing_option_id": { - "type": "string", - "description": "Unique identifier for this pricing option within the product (e.g., 'cpc_usd_fixed')" - }, - "pricing_model": { - "type": "string", - "const": "cpc", - "description": "Cost per click" - }, - "rate": { - "type": "number", - "description": "Fixed CPC rate (cost per click)", - "minimum": 0 - }, - "currency": { - "type": "string", - "description": "ISO 4217 currency code", - "pattern": "^[A-Z]{3}$", - "examples": ["USD", "EUR", "GBP", "JPY"] - }, - "min_spend_per_package": { - "type": "number", - "description": "Minimum spend requirement per package using this pricing option, in the specified currency", - "minimum": 0 - } - }, - "required": ["pricing_option_id", "pricing_model", "rate", "currency"], - "additionalProperties": false -} diff --git a/tests/schemas/v1/_schemas_v1_pricing-options_cpcv-option_json.json b/tests/schemas/v1/_schemas_v1_pricing-options_cpcv-option_json.json deleted file mode 100644 index f6d0e5e..0000000 --- a/tests/schemas/v1/_schemas_v1_pricing-options_cpcv-option_json.json +++ /dev/null @@ -1,36 +0,0 @@ -{ - "$schema": "http://json-schema.org/draft-07/schema#", - "$id": "/schemas/v1/pricing-options/cpcv-option.json", - "title": "CPCV Pricing Option", - "description": "Cost Per Completed View (100% video/audio completion) fixed-rate pricing", - "type": "object", - "properties": { - "pricing_option_id": { - "type": "string", - "description": "Unique identifier for this pricing option within the product (e.g., 'cpcv_usd_guaranteed')" - }, - "pricing_model": { - "type": "string", - "const": "cpcv", - "description": "Cost per completed view (100% completion)" - }, - "rate": { - "type": "number", - "description": "Fixed CPCV rate (cost per 100% completion)", - "minimum": 0 - }, - "currency": { - "type": "string", - "description": "ISO 4217 currency code", - "pattern": "^[A-Z]{3}$", - "examples": ["USD", "EUR", "GBP", "JPY"] - }, - "min_spend_per_package": { - "type": "number", - "description": "Minimum spend requirement per package using this pricing option, in the specified currency", - "minimum": 0 - } - }, - "required": ["pricing_option_id", "pricing_model", "rate", "currency"], - "additionalProperties": false -} diff --git a/tests/schemas/v1/_schemas_v1_pricing-options_cpm-auction-option_json.json b/tests/schemas/v1/_schemas_v1_pricing-options_cpm-auction-option_json.json deleted file mode 100644 index 4003e8f..0000000 --- a/tests/schemas/v1/_schemas_v1_pricing-options_cpm-auction-option_json.json +++ /dev/null @@ -1,63 +0,0 @@ -{ - "$schema": "http://json-schema.org/draft-07/schema#", - "$id": "/schemas/v1/pricing-options/cpm-auction-option.json", - "title": "CPM Auction Pricing Option", - "description": "Cost Per Mille (cost per 1,000 impressions) with auction-based pricing - common for programmatic/non-guaranteed inventory", - "type": "object", - "properties": { - "pricing_option_id": { - "type": "string", - "description": "Unique identifier for this pricing option within the product (e.g., 'cpm_usd_auction')" - }, - "pricing_model": { - "type": "string", - "const": "cpm", - "description": "Cost per 1,000 impressions" - }, - "currency": { - "type": "string", - "description": "ISO 4217 currency code", - "pattern": "^[A-Z]{3}$", - "examples": ["USD", "EUR", "GBP", "JPY"] - }, - "price_guidance": { - "type": "object", - "description": "Pricing guidance for auction-based CPM bidding", - "properties": { - "floor": { - "type": "number", - "description": "Minimum bid price - publisher will reject bids under this value", - "minimum": 0 - }, - "p25": { - "type": "number", - "description": "25th percentile winning price", - "minimum": 0 - }, - "p50": { - "type": "number", - "description": "Median winning price", - "minimum": 0 - }, - "p75": { - "type": "number", - "description": "75th percentile winning price", - "minimum": 0 - }, - "p90": { - "type": "number", - "description": "90th percentile winning price", - "minimum": 0 - } - }, - "required": ["floor"] - }, - "min_spend_per_package": { - "type": "number", - "description": "Minimum spend requirement per package using this pricing option, in the specified currency", - "minimum": 0 - } - }, - "required": ["pricing_option_id", "pricing_model", "price_guidance", "currency"], - "additionalProperties": false -} diff --git a/tests/schemas/v1/_schemas_v1_pricing-options_cpm-fixed-option_json.json b/tests/schemas/v1/_schemas_v1_pricing-options_cpm-fixed-option_json.json deleted file mode 100644 index 87c33c2..0000000 --- a/tests/schemas/v1/_schemas_v1_pricing-options_cpm-fixed-option_json.json +++ /dev/null @@ -1,36 +0,0 @@ -{ - "$schema": "http://json-schema.org/draft-07/schema#", - "$id": "/schemas/v1/pricing-options/cpm-fixed-option.json", - "title": "CPM Fixed Rate Pricing Option", - "description": "Cost Per Mille (cost per 1,000 impressions) with guaranteed fixed rate - common for direct/guaranteed deals", - "type": "object", - "properties": { - "pricing_option_id": { - "type": "string", - "description": "Unique identifier for this pricing option within the product (e.g., 'cpm_usd_guaranteed')" - }, - "pricing_model": { - "type": "string", - "const": "cpm", - "description": "Cost per 1,000 impressions" - }, - "rate": { - "type": "number", - "description": "Fixed CPM rate (cost per 1,000 impressions)", - "minimum": 0 - }, - "currency": { - "type": "string", - "description": "ISO 4217 currency code", - "pattern": "^[A-Z]{3}$", - "examples": ["USD", "EUR", "GBP", "JPY"] - }, - "min_spend_per_package": { - "type": "number", - "description": "Minimum spend requirement per package using this pricing option, in the specified currency", - "minimum": 0 - } - }, - "required": ["pricing_option_id", "pricing_model", "rate", "currency"], - "additionalProperties": false -} diff --git a/tests/schemas/v1/_schemas_v1_pricing-options_cpp-option_json.json b/tests/schemas/v1/_schemas_v1_pricing-options_cpp-option_json.json deleted file mode 100644 index 5ee9ed0..0000000 --- a/tests/schemas/v1/_schemas_v1_pricing-options_cpp-option_json.json +++ /dev/null @@ -1,54 +0,0 @@ -{ - "$schema": "http://json-schema.org/draft-07/schema#", - "$id": "/schemas/v1/pricing-options/cpp-option.json", - "title": "CPP Pricing Option", - "description": "Cost Per Point (Gross Rating Point) fixed-rate pricing for TV and audio campaigns requiring demographic measurement", - "type": "object", - "properties": { - "pricing_option_id": { - "type": "string", - "description": "Unique identifier for this pricing option within the product (e.g., 'cpp_usd_p18-49')" - }, - "pricing_model": { - "type": "string", - "const": "cpp", - "description": "Cost per Gross Rating Point" - }, - "rate": { - "type": "number", - "description": "Fixed CPP rate (cost per rating point)", - "minimum": 0 - }, - "currency": { - "type": "string", - "description": "ISO 4217 currency code", - "pattern": "^[A-Z]{3}$", - "examples": ["USD", "EUR", "GBP", "JPY"] - }, - "parameters": { - "type": "object", - "description": "CPP-specific parameters for demographic targeting and GRP requirements", - "properties": { - "demographic": { - "type": "string", - "pattern": "^[PMWAC][0-9]{2}(-[0-9]{2}|\\+)$", - "description": "Target demographic in Nielsen format: P/M/W/A/C + age range. Examples: P18-49 (Persons 18-49), M25-54 (Men 25-54), W35+ (Women 35+), A18-34 (Adults 18-34), C2-11 (Children 2-11)" - }, - "min_points": { - "type": "number", - "description": "Minimum GRPs/TRPs required for this pricing option", - "minimum": 0 - } - }, - "required": ["demographic"], - "additionalProperties": false - }, - "min_spend_per_package": { - "type": "number", - "description": "Minimum spend requirement per package using this pricing option, in the specified currency", - "minimum": 0 - } - }, - "required": ["pricing_option_id", "pricing_model", "rate", "currency", "parameters"], - "additionalProperties": false -} diff --git a/tests/schemas/v1/_schemas_v1_pricing-options_cpv-option_json.json b/tests/schemas/v1/_schemas_v1_pricing-options_cpv-option_json.json deleted file mode 100644 index 827678b..0000000 --- a/tests/schemas/v1/_schemas_v1_pricing-options_cpv-option_json.json +++ /dev/null @@ -1,67 +0,0 @@ -{ - "$schema": "http://json-schema.org/draft-07/schema#", - "$id": "/schemas/v1/pricing-options/cpv-option.json", - "title": "CPV Pricing Option", - "description": "Cost Per View (at publisher-defined threshold) fixed-rate pricing for video/audio", - "type": "object", - "properties": { - "pricing_option_id": { - "type": "string", - "description": "Unique identifier for this pricing option within the product (e.g., 'cpv_usd_50pct')" - }, - "pricing_model": { - "type": "string", - "const": "cpv", - "description": "Cost per view at threshold" - }, - "rate": { - "type": "number", - "description": "Fixed CPV rate (cost per view)", - "minimum": 0 - }, - "currency": { - "type": "string", - "description": "ISO 4217 currency code", - "pattern": "^[A-Z]{3}$", - "examples": ["USD", "EUR", "GBP", "JPY"] - }, - "parameters": { - "type": "object", - "description": "CPV-specific parameters defining the view threshold", - "properties": { - "view_threshold": { - "oneOf": [ - { - "type": "number", - "description": "Percentage completion threshold for CPV pricing (0.0 to 1.0, e.g., 0.5 = 50% completion)", - "minimum": 0, - "maximum": 1 - }, - { - "type": "object", - "description": "Time-based view threshold for CPV pricing", - "properties": { - "duration_seconds": { - "type": "integer", - "description": "Seconds of viewing required (e.g., 30 for YouTube-style '30 seconds = view')", - "minimum": 1 - } - }, - "required": ["duration_seconds"], - "additionalProperties": false - } - ] - } - }, - "required": ["view_threshold"], - "additionalProperties": false - }, - "min_spend_per_package": { - "type": "number", - "description": "Minimum spend requirement per package using this pricing option, in the specified currency", - "minimum": 0 - } - }, - "required": ["pricing_option_id", "pricing_model", "rate", "currency", "parameters"], - "additionalProperties": false -} diff --git a/tests/schemas/v1/_schemas_v1_pricing-options_flat-rate-option_json.json b/tests/schemas/v1/_schemas_v1_pricing-options_flat-rate-option_json.json deleted file mode 100644 index bb14f9f..0000000 --- a/tests/schemas/v1/_schemas_v1_pricing-options_flat-rate-option_json.json +++ /dev/null @@ -1,82 +0,0 @@ -{ - "$schema": "http://json-schema.org/draft-07/schema#", - "$id": "/schemas/v1/pricing-options/flat-rate-option.json", - "title": "Flat Rate Pricing Option", - "description": "Flat rate pricing for DOOH, sponsorships, and time-based campaigns - fixed cost regardless of delivery volume", - "type": "object", - "properties": { - "pricing_option_id": { - "type": "string", - "description": "Unique identifier for this pricing option within the product (e.g., 'flat_rate_usd_24h_takeover')" - }, - "pricing_model": { - "type": "string", - "const": "flat_rate", - "description": "Fixed cost regardless of delivery volume" - }, - "rate": { - "type": "number", - "description": "Flat rate cost", - "minimum": 0 - }, - "currency": { - "type": "string", - "description": "ISO 4217 currency code", - "pattern": "^[A-Z]{3}$", - "examples": ["USD", "EUR", "GBP", "JPY"] - }, - "is_fixed": { - "type": "boolean", - "description": "Whether this is a fixed rate (true) or auction-based (false)", - "const": true - }, - "parameters": { - "type": "object", - "description": "Flat rate parameters for DOOH and time-based campaigns", - "properties": { - "duration_hours": { - "type": "number", - "description": "Duration in hours for time-based flat rate pricing (DOOH)", - "minimum": 0 - }, - "sov_percentage": { - "type": "number", - "description": "Guaranteed share of voice as percentage (DOOH, 0-100)", - "minimum": 0, - "maximum": 100 - }, - "loop_duration_seconds": { - "type": "integer", - "description": "Duration of ad loop rotation in seconds (DOOH)", - "minimum": 1 - }, - "min_plays_per_hour": { - "type": "integer", - "description": "Minimum number of times ad plays per hour (DOOH frequency guarantee)", - "minimum": 0 - }, - "venue_package": { - "type": "string", - "description": "Named venue package identifier for DOOH (e.g., 'times_square_network', 'airport_terminals')" - }, - "estimated_impressions": { - "type": "integer", - "description": "Estimated impressions for this flat rate option (informational, commonly used with SOV or time-based DOOH)", - "minimum": 0 - }, - "daypart": { - "type": "string", - "description": "Specific daypart for time-based pricing (e.g., 'morning_commute', 'evening_prime', 'overnight')" - } - }, - "additionalProperties": false - }, - "min_spend_per_package": { - "type": "number", - "description": "Minimum spend requirement per package using this pricing option, in the specified currency", - "minimum": 0 - } - }, - "required": ["pricing_option_id", "pricing_model", "currency", "is_fixed", "rate"], - "additionalProperties": false -} diff --git a/tests/schemas/v1/_schemas_v1_signals_activate-signal-request_json.json b/tests/schemas/v1/_schemas_v1_signals_activate-signal-request_json.json deleted file mode 100644 index 94ee048..0000000 --- a/tests/schemas/v1/_schemas_v1_signals_activate-signal-request_json.json +++ /dev/null @@ -1,32 +0,0 @@ -{ - "$schema": "http://json-schema.org/draft-07/schema#", - "$id": "/schemas/v1/signals/activate-signal-request.json", - "title": "Activate Signal Request", - "description": "Request parameters for activating a signal on a specific platform/account", - "type": "object", - "properties": { - "adcp_version": { - "type": "string", - "description": "AdCP schema version for this request", - "pattern": "^\\d+\\.\\d+\\.\\d+$", - "default": "1.5.0" - }, - "signal_agent_segment_id": { - "type": "string", - "description": "The universal identifier for the signal to activate" - }, - "platform": { - "type": "string", - "description": "The target platform for activation" - }, - "account": { - "type": "string", - "description": "Account identifier (required for account-specific activation)" - } - }, - "required": [ - "signal_agent_segment_id", - "platform" - ], - "additionalProperties": false -} diff --git a/tests/schemas/v1/_schemas_v1_signals_activate-signal-response_json.json b/tests/schemas/v1/_schemas_v1_signals_activate-signal-response_json.json deleted file mode 100644 index 8220868..0000000 --- a/tests/schemas/v1/_schemas_v1_signals_activate-signal-response_json.json +++ /dev/null @@ -1,55 +0,0 @@ -{ - "$schema": "http://json-schema.org/draft-07/schema#", - "$id": "/schemas/v1/signals/activate-signal-response.json", - "title": "Activate Signal Response", - "description": "Response payload for activate_signal task", - "type": "object", - "properties": { - "adcp_version": { - "type": "string", - "description": "AdCP schema version used for this response", - "pattern": "^\\d+\\.\\d+\\.\\d+$" - }, - "task_id": { - "type": "string", - "description": "Unique identifier for tracking the activation" - }, - "status": { - "type": "string", - "description": "Current status", - "enum": [ - "pending", - "processing", - "deployed", - "failed" - ] - }, - "decisioning_platform_segment_id": { - "type": "string", - "description": "The platform-specific ID to use once activated" - }, - "estimated_activation_duration_minutes": { - "type": "number", - "description": "Estimated time to complete (optional)", - "minimum": 0 - }, - "deployed_at": { - "type": "string", - "format": "date-time", - "description": "Timestamp when activation completed (optional)" - }, - "errors": { - "type": "array", - "description": "Task-specific errors and warnings (e.g., activation failures, platform issues)", - "items": { - "$ref": "/schemas/v1/core/error.json" - } - } - }, - "required": [ - "adcp_version", - "task_id", - "status" - ], - "additionalProperties": false -} diff --git a/tests/schemas/v1/_schemas_v1_signals_get-signals-request_json.json b/tests/schemas/v1/_schemas_v1_signals_get-signals-request_json.json deleted file mode 100644 index aae6b9f..0000000 --- a/tests/schemas/v1/_schemas_v1_signals_get-signals-request_json.json +++ /dev/null @@ -1,122 +0,0 @@ -{ - "$schema": "http://json-schema.org/draft-07/schema#", - "$id": "/schemas/v1/signals/get-signals-request.json", - "title": "Get Signals Request", - "description": "Request parameters for discovering signals based on description", - "type": "object", - "properties": { - "adcp_version": { - "type": "string", - "description": "AdCP schema version for this request", - "pattern": "^\\d+\\.\\d+\\.\\d+$", - "default": "1.5.0" - }, - "signal_spec": { - "type": "string", - "description": "Natural language description of the desired signals" - }, - "deliver_to": { - "type": "object", - "description": "Where the signals need to be delivered", - "properties": { - "platforms": { - "oneOf": [ - { - "type": "string", - "const": "all" - }, - { - "type": "array", - "items": { - "type": "string" - } - } - ], - "description": "Target platforms for signal deployment" - }, - "accounts": { - "type": "array", - "description": "Specific platform-account combinations", - "items": { - "type": "object", - "properties": { - "platform": { - "type": "string", - "description": "Platform identifier" - }, - "account": { - "type": "string", - "description": "Account identifier on that platform" - } - }, - "required": [ - "platform", - "account" - ], - "additionalProperties": false - } - }, - "countries": { - "type": "array", - "description": "Countries where signals will be used (ISO codes)", - "items": { - "type": "string", - "pattern": "^[A-Z]{2}$" - } - } - }, - "required": [ - "platforms", - "countries" - ], - "additionalProperties": false - }, - "filters": { - "type": "object", - "description": "Filters to refine results", - "properties": { - "catalog_types": { - "type": "array", - "description": "Filter by catalog type", - "items": { - "type": "string", - "enum": [ - "marketplace", - "custom", - "owned" - ] - } - }, - "data_providers": { - "type": "array", - "description": "Filter by specific data providers", - "items": { - "type": "string" - } - }, - "max_cpm": { - "type": "number", - "description": "Maximum CPM price filter", - "minimum": 0 - }, - "min_coverage_percentage": { - "type": "number", - "description": "Minimum coverage requirement", - "minimum": 0, - "maximum": 100 - } - }, - "additionalProperties": false - }, - "max_results": { - "type": "integer", - "description": "Maximum number of results to return", - "minimum": 1 - } - }, - "required": [ - "signal_spec", - "deliver_to" - ], - "additionalProperties": false -} diff --git a/tests/schemas/v1/_schemas_v1_signals_get-signals-response_json.json b/tests/schemas/v1/_schemas_v1_signals_get-signals-response_json.json deleted file mode 100644 index 1e2ba1f..0000000 --- a/tests/schemas/v1/_schemas_v1_signals_get-signals-response_json.json +++ /dev/null @@ -1,155 +0,0 @@ -{ - "$schema": "http://json-schema.org/draft-07/schema#", - "$id": "/schemas/v1/signals/get-signals-response.json", - "title": "Get Signals Response", - "description": "Response payload for get_signals task", - "type": "object", - "properties": { - "adcp_version": { - "type": "string", - "description": "AdCP schema version used for this response", - "pattern": "^\\d+\\.\\d+\\.\\d+$" - }, - "message": { - "type": "string", - "description": "Human-readable summary of the signal discovery results" - }, - "context_id": { - "type": "string", - "description": "Session continuity identifier for follow-up requests" - }, - "signals": { - "type": "array", - "description": "Array of matching signals", - "items": { - "type": "object", - "properties": { - "signal_agent_segment_id": { - "type": "string", - "description": "Unique identifier for the signal" - }, - "name": { - "type": "string", - "description": "Human-readable signal name" - }, - "description": { - "type": "string", - "description": "Detailed signal description" - }, - "signal_type": { - "type": "string", - "description": "Type of signal", - "enum": [ - "marketplace", - "custom", - "owned" - ] - }, - "data_provider": { - "type": "string", - "description": "Name of the data provider" - }, - "coverage_percentage": { - "type": "number", - "description": "Percentage of audience coverage", - "minimum": 0, - "maximum": 100 - }, - "deployments": { - "type": "array", - "description": "Array of platform deployments", - "items": { - "type": "object", - "properties": { - "platform": { - "type": "string", - "description": "Platform name" - }, - "account": { - "type": [ - "string", - "null" - ], - "description": "Specific account if applicable" - }, - "is_live": { - "type": "boolean", - "description": "Whether signal is currently active" - }, - "scope": { - "type": "string", - "description": "Deployment scope", - "enum": [ - "platform-wide", - "account-specific" - ] - }, - "decisioning_platform_segment_id": { - "type": "string", - "description": "Platform-specific segment ID" - }, - "estimated_activation_duration_minutes": { - "type": "number", - "description": "Time to activate if not live", - "minimum": 0 - } - }, - "required": [ - "platform", - "is_live", - "scope" - ], - "additionalProperties": false - } - }, - "pricing": { - "type": "object", - "description": "Pricing information", - "properties": { - "cpm": { - "type": "number", - "description": "Cost per thousand impressions", - "minimum": 0 - }, - "currency": { - "type": "string", - "description": "Currency code", - "pattern": "^[A-Z]{3}$" - } - }, - "required": [ - "cpm", - "currency" - ], - "additionalProperties": false - } - }, - "required": [ - "signal_agent_segment_id", - "name", - "description", - "signal_type", - "data_provider", - "coverage_percentage", - "deployments", - "pricing" - ], - "additionalProperties": false - } - }, - "errors": { - "type": "array", - "description": "Task-specific errors and warnings (e.g., signal discovery or pricing issues)", - "items": { - "$ref": "/schemas/v1/core/error.json" - } - } - }, - "required": [ - "adcp_version", - "message", - "context_id", - "signals" - ], - "additionalProperties": false -} diff --git a/tests/schemas/v1/index.json b/tests/schemas/v1/index.json deleted file mode 100644 index 9fbfc95..0000000 --- a/tests/schemas/v1/index.json +++ /dev/null @@ -1,317 +0,0 @@ -{ - "$schema": "http://json-schema.org/draft-07/schema#", - "$id": "/schemas/v1/index.json", - "title": "AdCP Schema Registry v1", - "version": "1.0.0", - "description": "Registry of all AdCP JSON schemas for validation and discovery", - "adcp_version": "1.6.1", - "standard_formats_version": "1.0.0", - "versioning": { - "note": "All request/response schemas include adcp_version field. Compatibility follows semantic versioning rules." - }, - "lastUpdated": "2025-10-04", - "baseUrl": "/schemas/v1", - "schemas": { - "core": { - "description": "Core data models used throughout AdCP", - "schemas": { - "product": { - "$ref": "/schemas/v1/core/product.json", - "description": "Represents available advertising inventory" - }, - "media-buy": { - "$ref": "/schemas/v1/core/media-buy.json", - "description": "Represents a purchased advertising campaign" - }, - "package": { - "$ref": "/schemas/v1/core/package.json", - "description": "A specific product within a media buy (line item)" - }, - "creative-asset": { - "$ref": "/schemas/v1/core/creative-asset.json", - "description": "Creative asset for upload to library - supports both hosted assets and third-party snippets" - }, - "targeting": { - "$ref": "/schemas/v1/core/targeting.json", - "description": "Audience targeting criteria" - }, - "budget": { - "$ref": "/schemas/v1/core/budget.json", - "description": "Budget configuration for a media buy or package" - }, - "frequency-cap": { - "$ref": "/schemas/v1/core/frequency-cap.json", - "description": "Frequency capping settings" - }, - "format": { - "$ref": "/schemas/v1/core/format.json", - "description": "Represents a creative format with its requirements" - }, - "measurement": { - "$ref": "/schemas/v1/core/measurement.json", - "description": "Measurement capabilities included with a product" - }, - "creative-policy": { - "$ref": "/schemas/v1/core/creative-policy.json", - "description": "Creative requirements and restrictions for a product" - }, - "response": { - "$ref": "/schemas/v1/core/response.json", - "description": "Standard response structure (MCP)" - }, - "error": { - "$ref": "/schemas/v1/core/error.json", - "description": "Standard error structure" - }, - "sub-asset": { - "$ref": "/schemas/v1/core/sub-asset.json", - "description": "Sub-asset for multi-asset creative formats" - }, - "creative-assignment": { - "$ref": "/schemas/v1/core/creative-assignment.json", - "description": "Assignment of a creative asset to a package" - }, - "creative-library-item": { - "$ref": "/schemas/v1/core/creative-library-item.json", - "description": "Creative asset as it appears in the centralized library" - }, - "performance-feedback": { - "$ref": "/schemas/v1/core/performance-feedback.json", - "description": "Performance feedback data for a media buy or package" - }, - "property": { - "$ref": "/schemas/v1/core/property.json", - "description": "An advertising property that can be validated via adagents.json" - } - } - }, - "enums": { - "description": "Enumerated types and constants", - "schemas": { - "delivery-type": { - "$ref": "/schemas/v1/enums/delivery-type.json", - "description": "Type of inventory delivery" - }, - "media-buy-status": { - "$ref": "/schemas/v1/enums/media-buy-status.json", - "description": "Status of a media buy" - }, - "package-status": { - "$ref": "/schemas/v1/enums/package-status.json", - "description": "Status of a package" - }, - "creative-status": { - "$ref": "/schemas/v1/enums/creative-status.json", - "description": "Status of a creative asset" - }, - "pacing": { - "$ref": "/schemas/v1/enums/pacing.json", - "description": "Budget pacing strategy" - }, - "frequency-cap-scope": { - "$ref": "/schemas/v1/enums/frequency-cap-scope.json", - "description": "Scope for frequency cap application" - }, - "standard-format-ids": { - "$ref": "/schemas/v1/enums/standard-format-ids.json", - "description": "Enumeration of all standard creative format identifiers" - }, - "snippet-type": { - "$ref": "/schemas/v1/enums/snippet-type.json", - "description": "Types of third-party creative snippets (VAST, HTML, JavaScript, etc.)" - }, - "identifier-types": { - "$ref": "/schemas/v1/enums/identifier-types.json", - "description": "Valid identifier types for property identification across different media types" - }, - "task-status": { - "$ref": "/schemas/v1/enums/task-status.json", - "description": "Standardized task status values based on A2A TaskState enum" - } - } - }, - "media-buy": { - "description": "Media buy task request/response schemas", - "supporting-schemas": { - "package-request": { - "$ref": "/schemas/v1/media-buy/package-request.json", - "description": "Package configuration for media buy creation - used within create_media_buy request" - } - }, - "tasks": { - "get-products": { - "request": { - "$ref": "/schemas/v1/media-buy/get-products-request.json", - "description": "Request parameters for discovering available advertising products" - }, - "response": { - "$ref": "/schemas/v1/media-buy/get-products-response.json", - "description": "Response payload for get_products task" - } - }, - "list-creative-formats": { - "request": { - "$ref": "/schemas/v1/media-buy/list-creative-formats-request.json", - "description": "Request parameters for discovering supported creative formats" - }, - "response": { - "$ref": "/schemas/v1/media-buy/list-creative-formats-response.json", - "description": "Response payload for list_creative_formats task" - } - }, - "create-media-buy": { - "request": { - "$ref": "/schemas/v1/media-buy/create-media-buy-request.json", - "description": "Request parameters for creating a media buy" - }, - "response": { - "$ref": "/schemas/v1/media-buy/create-media-buy-response.json", - "description": "Response payload for create_media_buy task" - } - }, - "sync-creatives": { - "request": { - "$ref": "/schemas/v1/media-buy/sync-creatives-request.json", - "description": "Request parameters for syncing creative assets with upsert semantics" - }, - "response": { - "$ref": "/schemas/v1/media-buy/sync-creatives-response.json", - "description": "Response payload for sync_creatives task" - } - }, - "list-creatives": { - "request": { - "$ref": "/schemas/v1/media-buy/list-creatives-request.json", - "description": "Request parameters for querying creative library with filtering and pagination" - }, - "response": { - "$ref": "/schemas/v1/media-buy/list-creatives-response.json", - "description": "Response payload for list_creatives task" - } - }, - "update-media-buy": { - "request": { - "$ref": "/schemas/v1/media-buy/update-media-buy-request.json", - "description": "Request parameters for updating campaign and package settings" - }, - "response": { - "$ref": "/schemas/v1/media-buy/update-media-buy-response.json", - "description": "Response payload for update_media_buy task" - } - }, - "get-media-buy-delivery": { - "request": { - "$ref": "/schemas/v1/media-buy/get-media-buy-delivery-request.json", - "description": "Request parameters for retrieving comprehensive delivery metrics" - }, - "response": { - "$ref": "/schemas/v1/media-buy/get-media-buy-delivery-response.json", - "description": "Response payload for get_media_buy_delivery task" - } - }, - "list-authorized-properties": { - "request": { - "$ref": "/schemas/v1/media-buy/list-authorized-properties-request.json", - "description": "Request parameters for discovering all properties this agent is authorized to represent" - }, - "response": { - "$ref": "/schemas/v1/media-buy/list-authorized-properties-response.json", - "description": "Response payload for list_authorized_properties task" - } - }, - "provide-performance-feedback": { - "request": { - "$ref": "/schemas/v1/media-buy/provide-performance-feedback-request.json", - "description": "Request parameters for sharing performance outcomes with publishers" - }, - "response": { - "$ref": "/schemas/v1/media-buy/provide-performance-feedback-response.json", - "description": "Response payload for provide_performance_feedback task" - } - }, - "build-creative": { - "request": { - "$ref": "/schemas/v1/media-buy/build-creative-request.json", - "description": "Request parameters for AI-powered creative generation" - }, - "response": { - "$ref": "/schemas/v1/media-buy/build-creative-response.json", - "description": "Response payload for build_creative task" - } - }, - "manage-creative-library": { - "request": { - "$ref": "/schemas/v1/media-buy/manage-creative-library-request.json", - "description": "Request parameters for managing creative library assets" - }, - "response": { - "$ref": "/schemas/v1/media-buy/manage-creative-library-response.json", - "description": "Response payload for manage_creative_library task" - } - } - } - }, - "signals": { - "description": "Signals protocol task request/response schemas", - "tasks": { - "get-signals": { - "request": { - "$ref": "/schemas/v1/signals/get-signals-request.json", - "description": "Request parameters for discovering signals based on description" - }, - "response": { - "$ref": "/schemas/v1/signals/get-signals-response.json", - "description": "Response payload for get_signals task" - } - }, - "activate-signal": { - "request": { - "$ref": "/schemas/v1/signals/activate-signal-request.json", - "description": "Request parameters for activating a signal on a specific platform/account" - }, - "response": { - "$ref": "/schemas/v1/signals/activate-signal-response.json", - "description": "Response payload for activate_signal task" - } - } - } - }, - "adagents": { - "description": "Authorized sales agents file format specification", - "$ref": "/schemas/v1/adagents.json", - "file_location": "/.well-known/adagents.json", - "purpose": "Declares which sales agents are authorized to sell a publisher's advertising inventory" - }, - "standard-formats": { - "description": "Standard creative formats registry and schemas", - "$ref": "/schemas/v1/standard-formats/index.json", - "asset_types": { - "$ref": "/schemas/v1/standard-formats/asset-types/index.json", - "description": "Standardized asset type definitions" - } - } - }, - "usage": { - "validation": "Use these schemas to validate AdCP requests and responses", - "codeGeneration": "Generate client SDKs using these schemas", - "documentation": "Reference schemas for API documentation", - "testing": "Validate test fixtures and examples" - }, - "examples": [ - { - "language": "javascript", - "description": "JavaScript validation example", - "code": "const Ajv = require('ajv'); const ajv = new Ajv(); const schema = require('./schemas/v1/core/product.json'); const validate = ajv.compile(schema);" - }, - { - "language": "python", - "description": "Python validation example", - "code": "import jsonschema; schema = {...}; jsonschema.validate(data, schema)" - }, - { - "language": "java", - "description": "Java validation example", - "code": "// Use everit-org/json-schema or similar library" - } - ] -}