Module adcp.types.buyer

AdCP buyer types — curated partial surface.

Buy-side (DSP / agency) surface — product discovery, briefs / refine, pricing, media buys the buyer sends, performance feedback, brand rights.

A stable, narrow alternative to importing the whole :mod:adcp.types namespace. Every name here is also exported from :mod:adcp.types; this module simply groups the ones a buyer integration reaches for, and never exposes the internal generated layer.

This module is for curation and discoverability, not a separate performance tier: importing it is cheap, but the first access to any AdCP type (here or via :mod:adcp.types / :mod:adcp) realizes the full generated Pydantic graph — there is no per-domain graph. Use it for a smaller, focused import surface.

from adcp.types.buyer import GetProductsRequest

Classes

class AcquireRightsRequest (**data: Any)
Expand source code
class AcquireRightsRequest(AdcpVersionEnvelope):
    model_config = ConfigDict(
        extra='allow',
    )
    rights_id: Annotated[
        str, Field(description='Rights offering identifier from get_rights response')
    ]
    pricing_option_id: Annotated[
        str, Field(description='Selected pricing option from the rights offering')
    ]
    buyer: Annotated[brand_ref.BrandReference, Field(description="The buyer's brand identity")]
    account: Annotated[
        account_ref.AccountReference | None,
        Field(
            description='Account context for this acquisition. Used by the brand agent to resolve any governance agent previously bound for this brand+operator pair via sync_governance. When both an inline governance_context token (on the protocol envelope) and a bound governance agent are present, the inline token wins — brand agents MUST consult the agent identified by the inline token. When the request omits both `account` and an inline governance_context token, the brand agent treats the acquisition as ungoverned and the CPM-projection rule on `campaign.estimated_impressions` does not apply (sellers MAY refuse to transact ungoverned requests as a matter of commercial policy). Pass a natural key (brand, operator, optional sandbox) or a seller-assigned account_id from list_accounts.'
        ),
    ] = None
    campaign: Annotated[Campaign, Field(description='Campaign details for rights clearance')]
    revocation_webhook: Annotated[
        push_notification_config_1.PushNotificationConfig,
        Field(
            description='Webhook for rights revocation notifications. If the rights holder needs to revoke rights (talent scandal, contract violation, etc.), they POST a revocation-notification to this URL. The buyer is responsible for stopping creative delivery upon receipt.'
        ),
    ]
    push_notification_config: Annotated[
        push_notification_config_1.PushNotificationConfig | None,
        Field(
            description='Webhook for async status updates if the acquisition requires approval. The rights agent sends a webhook notification when the status transitions to acquired or rejected.'
        ),
    ] = None
    idempotency_key: Annotated[
        str,
        Field(
            description='Client-generated key for safe retries. Resubmitting with the same key returns the original response rather than creating a duplicate acquisition. MUST be unique per (seller, request) pair to prevent cross-seller correlation. Use a fresh UUID v4 for each request.',
            max_length=255,
            min_length=16,
            pattern='^[A-Za-z0-9_.:-]{16,255}$',
        ),
    ]
    context: context_1.ContextObject | None = None
    ext: ext_1.ExtensionObject | None = None

Base model for AdCP types with spec-compliant serialization.

Defaults to extra='ignore' so unknown fields from newer spec versions are silently dropped rather than causing validation errors. Generated types whose schemas set additionalProperties: true override this with extra='allow' in their own model_config.

Set ADCP_STRICT_VALIDATION=1 in the environment ("1", "true", "yes", "on" are accepted) to flip the default to extra='forbid'. Use this during spec upgrades to catch silently-dropped renamed fields in tests. See :func:_resolve_extra_policy.

Important

The env var is resolved once at module import time. Set it in your shell or CI environment before import adcp runs — mutating os.environ["ADCP_STRICT_VALIDATION"] after the first adcp import has no effect on already-imported model classes (they captured the policy at class-body evaluation).

Consumers who want per-model strict validation can override model_config on their subclass.

Create a new model by parsing and validating input data from keyword arguments.

Raises [ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.

self is explicitly positional-only to allow self as a field name.

Ancestors

  • adcp.types.generated_poc.core.version_envelope.AdcpVersionEnvelope
  • AdCPBaseModel
  • pydantic.main.BaseModel

Class variables

var account : adcp.types.generated_poc.core.account_ref.AccountReference | None
var buyer : adcp.types.generated_poc.core.brand_ref.BrandReference
var campaign : adcp.types.generated_poc.brand.acquire_rights_request.Campaign
var context : adcp.types.generated_poc.core.context.ContextObject | None
var ext : adcp.types.generated_poc.core.ext.ExtensionObject | None
var idempotency_key : str
var model_config
var pricing_option_id : str
var push_notification_config : adcp.types.generated_poc.core.push_notification_config.PushNotificationConfig | None
var revocation_webhook : adcp.types.generated_poc.core.push_notification_config.PushNotificationConfig
var rights_id : str

Inherited members

class BrandReference (**data: Any)
Expand source code
class BrandReference(AdCPBaseModel):
    model_config = ConfigDict(
        extra='forbid',
    )
    domain: Annotated[
        str,
        Field(
            description="Domain where /.well-known/brand.json is hosted, or the brand's operating domain",
            pattern='^[a-z0-9]([a-z0-9-]*[a-z0-9])?(\\.[a-z0-9]([a-z0-9-]*[a-z0-9])?)*$',
        ),
    ]
    brand_id: Annotated[
        brand_id_1.BrandId | None,
        Field(
            description='Brand identifier within the house portfolio. Optional for single-brand domains.'
        ),
    ] = None
    industries: Annotated[
        list[str] | None,
        Field(
            description="Inline override for the brand's industries. Useful when the caller cannot modify the brand's canonical brand.json but needs to declare industries for governance (e.g., Annex III vertical detection). brand.json remains the canonical source; when omitted here, governance agents SHOULD resolve from brand.json."
        ),
    ] = None
    data_subject_contestation: Annotated[
        DataSubjectContestation | None,
        Field(
            description="Inline override for the brand's contestation contact point. Useful when the operator does not control brand.json but needs to discharge Art 22(3) for this plan. brand.json is canonical; when omitted, governance agents resolve brand → house → missing."
        ),
    ] = None
    brand_kit_override: Annotated[
        BrandKitOverride | None,
        Field(
            description="Inline override for brand-kit fields normally resolved from `/.well-known/brand.json` on `domain` (logo, colors, voice, tagline). Use when brand.json is missing, stale, or inappropriate for this specific call — e.g., a campaign-scoped tagline, a co-branded creative, a freshly-rebranded color palette the brand.json hasn't shipped yet. Same inline-override pattern as `industries` and `data_subject_contestation` above: brand.json is canonical, the override is per-call. Adopters needing to override fields outside this subset (`voice_attributes`, `prohibited_terms`, etc.) MUST publish a different brand.json and reference it via a different `domain` — the inline override is intentionally narrow to a small high-traffic subset.\n\n**Merge semantics (normative).** The merge is **field-level**, not whole-object replacement. Each field within `brand_kit_override` (`logo`, `colors`, `voice`, `tagline`) is evaluated independently — when a field is present on the override the override value applies; when a field is absent the brand.json value applies (or is absent if brand.json doesn't carry one either). For composite fields (`colors.primary`, `colors.secondary`, `colors.accent`), the merge is one level deeper: each color slot is evaluated independently — a producer can override `colors.primary` while still inheriting `colors.secondary` from brand.json. SDKs MUST NOT treat a present `brand_kit_override.colors` as wiping the brand.json `colors` block entirely; only the per-slot fields present in the override take precedence. Without this rule, a partial-override semantics would diverge across SDKs and produce inconsistent rendering for the same payload."
        ),
    ] = None

Base model for AdCP types with spec-compliant serialization.

Defaults to extra='ignore' so unknown fields from newer spec versions are silently dropped rather than causing validation errors. Generated types whose schemas set additionalProperties: true override this with extra='allow' in their own model_config.

Set ADCP_STRICT_VALIDATION=1 in the environment ("1", "true", "yes", "on" are accepted) to flip the default to extra='forbid'. Use this during spec upgrades to catch silently-dropped renamed fields in tests. See :func:_resolve_extra_policy.

Important

The env var is resolved once at module import time. Set it in your shell or CI environment before import adcp runs — mutating os.environ["ADCP_STRICT_VALIDATION"] after the first adcp import has no effect on already-imported model classes (they captured the policy at class-body evaluation).

Consumers who want per-model strict validation can override model_config on their subclass.

Create a new model by parsing and validating input data from keyword arguments.

Raises [ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.

self is explicitly positional-only to allow self as a field name.

Ancestors

Class variables

var brand_id : adcp.types.generated_poc.core.brand_id.BrandId | None
var brand_kit_override : adcp.types.generated_poc.core.brand_ref.BrandKitOverride | None
var data_subject_contestation : adcp.types.generated_poc.core.brand_ref.DataSubjectContestation | None
var domain : str
var industries : list[str] | None
var model_config

Inherited members

class BrandSource (*args, **kwds)
Expand source code
class BrandSource(Enum):
    brand_json = "brand_json"
    community = "community"
    enriched = "enriched"

Create a collection of name/value pairs.

Example enumeration:

>>> class Color(Enum):
...     RED = 1
...     BLUE = 2
...     GREEN = 3

Access them by:

  • attribute access::
>>> Color.RED
<Color.RED: 1>
  • value lookup:
>>> Color(1)
<Color.RED: 1>
  • name lookup:
>>> Color['RED']
<Color.RED: 1>

Enumerations can be iterated over, and know how many members they have:

>>> len(Color)
3
>>> list(Color)
[<Color.RED: 1>, <Color.BLUE: 2>, <Color.GREEN: 3>]

Methods can be added to enumerations, and members can have their own attributes – see the documentation for details.

Ancestors

  • enum.Enum

Class variables

var brand_json
var community
var enriched
class CpaPricingOption (**data: Any)
Expand source code
class CpaPricingOption(AdCPBaseModel):
    model_config = ConfigDict(
        extra='allow',
    )
    pricing_option_id: Annotated[
        str, Field(description='Unique identifier for this pricing option within the product')
    ]
    pricing_model: Annotated[
        Literal['cpa'], Field(description='Cost per acquisition (conversion event)')
    ] = 'cpa'
    event_type: Annotated[
        event_type_1.EventType,
        Field(
            description='The conversion event type that triggers billing (e.g., purchase, lead, app_install)'
        ),
    ]
    custom_event_name: Annotated[
        str | None,
        Field(
            description="Name of the custom event when event_type is 'custom'. Required when event_type is 'custom', ignored otherwise."
        ),
    ] = None
    event_source_id: Annotated[
        str | None,
        Field(
            description='When present, only events from this specific event source count toward billing. Allows different CPA rates for different sources (e.g., online vs in-store purchases). Must match an event source configured via sync_event_sources.'
        ),
    ] = None
    currency: Annotated[
        str,
        Field(
            description='ISO 4217 currency code',
            examples=['USD', 'EUR', 'GBP', 'JPY'],
            pattern='^[A-Z]{3}$',
        ),
    ]
    fixed_price: Annotated[
        float, Field(description='Fixed price per acquisition in the specified currency', gt=0.0)
    ]
    min_spend_per_package: Annotated[
        float | None,
        Field(
            description='Minimum spend requirement per package using this pricing option, in the specified currency',
            ge=0.0,
        ),
    ] = None
    price_breakdown: Annotated[
        price_breakdown_1.PriceBreakdown | None,
        Field(
            description='Breakdown of how fixed_price was derived from the list (rate card) price. Only meaningful when fixed_price is present.'
        ),
    ] = None
    eligible_adjustments: Annotated[
        list[adjustment_kind.PriceAdjustmentKind] | None,
        Field(
            description='Adjustment kinds applicable to this pricing option. Tells buyer agents which adjustments are available before negotiation. When absent, no adjustments are pre-declared — the buyer should check price_breakdown if present.'
        ),
    ] = None

Base model for AdCP types with spec-compliant serialization.

Defaults to extra='ignore' so unknown fields from newer spec versions are silently dropped rather than causing validation errors. Generated types whose schemas set additionalProperties: true override this with extra='allow' in their own model_config.

Set ADCP_STRICT_VALIDATION=1 in the environment ("1", "true", "yes", "on" are accepted) to flip the default to extra='forbid'. Use this during spec upgrades to catch silently-dropped renamed fields in tests. See :func:_resolve_extra_policy.

Important

The env var is resolved once at module import time. Set it in your shell or CI environment before import adcp runs — mutating os.environ["ADCP_STRICT_VALIDATION"] after the first adcp import has no effect on already-imported model classes (they captured the policy at class-body evaluation).

Consumers who want per-model strict validation can override model_config on their subclass.

Create a new model by parsing and validating input data from keyword arguments.

Raises [ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.

self is explicitly positional-only to allow self as a field name.

Ancestors

Class variables

var currency : str
var custom_event_name : str | None
var eligible_adjustments : list[adcp.types.generated_poc.enums.adjustment_kind.PriceAdjustmentKind] | None
var event_source_id : str | None
var event_type : adcp.types.generated_poc.enums.event_type.EventType
var fixed_price : float
var min_spend_per_package : float | None
var model_config
var price_breakdown : adcp.types.generated_poc.pricing_options.price_breakdown.PriceBreakdown | None
var pricing_model : Literal['cpa']
var pricing_option_id : str

Inherited members

class CpcPricingOption (**data: Any)
Expand source code
class CpcPricingOption(AdCPBaseModel):
    model_config = ConfigDict(
        extra='allow',
    )
    pricing_option_id: Annotated[
        str, Field(description='Unique identifier for this pricing option within the product')
    ]
    pricing_model: Annotated[Literal['cpc'], Field(description='Cost per click')] = 'cpc'
    currency: Annotated[
        str,
        Field(
            description='ISO 4217 currency code',
            examples=['USD', 'EUR', 'GBP', 'JPY'],
            pattern='^[A-Z]{3}$',
        ),
    ]
    fixed_price: Annotated[
        float | None,
        Field(
            description='Fixed price per click. If present, this is fixed pricing. If absent, auction-based.',
            ge=0.0,
        ),
    ] = None
    floor_price: Annotated[
        float | None,
        Field(
            description='Minimum acceptable bid for auction pricing (mutually exclusive with fixed_price). Bids below this value will be rejected.',
            ge=0.0,
        ),
    ] = None
    max_bid: Annotated[
        bool | None,
        Field(
            description="When true, bid_price is interpreted as the buyer's maximum willingness to pay (ceiling) rather than an exact price. Sellers may optimize actual clearing prices between floor_price and bid_price based on delivery pacing. When false or absent, bid_price (if provided) is the exact bid/price to honor."
        ),
    ] = False
    price_guidance: Annotated[
        price_guidance_1.PriceGuidance | None,
        Field(description='Optional pricing guidance for auction-based bidding'),
    ] = None
    min_spend_per_package: Annotated[
        float | None,
        Field(
            description='Minimum spend requirement per package using this pricing option, in the specified currency',
            ge=0.0,
        ),
    ] = None
    price_breakdown: Annotated[
        price_breakdown_1.PriceBreakdown | None,
        Field(
            description='Breakdown of how fixed_price was derived from the list (rate card) price. Only meaningful when fixed_price is present.'
        ),
    ] = None
    eligible_adjustments: Annotated[
        list[adjustment_kind.PriceAdjustmentKind] | None,
        Field(
            description='Adjustment kinds applicable to this pricing option. Tells buyer agents which adjustments are available before negotiation. When absent, no adjustments are pre-declared — the buyer should check price_breakdown if present.'
        ),
    ] = None

Base model for AdCP types with spec-compliant serialization.

Defaults to extra='ignore' so unknown fields from newer spec versions are silently dropped rather than causing validation errors. Generated types whose schemas set additionalProperties: true override this with extra='allow' in their own model_config.

Set ADCP_STRICT_VALIDATION=1 in the environment ("1", "true", "yes", "on" are accepted) to flip the default to extra='forbid'. Use this during spec upgrades to catch silently-dropped renamed fields in tests. See :func:_resolve_extra_policy.

Important

The env var is resolved once at module import time. Set it in your shell or CI environment before import adcp runs — mutating os.environ["ADCP_STRICT_VALIDATION"] after the first adcp import has no effect on already-imported model classes (they captured the policy at class-body evaluation).

Consumers who want per-model strict validation can override model_config on their subclass.

Create a new model by parsing and validating input data from keyword arguments.

Raises [ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.

self is explicitly positional-only to allow self as a field name.

Ancestors

Class variables

var currency : str
var eligible_adjustments : list[adcp.types.generated_poc.enums.adjustment_kind.PriceAdjustmentKind] | None
var fixed_price : float | None
var floor_price : float | None
var max_bid : bool | None
var min_spend_per_package : float | None
var model_config
var price_breakdown : adcp.types.generated_poc.pricing_options.price_breakdown.PriceBreakdown | None
var price_guidance : adcp.types.generated_poc.pricing_options.price_guidance.PriceGuidance | None
var pricing_model : Literal['cpc']
var pricing_option_id : str

Inherited members

class CpmPricingOption (**data: Any)
Expand source code
class CpmPricingOption(AdCPBaseModel):
    model_config = ConfigDict(
        extra='allow',
    )
    pricing_option_id: Annotated[
        str, Field(description='Unique identifier for this pricing option within the product')
    ]
    pricing_model: Annotated[Literal['cpm'], Field(description='Cost per 1,000 impressions')] = 'cpm'
    currency: Annotated[
        str,
        Field(
            description='ISO 4217 currency code',
            examples=['USD', 'EUR', 'GBP', 'JPY'],
            pattern='^[A-Z]{3}$',
        ),
    ]
    fixed_price: Annotated[
        float | None,
        Field(
            description='Fixed price per unit. If present, this is fixed pricing. If absent, auction-based.',
            ge=0.0,
        ),
    ] = None
    floor_price: Annotated[
        float | None,
        Field(
            description='Minimum acceptable bid for auction pricing (mutually exclusive with fixed_price). Bids below this value will be rejected.',
            ge=0.0,
        ),
    ] = None
    max_bid: Annotated[
        bool | None,
        Field(
            description="When true, bid_price is interpreted as the buyer's maximum willingness to pay (ceiling) rather than an exact price. Sellers may optimize actual clearing prices between floor_price and bid_price based on delivery pacing. When false or absent, bid_price (if provided) is the exact bid/price to honor."
        ),
    ] = False
    price_guidance: Annotated[
        price_guidance_1.PriceGuidance | None,
        Field(description='Optional pricing guidance for auction-based bidding'),
    ] = None
    min_spend_per_package: Annotated[
        float | None,
        Field(
            description='Minimum spend requirement per package using this pricing option, in the specified currency',
            ge=0.0,
        ),
    ] = None
    price_breakdown: Annotated[
        price_breakdown_1.PriceBreakdown | None,
        Field(
            description='Breakdown of how fixed_price was derived from the list (rate card) price. Only meaningful when fixed_price is present.'
        ),
    ] = None
    eligible_adjustments: Annotated[
        list[adjustment_kind.PriceAdjustmentKind] | None,
        Field(
            description='Adjustment kinds applicable to this pricing option. Tells buyer agents which adjustments are available before negotiation. When absent, no adjustments are pre-declared — the buyer should check price_breakdown if present.'
        ),
    ] = None

Base model for AdCP types with spec-compliant serialization.

Defaults to extra='ignore' so unknown fields from newer spec versions are silently dropped rather than causing validation errors. Generated types whose schemas set additionalProperties: true override this with extra='allow' in their own model_config.

Set ADCP_STRICT_VALIDATION=1 in the environment ("1", "true", "yes", "on" are accepted) to flip the default to extra='forbid'. Use this during spec upgrades to catch silently-dropped renamed fields in tests. See :func:_resolve_extra_policy.

Important

The env var is resolved once at module import time. Set it in your shell or CI environment before import adcp runs — mutating os.environ["ADCP_STRICT_VALIDATION"] after the first adcp import has no effect on already-imported model classes (they captured the policy at class-body evaluation).

Consumers who want per-model strict validation can override model_config on their subclass.

Create a new model by parsing and validating input data from keyword arguments.

Raises [ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.

self is explicitly positional-only to allow self as a field name.

Ancestors

Class variables

var currency : str
var eligible_adjustments : list[adcp.types.generated_poc.enums.adjustment_kind.PriceAdjustmentKind] | None
var fixed_price : float | None
var floor_price : float | None
var max_bid : bool | None
var min_spend_per_package : float | None
var model_config
var price_breakdown : adcp.types.generated_poc.pricing_options.price_breakdown.PriceBreakdown | None
var price_guidance : adcp.types.generated_poc.pricing_options.price_guidance.PriceGuidance | None
var pricing_model : Literal['cpm']
var pricing_option_id : str

Inherited members

class CreateMediaBuyRequest (**data: Any)
Expand source code
class CreateMediaBuyRequest(AdcpVersionEnvelope):
    model_config = ConfigDict(
        extra='allow',
    )
    idempotency_key: Annotated[
        str,
        Field(
            description='Client-generated unique key for this request. If a request with the same idempotency_key and account has already been processed, the seller returns the existing media buy rather than creating a duplicate. MUST be unique per (seller, request) pair to prevent cross-seller correlation. Use a fresh UUID v4 for each request.',
            max_length=255,
            min_length=16,
            pattern='^[A-Za-z0-9_.:-]{16,255}$',
        ),
    ]
    plan_id: Annotated[
        str | None,
        Field(
            description='Campaign governance plan identifier. Required when the account has governance_agents. The seller includes this in the committed check_governance request so the governance agent can validate against the correct plan.'
        ),
    ] = None
    account: Annotated[
        account_ref.AccountReference,
        Field(
            description='Account to bill for this media buy. Pass a natural key (brand, operator, optional sandbox) or a seller-assigned account_id from list_accounts.'
        ),
    ]
    proposal_id: Annotated[
        str | None,
        Field(
            description="ID of a committed proposal from get_products to execute. When provided with total_budget, the publisher converts the proposal's allocation percentages into packages automatically. Alternative to providing packages array. If the referenced proposal has proposal_status: 'draft', the seller MUST reject with PROPOSAL_NOT_COMMITTED; the buyer finalizes first via get_products refine action 'finalize'."
        ),
    ] = None
    total_budget: Annotated[
        TotalBudget | None,
        Field(
            description="Total budget for the media buy when executing a proposal. The publisher applies the proposal's allocation percentages to this amount to derive package budgets."
        ),
    ] = None
    packages: Annotated[
        Sequence[package_request.PackageRequest] | None,
        Field(
            description="Array of package configurations. Required when not using proposal_id. When executing a proposal, this can be omitted and packages will be derived from the proposal's allocations.",
            min_length=1,
        ),
    ] = None
    brand: Annotated[
        brand_ref.BrandReference,
        Field(
            description='Brand reference for this media buy. Resolved to full brand identity at execution time from brand.json or the registry.'
        ),
    ]
    advertiser_industry: Annotated[
        advertiser_industry_1.AdvertiserIndustry | None,
        Field(
            description="Industry classification for this specific campaign. A brand may operate across multiple industries (brand.json industries field), but each media buy targets one. For example, a consumer health company running a wellness campaign sends 'healthcare.wellness', not 'cpg'. Sellers map this to platform-native codes (e.g., Spotify ADV categories, LinkedIn industry IDs). When omitted, sellers may infer from the brand manifest's industries field."
        ),
    ] = None
    invoice_recipient: Annotated[
        business_entity.BusinessEntity | None,
        Field(
            description="Override the account's default billing entity for this specific buy. When provided, the seller invoices this entity instead. The seller MUST validate the invoice recipient is authorized for this account. When governance_agents are configured, the seller MUST include invoice_recipient in the check_governance request."
        ),
    ] = None
    io_acceptance: Annotated[
        IoAcceptance | None,
        Field(
            description="Acceptance of an insertion order from a committed proposal. Required when the proposal's insertion_order has requires_signature: true. References the io_id from the proposal's insertion_order."
        ),
    ] = None
    po_number: Annotated[str | None, Field(description='Purchase order number for tracking')] = None
    agency_estimate_number: Annotated[
        str | None,
        Field(
            description="Agency estimate or authorization number. Primary financial reference for broadcast buys — links the order to the agency's media plan and billing system. Travels with the order and creative traffic identifiers through the transaction lifecycle.",
            max_length=100,
        ),
    ] = None
    start_time: start_timing.StartTiming
    end_time: Annotated[
        AwareDatetime, Field(description='Campaign end date/time in ISO 8601 format')
    ]
    paused: Annotated[
        bool | None,
        Field(
            description="Create the media buy in a paused delivery state. When true, and the buy would otherwise be active because creatives are assigned and the flight has started, the seller returns media_buy_status 'paused'. Setup blockers still take precedence: a buy with no creatives remains 'pending_creatives', and a future-dated buy remains 'pending_start' until its flight can start. Defaults to false."
        ),
    ] = False
    push_notification_config: Annotated[
        push_notification_config_1.PushNotificationConfig | None,
        Field(
            description='Optional webhook configuration for async task status notifications. Publisher will send webhooks when status changes (working, input-required, completed, failed, canceled). Buyers SHOULD supply `push_notification_config_1.operation_id` as the canonical correlation value; publishers echo that field back verbatim in webhook payloads and MUST NOT parse the URL to derive it.'
        ),
    ] = None
    reporting_webhook: Annotated[
        reporting_webhook_1.ReportingWebhook | None,
        Field(description='Optional webhook configuration for automated reporting delivery'),
    ] = None
    artifact_webhook: Annotated[
        ArtifactWebhook | None,
        Field(
            description='Optional webhook configuration for content artifact delivery. Used by governance agents to validate content adjacency. Seller pushes artifacts to this endpoint; orchestrator forwards to governance agent for validation.'
        ),
    ] = None
    context: context_1.ContextObject | None = None
    ext: ext_1.ExtensionObject | None = None

Base model for AdCP types with spec-compliant serialization.

Defaults to extra='ignore' so unknown fields from newer spec versions are silently dropped rather than causing validation errors. Generated types whose schemas set additionalProperties: true override this with extra='allow' in their own model_config.

Set ADCP_STRICT_VALIDATION=1 in the environment ("1", "true", "yes", "on" are accepted) to flip the default to extra='forbid'. Use this during spec upgrades to catch silently-dropped renamed fields in tests. See :func:_resolve_extra_policy.

Important

The env var is resolved once at module import time. Set it in your shell or CI environment before import adcp runs — mutating os.environ["ADCP_STRICT_VALIDATION"] after the first adcp import has no effect on already-imported model classes (they captured the policy at class-body evaluation).

Consumers who want per-model strict validation can override model_config on their subclass.

Create a new model by parsing and validating input data from keyword arguments.

Raises [ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.

self is explicitly positional-only to allow self as a field name.

Ancestors

  • adcp.types.generated_poc.core.version_envelope.AdcpVersionEnvelope
  • AdCPBaseModel
  • pydantic.main.BaseModel

Class variables

var account : adcp.types.generated_poc.core.account_ref.AccountReference
var advertiser_industry : adcp.types.generated_poc.enums.advertiser_industry.AdvertiserIndustry | None
var agency_estimate_number : str | None
var artifact_webhook : adcp.types.generated_poc.media_buy.create_media_buy_request.ArtifactWebhook | None
var brand : adcp.types.generated_poc.core.brand_ref.BrandReference
var context : adcp.types.generated_poc.core.context.ContextObject | None
var end_time : pydantic.types.AwareDatetime
var ext : adcp.types.generated_poc.core.ext.ExtensionObject | None
var idempotency_key : str
var invoice_recipient : adcp.types.generated_poc.core.business_entity.BusinessEntity | None
var io_acceptance : adcp.types.generated_poc.media_buy.create_media_buy_request.IoAcceptance | None
var model_config
var packages : collections.abc.Sequence[adcp.types.generated_poc.media_buy.package_request.PackageRequest] | None
var paused : bool | None
var plan_id : str | None
var po_number : str | None
var proposal_id : str | None
var push_notification_config : adcp.types.generated_poc.core.push_notification_config.PushNotificationConfig | None
var reporting_webhook : adcp.types.generated_poc.core.reporting_webhook.ReportingWebhook | None
var start_time : adcp.types.generated_poc.core.start_timing.StartTiming
var total_budget : adcp.types.generated_poc.media_buy.create_media_buy_request.TotalBudget | None

Inherited members

class FeedbackSource (*args, **kwds)
Expand source code
class FeedbackSource(StrEnum):
    buyer_attribution = 'buyer_attribution'
    third_party_measurement = 'third_party_measurement'
    platform_analytics = 'platform_analytics'
    verification_partner = 'verification_partner'

Enum where members are also (and must be) strings

Ancestors

  • enum.StrEnum
  • builtins.str
  • enum.ReprEnum
  • enum.Enum

Class variables

var buyer_attribution
var platform_analytics
var third_party_measurement
var verification_partner
class FlatRatePricingOption (**data: Any)
Expand source code
class FlatRatePricingOption(AdCPBaseModel):
    model_config = ConfigDict(
        extra='allow',
    )
    pricing_option_id: Annotated[
        str, Field(description='Unique identifier for this pricing option within the product')
    ]
    pricing_model: Annotated[
        Literal['flat_rate'], Field(description='Fixed cost regardless of delivery volume')
    ] = 'flat_rate'
    currency: Annotated[
        str,
        Field(
            description='ISO 4217 currency code',
            examples=['USD', 'EUR', 'GBP', 'JPY'],
            pattern='^[A-Z]{3}$',
        ),
    ]
    fixed_price: Annotated[
        float | None,
        Field(
            description='Flat rate cost. If present, this is fixed pricing. If absent, auction-based.',
            ge=0.0,
        ),
    ] = None
    floor_price: Annotated[
        float | None,
        Field(
            description='Minimum acceptable bid for auction pricing (mutually exclusive with fixed_price). Bids below this value will be rejected.',
            ge=0.0,
        ),
    ] = None
    price_guidance: Annotated[
        price_guidance_1.PriceGuidance | None,
        Field(description='Optional pricing guidance for auction-based bidding'),
    ] = None
    parameters: Annotated[
        Parameters | None,
        Field(
            description='DOOH inventory allocation parameters. Sponsorship and takeover flat_rate options omit this field entirely — only include for digital out-of-home inventory.',
            title='DoohParameters',
        ),
    ] = None
    min_spend_per_package: Annotated[
        float | None,
        Field(
            description='Minimum spend requirement per package using this pricing option, in the specified currency',
            ge=0.0,
        ),
    ] = None
    price_breakdown: Annotated[
        price_breakdown_1.PriceBreakdown | None,
        Field(
            description='Breakdown of how fixed_price was derived from the list (rate card) price. Only meaningful when fixed_price is present.'
        ),
    ] = None
    eligible_adjustments: Annotated[
        list[adjustment_kind.PriceAdjustmentKind] | None,
        Field(
            description='Adjustment kinds applicable to this pricing option. Tells buyer agents which adjustments are available before negotiation. When absent, no adjustments are pre-declared — the buyer should check price_breakdown if present.'
        ),
    ] = None

Base model for AdCP types with spec-compliant serialization.

Defaults to extra='ignore' so unknown fields from newer spec versions are silently dropped rather than causing validation errors. Generated types whose schemas set additionalProperties: true override this with extra='allow' in their own model_config.

Set ADCP_STRICT_VALIDATION=1 in the environment ("1", "true", "yes", "on" are accepted) to flip the default to extra='forbid'. Use this during spec upgrades to catch silently-dropped renamed fields in tests. See :func:_resolve_extra_policy.

Important

The env var is resolved once at module import time. Set it in your shell or CI environment before import adcp runs — mutating os.environ["ADCP_STRICT_VALIDATION"] after the first adcp import has no effect on already-imported model classes (they captured the policy at class-body evaluation).

Consumers who want per-model strict validation can override model_config on their subclass.

Create a new model by parsing and validating input data from keyword arguments.

Raises [ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.

self is explicitly positional-only to allow self as a field name.

Ancestors

Class variables

var currency : str
var eligible_adjustments : list[adcp.types.generated_poc.enums.adjustment_kind.PriceAdjustmentKind] | None
var fixed_price : float | None
var floor_price : float | None
var min_spend_per_package : float | None
var model_config
var parameters : adcp.types.generated_poc.pricing_options.flat_rate_option.Parameters | None
var price_breakdown : adcp.types.generated_poc.pricing_options.price_breakdown.PriceBreakdown | None
var price_guidance : adcp.types.generated_poc.pricing_options.price_guidance.PriceGuidance | None
var pricing_model : Literal['flat_rate']
var pricing_option_id : str

Inherited members

class GetBrandIdentityRequest (**data: Any)
Expand source code
class GetBrandIdentityRequest(AdcpVersionEnvelope):
    model_config = ConfigDict(
        extra='allow',
    )
    brand_id: Annotated[str, Field(description='Brand identifier from brand.json brands array')]
    fields: Annotated[
        list[FieldModel] | None,
        Field(
            description='Optional identity sections to include in the response. When omitted, all sections the caller is authorized to see are returned. Core fields (brand_id, house, names) are always returned and do not need to be requested.',
            min_length=1,
        ),
    ] = None
    use_case: Annotated[
        str | None,
        Field(
            description="Intended use case, so the agent can tailor the response. A 'voice_synthesis' use case returns voice configs; a 'likeness' use case returns high-res photos and appearance guidelines."
        ),
    ] = None
    context: context_1.ContextObject | None = None
    ext: ext_1.ExtensionObject | None = None

Base model for AdCP types with spec-compliant serialization.

Defaults to extra='ignore' so unknown fields from newer spec versions are silently dropped rather than causing validation errors. Generated types whose schemas set additionalProperties: true override this with extra='allow' in their own model_config.

Set ADCP_STRICT_VALIDATION=1 in the environment ("1", "true", "yes", "on" are accepted) to flip the default to extra='forbid'. Use this during spec upgrades to catch silently-dropped renamed fields in tests. See :func:_resolve_extra_policy.

Important

The env var is resolved once at module import time. Set it in your shell or CI environment before import adcp runs — mutating os.environ["ADCP_STRICT_VALIDATION"] after the first adcp import has no effect on already-imported model classes (they captured the policy at class-body evaluation).

Consumers who want per-model strict validation can override model_config on their subclass.

Create a new model by parsing and validating input data from keyword arguments.

Raises [ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.

self is explicitly positional-only to allow self as a field name.

Ancestors

  • adcp.types.generated_poc.core.version_envelope.AdcpVersionEnvelope
  • AdCPBaseModel
  • pydantic.main.BaseModel

Class variables

var brand_id : str
var context : adcp.types.generated_poc.core.context.ContextObject | None
var ext : adcp.types.generated_poc.core.ext.ExtensionObject | None
var fields : list[adcp.types.generated_poc.brand.get_brand_identity_request.FieldModel] | None
var model_config
var use_case : str | None

Inherited members

class GetProductsInputRequiredResponse (**data: Any)
Expand source code
class GetProductsInputRequired(AdCPBaseModel):
    model_config = ConfigDict(
        extra='allow',
    )
    reason: Annotated[
        Reason | None, Field(description='Reason code indicating why input is needed')
    ] = None
    partial_results: Annotated[
        list[product.Product] | None,
        Field(description='Partial product results that may help inform the clarification'),
    ] = None
    suggestions: Annotated[
        list[str] | None, Field(description='Suggested values or options for the required input')
    ] = None
    context: context_1.ContextObject | None = None
    ext: ext_1.ExtensionObject | None = None

Base model for AdCP types with spec-compliant serialization.

Defaults to extra='ignore' so unknown fields from newer spec versions are silently dropped rather than causing validation errors. Generated types whose schemas set additionalProperties: true override this with extra='allow' in their own model_config.

Set ADCP_STRICT_VALIDATION=1 in the environment ("1", "true", "yes", "on" are accepted) to flip the default to extra='forbid'. Use this during spec upgrades to catch silently-dropped renamed fields in tests. See :func:_resolve_extra_policy.

Important

The env var is resolved once at module import time. Set it in your shell or CI environment before import adcp runs — mutating os.environ["ADCP_STRICT_VALIDATION"] after the first adcp import has no effect on already-imported model classes (they captured the policy at class-body evaluation).

Consumers who want per-model strict validation can override model_config on their subclass.

Create a new model by parsing and validating input data from keyword arguments.

Raises [ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.

self is explicitly positional-only to allow self as a field name.

Ancestors

Class variables

var context : adcp.types.generated_poc.core.context.ContextObject | None
var ext : adcp.types.generated_poc.core.ext.ExtensionObject | None
var model_config
var partial_results : list[adcp.types.generated_poc.core.product.Product] | None
var reason : adcp.types.generated_poc.core.async_response_refs.media_buy.get_products_async_response_input_required.Reason | None
var suggestions : list[str] | None

Inherited members

class GetProductsRequest (**data: Any)
Expand source code
class GetProductsRequest(AdcpVersionEnvelope):
    model_config = ConfigDict(
        extra='allow',
    )
    buying_mode: Annotated[
        BuyingMode,
        Field(
            description="Declares buyer intent for this request. 'brief': publisher curates product recommendations from the provided brief. 'wholesale': buyer requests raw product inventory to apply their own audiences — brief must not be provided, and proposals are omitted. 'refine': iterate on products and proposals from a previous get_products response using the refine array of change requests. v3 clients MUST include buying_mode. Sellers receiving requests from pre-v3 clients without buying_mode SHOULD default to 'brief'. Timing semantics: 'wholesale' is a wholesale product feed read — sellers SHOULD return a synchronous response and MUST NOT route a 'wholesale' request through the async/Submitted arm; partial completion is signalled via the response's incomplete[] field (with optional estimated_wait), not via a task-handoff envelope. 'brief' and 'refine' MAY complete synchronously, or MAY return a Submitted envelope (see get-products-async-response-submitted.json) when curation requires upstream-system queries or HITL review the seller cannot complete inside time_budget. Buyers needing predictable fast wholesale product feed access MUST use 'wholesale'; buyers open to slower curation use 'brief' or 'refine'."
        ),
    ]
    brief: Annotated[
        str | None,
        Field(
            description="Natural language description of campaign requirements. Required when buying_mode is 'brief'. Must not be provided when buying_mode is 'wholesale' or 'refine'."
        ),
    ] = None
    refine: Annotated[
        list[Refine] | None,
        Field(
            description="Array of change requests for iterating on products and proposals from a previous get_products response. Each entry declares a scope (request, product, or proposal) and what the buyer is asking for. Only valid when buying_mode is 'refine'. The seller responds to each entry via refinement_applied in the response, matched by position.\n\nFinalize-exclusivity rule: if any entry has `action: 'finalize'`, ALL entries in the array MUST be proposal-scoped with `action: 'finalize'` — mixing finalize entries with `include`/`omit` entries or with request- / product-scoped entries MUST be rejected by the seller with `INVALID_REQUEST`. Finalize is a commit, not a refinement; the buyer expressing intent to commit means refinements have already converged. Buyers needing to refine AND commit in close succession sequence the calls: first a refine call (no finalize), then a finalize call against the resulting `proposal_id`(s).\n\nMulti-finalize semantics: multiple finalize entries against different `proposal_id` values in a single call are allowed and MUST be **atomic at the observation point** — sellers MUST NOT return a success response unless every named proposal has both completed and been persisted as committed. Pre-commit validation runs before any side-effects (inventory pull, terms lock, governance attestation); if any proposal fails validation, the seller MUST reject the entire call without committing any of the named proposals. There is no rollback operation in the spec — an `unfinalize` would itself be a new mutation surface; the atomicity guarantee runs entirely on the seller's pre-commit validation gate, not on post-commit reversal. Sellers that cannot guarantee atomic pre-commit validation MUST reject multi-finalize arrays with `MULTI_FINALIZE_UNSUPPORTED` (preferred — distinguishes seller-side capability gap from a malformed request) or `INVALID_REQUEST` (acceptable fallback for sellers on a pre-3.1 error catalog). If a mid-commit failure occurs *after* validation passed but before all proposals persist (e.g., a downstream ad server fails between commits one and two), the seller MUST return `INTERNAL_ERROR` with `refinement_applied[]` carrying per-position outcomes — the spec does NOT define a recovery path for this case, and buyers SHOULD treat the resulting state as undefined and re-read via `get_media_buys` / equivalent before retrying. Buyers MUST NOT assume multi-finalize support without a successful first attempt — there is no capability flag for this; the failure response is the discovery surface. Buyers whose intent specifically requires atomic commit (e.g., budget-shared proposals where one finalizing without the other is incoherent) MUST be prepared to abandon the intent if the seller returns `MULTI_FINALIZE_UNSUPPORTED` — there is no recovery for that loss of buyer intent beyond sequencing single-finalize calls and accepting the looser commit guarantee.",
            min_length=1,
        ),
    ] = None
    brand: Annotated[
        brand_ref.BrandReference | None,
        Field(
            description='Brand reference for product discovery context. Resolved to full brand identity at execution time.'
        ),
    ] = None
    catalog: Annotated[
        catalog_1.Catalog | None,
        Field(
            description='Catalog of items the buyer wants to promote. The seller matches catalog items against its inventory and returns products where matches exist. Supports all catalog types: a job catalog finds job ad products, a product catalog finds sponsored product slots. Reference a synced catalog by catalog_id, or provide inline items.'
        ),
    ] = None
    account: Annotated[
        account_ref.AccountReference | None,
        Field(
            description="Account for product lookup. Returns products with pricing specific to this account's rate card."
        ),
    ] = None
    preferred_delivery_types: Annotated[
        list[delivery_type_1.DeliveryType] | None,
        Field(
            description='Delivery types the buyer prefers, in priority order. Unlike filters.delivery_type which excludes non-matching products, this signals preference for curation — the publisher may still include other delivery types when they match the brief well.',
            min_length=1,
        ),
    ] = None
    filters: product_filters.ProductFilters | None = None
    property_list: Annotated[
        property_list_ref.PropertyListReference | None,
        Field(
            description='[AdCP 3.0] Reference to an externally managed property list. When provided, the sales agent should filter products to only those available on properties in the list.'
        ),
    ] = None
    fields: Annotated[
        list[Field1] | None,
        Field(
            description='Specific product fields to include in the response. When omitted, all fields are returned. Use for lightweight discovery calls where only a subset of product data is needed (e.g., just IDs and pricing for comparison). Required fields (product_id, name) are always included regardless of selection.',
            min_length=1,
        ),
    ] = None
    time_budget: Annotated[
        duration.Duration | None,
        Field(
            description='Maximum time the buyer will commit to this request. The seller returns the best results achievable within this budget and does not start processes (human approvals, expensive external queries) that cannot complete in time. When omitted, the seller decides timing.'
        ),
    ] = None
    push_notification_config: Annotated[
        push_notification_config_1.PushNotificationConfig | None,
        Field(
            description='Optional webhook configuration for async terminal completion/failure notifications on curated discovery. Meaningful only for `buying_mode: "brief"` and `buying_mode: "refine"` requests that enter the async lifecycle. Submitted envelopes with `task_id` remain pollable through `get_task_status` (legacy `tasks/get`) whether or not this field is present. If a brief/refine request includes this field and the seller returns a Submitted envelope, the seller MUST deliver at least the terminal completion/failure notification to the configured URL; intermediate progress notifications are MAY. If the seller cannot honor the webhook channel, it MUST reject the request with a structured error instead of silently accepting. This field does not change wholesale timing semantics: sellers MUST NOT route `buying_mode: "wholesale"` requests through the async/Submitted arm or emit async delivery solely because `push_notification_config` is present; partial wholesale completion is reported via `incomplete[]`.'
        ),
    ] = None
    pagination: Annotated[
        pagination_request.PaginationRequest | None,
        Field(
            description="Cursor-based pagination controls for get_products. Valid in all buying modes. In brief mode, pagination bounds the seller's returned products[] for the curated answer to the brief and is not an exhaustive catalog-enumeration contract. In refine mode, pagination bounds the refined products[] result implied by refine[] and filters; proposals may accompany a page as plan metadata but are not independently counted by this pagination envelope. In wholesale mode, pagination walks the wholesale product feed and may be combined with wholesale feed versioning."
        ),
    ] = None
    if_wholesale_feed_version: Annotated[
        str | None,
        Field(
            description="Opaque wholesale_feed_version token returned by a prior wholesale-mode get_products response from this agent. Only valid when buying_mode is wholesale. When provided, the seller compares against its current wholesale product feed version for the buyer's cache_scope and MAY return an unchanged: true response (with products omitted) if nothing has changed. The token is scope-keyed: buyers cache `(cache_scope, wholesale_feed_version)` pairs. Scoping dimensions: (agent, buying_mode, filters, property_list, catalog) for cache_scope: 'public'; that tuple plus account_id for cache_scope: 'account'. pagination.cursor is NOT part of the scoping tuple. Backward-compatible: pre-v3.1 agents that ignore this field simply return the full payload, same as the unchanged-server path. See specs/wholesale-feed-webhooks.md for the full sync pattern."
        ),
    ] = None
    if_pricing_version: Annotated[
        str | None,
        Field(
            description="Opaque pricing_version token from a prior get_products response. MUST only be sent together with if_wholesale_feed_version — pricing version has no structural baseline to compare against on its own. Evaluation order: (1) if_wholesale_feed_version mismatch → seller returns the full payload (pricing is implicitly stale); (2) if_wholesale_feed_version matches but if_pricing_version mismatches → seller returns the full payload so the buyer sees updated pricing_options; (3) both match → seller MAY return unchanged: true. Agents that don't track pricing separately ignore if_pricing_version and fall back to if_wholesale_feed_version semantics. Useful for storefronts that re-price compositions far more often than they re-render product mirrors."
        ),
    ] = None
    context: context_1.ContextObject | None = None
    required_policies: Annotated[
        list[str] | None,
        Field(
            description='Registry policy IDs that the buyer requires to be enforced for products in this response. Sellers filter products to only those that comply with or already enforce the requested policies.'
        ),
    ] = None
    ext: ext_1.ExtensionObject | None = None

Base model for AdCP types with spec-compliant serialization.

Defaults to extra='ignore' so unknown fields from newer spec versions are silently dropped rather than causing validation errors. Generated types whose schemas set additionalProperties: true override this with extra='allow' in their own model_config.

Set ADCP_STRICT_VALIDATION=1 in the environment ("1", "true", "yes", "on" are accepted) to flip the default to extra='forbid'. Use this during spec upgrades to catch silently-dropped renamed fields in tests. See :func:_resolve_extra_policy.

Important

The env var is resolved once at module import time. Set it in your shell or CI environment before import adcp runs — mutating os.environ["ADCP_STRICT_VALIDATION"] after the first adcp import has no effect on already-imported model classes (they captured the policy at class-body evaluation).

Consumers who want per-model strict validation can override model_config on their subclass.

Create a new model by parsing and validating input data from keyword arguments.

Raises [ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.

self is explicitly positional-only to allow self as a field name.

Ancestors

  • adcp.types.generated_poc.core.version_envelope.AdcpVersionEnvelope
  • AdCPBaseModel
  • pydantic.main.BaseModel

Class variables

var account : adcp.types.generated_poc.core.account_ref.AccountReference | None
var brand : adcp.types.generated_poc.core.brand_ref.BrandReference | None
var brief : str | None
var buying_mode : adcp.types.generated_poc.media_buy.get_products_request.BuyingMode | None
var catalog : adcp.types.generated_poc.core.catalog.Catalog | None
var context : adcp.types.generated_poc.core.context.ContextObject | None
var ext : adcp.types.generated_poc.core.ext.ExtensionObject | None
var fields : list[adcp.types.generated_poc.media_buy.get_products_request.Field1] | None
var filters : adcp.types.generated_poc.core.product_filters.ProductFilters | None
var if_pricing_version : str | None
var if_wholesale_feed_version : str | None
var model_config
var pagination : adcp.types.generated_poc.core.pagination_request.PaginationRequest | None
var preferred_delivery_types : list[adcp.types.generated_poc.enums.delivery_type.DeliveryType] | None
var property_list : adcp.types.generated_poc.core.property_list_ref.PropertyListReference | None
var push_notification_config : adcp.types.generated_poc.core.push_notification_config.PushNotificationConfig | None
var refine : list[adcp.types.generated_poc.media_buy.get_products_request.Refine] | None
var required_policies : list[str] | None
var time_budget : adcp.types.generated_poc.core.duration.Duration | None
class GetProductsBriefRequest (**data: Any)
Expand source code
class GetProductsRequest(AdcpVersionEnvelope):
    model_config = ConfigDict(
        extra='allow',
    )
    buying_mode: Annotated[
        BuyingMode,
        Field(
            description="Declares buyer intent for this request. 'brief': publisher curates product recommendations from the provided brief. 'wholesale': buyer requests raw product inventory to apply their own audiences — brief must not be provided, and proposals are omitted. 'refine': iterate on products and proposals from a previous get_products response using the refine array of change requests. v3 clients MUST include buying_mode. Sellers receiving requests from pre-v3 clients without buying_mode SHOULD default to 'brief'. Timing semantics: 'wholesale' is a wholesale product feed read — sellers SHOULD return a synchronous response and MUST NOT route a 'wholesale' request through the async/Submitted arm; partial completion is signalled via the response's incomplete[] field (with optional estimated_wait), not via a task-handoff envelope. 'brief' and 'refine' MAY complete synchronously, or MAY return a Submitted envelope (see get-products-async-response-submitted.json) when curation requires upstream-system queries or HITL review the seller cannot complete inside time_budget. Buyers needing predictable fast wholesale product feed access MUST use 'wholesale'; buyers open to slower curation use 'brief' or 'refine'."
        ),
    ]
    brief: Annotated[
        str | None,
        Field(
            description="Natural language description of campaign requirements. Required when buying_mode is 'brief'. Must not be provided when buying_mode is 'wholesale' or 'refine'."
        ),
    ] = None
    refine: Annotated[
        list[Refine] | None,
        Field(
            description="Array of change requests for iterating on products and proposals from a previous get_products response. Each entry declares a scope (request, product, or proposal) and what the buyer is asking for. Only valid when buying_mode is 'refine'. The seller responds to each entry via refinement_applied in the response, matched by position.\n\nFinalize-exclusivity rule: if any entry has `action: 'finalize'`, ALL entries in the array MUST be proposal-scoped with `action: 'finalize'` — mixing finalize entries with `include`/`omit` entries or with request- / product-scoped entries MUST be rejected by the seller with `INVALID_REQUEST`. Finalize is a commit, not a refinement; the buyer expressing intent to commit means refinements have already converged. Buyers needing to refine AND commit in close succession sequence the calls: first a refine call (no finalize), then a finalize call against the resulting `proposal_id`(s).\n\nMulti-finalize semantics: multiple finalize entries against different `proposal_id` values in a single call are allowed and MUST be **atomic at the observation point** — sellers MUST NOT return a success response unless every named proposal has both completed and been persisted as committed. Pre-commit validation runs before any side-effects (inventory pull, terms lock, governance attestation); if any proposal fails validation, the seller MUST reject the entire call without committing any of the named proposals. There is no rollback operation in the spec — an `unfinalize` would itself be a new mutation surface; the atomicity guarantee runs entirely on the seller's pre-commit validation gate, not on post-commit reversal. Sellers that cannot guarantee atomic pre-commit validation MUST reject multi-finalize arrays with `MULTI_FINALIZE_UNSUPPORTED` (preferred — distinguishes seller-side capability gap from a malformed request) or `INVALID_REQUEST` (acceptable fallback for sellers on a pre-3.1 error catalog). If a mid-commit failure occurs *after* validation passed but before all proposals persist (e.g., a downstream ad server fails between commits one and two), the seller MUST return `INTERNAL_ERROR` with `refinement_applied[]` carrying per-position outcomes — the spec does NOT define a recovery path for this case, and buyers SHOULD treat the resulting state as undefined and re-read via `get_media_buys` / equivalent before retrying. Buyers MUST NOT assume multi-finalize support without a successful first attempt — there is no capability flag for this; the failure response is the discovery surface. Buyers whose intent specifically requires atomic commit (e.g., budget-shared proposals where one finalizing without the other is incoherent) MUST be prepared to abandon the intent if the seller returns `MULTI_FINALIZE_UNSUPPORTED` — there is no recovery for that loss of buyer intent beyond sequencing single-finalize calls and accepting the looser commit guarantee.",
            min_length=1,
        ),
    ] = None
    brand: Annotated[
        brand_ref.BrandReference | None,
        Field(
            description='Brand reference for product discovery context. Resolved to full brand identity at execution time.'
        ),
    ] = None
    catalog: Annotated[
        catalog_1.Catalog | None,
        Field(
            description='Catalog of items the buyer wants to promote. The seller matches catalog items against its inventory and returns products where matches exist. Supports all catalog types: a job catalog finds job ad products, a product catalog finds sponsored product slots. Reference a synced catalog by catalog_id, or provide inline items.'
        ),
    ] = None
    account: Annotated[
        account_ref.AccountReference | None,
        Field(
            description="Account for product lookup. Returns products with pricing specific to this account's rate card."
        ),
    ] = None
    preferred_delivery_types: Annotated[
        list[delivery_type_1.DeliveryType] | None,
        Field(
            description='Delivery types the buyer prefers, in priority order. Unlike filters.delivery_type which excludes non-matching products, this signals preference for curation — the publisher may still include other delivery types when they match the brief well.',
            min_length=1,
        ),
    ] = None
    filters: product_filters.ProductFilters | None = None
    property_list: Annotated[
        property_list_ref.PropertyListReference | None,
        Field(
            description='[AdCP 3.0] Reference to an externally managed property list. When provided, the sales agent should filter products to only those available on properties in the list.'
        ),
    ] = None
    fields: Annotated[
        list[Field1] | None,
        Field(
            description='Specific product fields to include in the response. When omitted, all fields are returned. Use for lightweight discovery calls where only a subset of product data is needed (e.g., just IDs and pricing for comparison). Required fields (product_id, name) are always included regardless of selection.',
            min_length=1,
        ),
    ] = None
    time_budget: Annotated[
        duration.Duration | None,
        Field(
            description='Maximum time the buyer will commit to this request. The seller returns the best results achievable within this budget and does not start processes (human approvals, expensive external queries) that cannot complete in time. When omitted, the seller decides timing.'
        ),
    ] = None
    push_notification_config: Annotated[
        push_notification_config_1.PushNotificationConfig | None,
        Field(
            description='Optional webhook configuration for async terminal completion/failure notifications on curated discovery. Meaningful only for `buying_mode: "brief"` and `buying_mode: "refine"` requests that enter the async lifecycle. Submitted envelopes with `task_id` remain pollable through `get_task_status` (legacy `tasks/get`) whether or not this field is present. If a brief/refine request includes this field and the seller returns a Submitted envelope, the seller MUST deliver at least the terminal completion/failure notification to the configured URL; intermediate progress notifications are MAY. If the seller cannot honor the webhook channel, it MUST reject the request with a structured error instead of silently accepting. This field does not change wholesale timing semantics: sellers MUST NOT route `buying_mode: "wholesale"` requests through the async/Submitted arm or emit async delivery solely because `push_notification_config` is present; partial wholesale completion is reported via `incomplete[]`.'
        ),
    ] = None
    pagination: Annotated[
        pagination_request.PaginationRequest | None,
        Field(
            description="Cursor-based pagination controls for get_products. Valid in all buying modes. In brief mode, pagination bounds the seller's returned products[] for the curated answer to the brief and is not an exhaustive catalog-enumeration contract. In refine mode, pagination bounds the refined products[] result implied by refine[] and filters; proposals may accompany a page as plan metadata but are not independently counted by this pagination envelope. In wholesale mode, pagination walks the wholesale product feed and may be combined with wholesale feed versioning."
        ),
    ] = None
    if_wholesale_feed_version: Annotated[
        str | None,
        Field(
            description="Opaque wholesale_feed_version token returned by a prior wholesale-mode get_products response from this agent. Only valid when buying_mode is wholesale. When provided, the seller compares against its current wholesale product feed version for the buyer's cache_scope and MAY return an unchanged: true response (with products omitted) if nothing has changed. The token is scope-keyed: buyers cache `(cache_scope, wholesale_feed_version)` pairs. Scoping dimensions: (agent, buying_mode, filters, property_list, catalog) for cache_scope: 'public'; that tuple plus account_id for cache_scope: 'account'. pagination.cursor is NOT part of the scoping tuple. Backward-compatible: pre-v3.1 agents that ignore this field simply return the full payload, same as the unchanged-server path. See specs/wholesale-feed-webhooks.md for the full sync pattern."
        ),
    ] = None
    if_pricing_version: Annotated[
        str | None,
        Field(
            description="Opaque pricing_version token from a prior get_products response. MUST only be sent together with if_wholesale_feed_version — pricing version has no structural baseline to compare against on its own. Evaluation order: (1) if_wholesale_feed_version mismatch → seller returns the full payload (pricing is implicitly stale); (2) if_wholesale_feed_version matches but if_pricing_version mismatches → seller returns the full payload so the buyer sees updated pricing_options; (3) both match → seller MAY return unchanged: true. Agents that don't track pricing separately ignore if_pricing_version and fall back to if_wholesale_feed_version semantics. Useful for storefronts that re-price compositions far more often than they re-render product mirrors."
        ),
    ] = None
    context: context_1.ContextObject | None = None
    required_policies: Annotated[
        list[str] | None,
        Field(
            description='Registry policy IDs that the buyer requires to be enforced for products in this response. Sellers filter products to only those that comply with or already enforce the requested policies.'
        ),
    ] = None
    ext: ext_1.ExtensionObject | None = None

Base model for AdCP types with spec-compliant serialization.

Defaults to extra='ignore' so unknown fields from newer spec versions are silently dropped rather than causing validation errors. Generated types whose schemas set additionalProperties: true override this with extra='allow' in their own model_config.

Set ADCP_STRICT_VALIDATION=1 in the environment ("1", "true", "yes", "on" are accepted) to flip the default to extra='forbid'. Use this during spec upgrades to catch silently-dropped renamed fields in tests. See :func:_resolve_extra_policy.

Important

The env var is resolved once at module import time. Set it in your shell or CI environment before import adcp runs — mutating os.environ["ADCP_STRICT_VALIDATION"] after the first adcp import has no effect on already-imported model classes (they captured the policy at class-body evaluation).

Consumers who want per-model strict validation can override model_config on their subclass.

Create a new model by parsing and validating input data from keyword arguments.

Raises [ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.

self is explicitly positional-only to allow self as a field name.

Ancestors

  • adcp.types.generated_poc.core.version_envelope.AdcpVersionEnvelope
  • AdCPBaseModel
  • pydantic.main.BaseModel

Class variables

var account : adcp.types.generated_poc.core.account_ref.AccountReference | None
var brand : adcp.types.generated_poc.core.brand_ref.BrandReference | None
var brief : str | None
var buying_mode : adcp.types.generated_poc.media_buy.get_products_request.BuyingMode | None
var catalog : adcp.types.generated_poc.core.catalog.Catalog | None
var context : adcp.types.generated_poc.core.context.ContextObject | None
var ext : adcp.types.generated_poc.core.ext.ExtensionObject | None
var fields : list[adcp.types.generated_poc.media_buy.get_products_request.Field1] | None
var filters : adcp.types.generated_poc.core.product_filters.ProductFilters | None
var if_pricing_version : str | None
var if_wholesale_feed_version : str | None
var model_config
var pagination : adcp.types.generated_poc.core.pagination_request.PaginationRequest | None
var preferred_delivery_types : list[adcp.types.generated_poc.enums.delivery_type.DeliveryType] | None
var property_list : adcp.types.generated_poc.core.property_list_ref.PropertyListReference | None
var push_notification_config : adcp.types.generated_poc.core.push_notification_config.PushNotificationConfig | None
var refine : list[adcp.types.generated_poc.media_buy.get_products_request.Refine] | None
var required_policies : list[str] | None
var time_budget : adcp.types.generated_poc.core.duration.Duration | None
class GetProductsRefineRequest (**data: Any)
Expand source code
class GetProductsRequest(AdcpVersionEnvelope):
    model_config = ConfigDict(
        extra='allow',
    )
    buying_mode: Annotated[
        BuyingMode,
        Field(
            description="Declares buyer intent for this request. 'brief': publisher curates product recommendations from the provided brief. 'wholesale': buyer requests raw product inventory to apply their own audiences — brief must not be provided, and proposals are omitted. 'refine': iterate on products and proposals from a previous get_products response using the refine array of change requests. v3 clients MUST include buying_mode. Sellers receiving requests from pre-v3 clients without buying_mode SHOULD default to 'brief'. Timing semantics: 'wholesale' is a wholesale product feed read — sellers SHOULD return a synchronous response and MUST NOT route a 'wholesale' request through the async/Submitted arm; partial completion is signalled via the response's incomplete[] field (with optional estimated_wait), not via a task-handoff envelope. 'brief' and 'refine' MAY complete synchronously, or MAY return a Submitted envelope (see get-products-async-response-submitted.json) when curation requires upstream-system queries or HITL review the seller cannot complete inside time_budget. Buyers needing predictable fast wholesale product feed access MUST use 'wholesale'; buyers open to slower curation use 'brief' or 'refine'."
        ),
    ]
    brief: Annotated[
        str | None,
        Field(
            description="Natural language description of campaign requirements. Required when buying_mode is 'brief'. Must not be provided when buying_mode is 'wholesale' or 'refine'."
        ),
    ] = None
    refine: Annotated[
        list[Refine] | None,
        Field(
            description="Array of change requests for iterating on products and proposals from a previous get_products response. Each entry declares a scope (request, product, or proposal) and what the buyer is asking for. Only valid when buying_mode is 'refine'. The seller responds to each entry via refinement_applied in the response, matched by position.\n\nFinalize-exclusivity rule: if any entry has `action: 'finalize'`, ALL entries in the array MUST be proposal-scoped with `action: 'finalize'` — mixing finalize entries with `include`/`omit` entries or with request- / product-scoped entries MUST be rejected by the seller with `INVALID_REQUEST`. Finalize is a commit, not a refinement; the buyer expressing intent to commit means refinements have already converged. Buyers needing to refine AND commit in close succession sequence the calls: first a refine call (no finalize), then a finalize call against the resulting `proposal_id`(s).\n\nMulti-finalize semantics: multiple finalize entries against different `proposal_id` values in a single call are allowed and MUST be **atomic at the observation point** — sellers MUST NOT return a success response unless every named proposal has both completed and been persisted as committed. Pre-commit validation runs before any side-effects (inventory pull, terms lock, governance attestation); if any proposal fails validation, the seller MUST reject the entire call without committing any of the named proposals. There is no rollback operation in the spec — an `unfinalize` would itself be a new mutation surface; the atomicity guarantee runs entirely on the seller's pre-commit validation gate, not on post-commit reversal. Sellers that cannot guarantee atomic pre-commit validation MUST reject multi-finalize arrays with `MULTI_FINALIZE_UNSUPPORTED` (preferred — distinguishes seller-side capability gap from a malformed request) or `INVALID_REQUEST` (acceptable fallback for sellers on a pre-3.1 error catalog). If a mid-commit failure occurs *after* validation passed but before all proposals persist (e.g., a downstream ad server fails between commits one and two), the seller MUST return `INTERNAL_ERROR` with `refinement_applied[]` carrying per-position outcomes — the spec does NOT define a recovery path for this case, and buyers SHOULD treat the resulting state as undefined and re-read via `get_media_buys` / equivalent before retrying. Buyers MUST NOT assume multi-finalize support without a successful first attempt — there is no capability flag for this; the failure response is the discovery surface. Buyers whose intent specifically requires atomic commit (e.g., budget-shared proposals where one finalizing without the other is incoherent) MUST be prepared to abandon the intent if the seller returns `MULTI_FINALIZE_UNSUPPORTED` — there is no recovery for that loss of buyer intent beyond sequencing single-finalize calls and accepting the looser commit guarantee.",
            min_length=1,
        ),
    ] = None
    brand: Annotated[
        brand_ref.BrandReference | None,
        Field(
            description='Brand reference for product discovery context. Resolved to full brand identity at execution time.'
        ),
    ] = None
    catalog: Annotated[
        catalog_1.Catalog | None,
        Field(
            description='Catalog of items the buyer wants to promote. The seller matches catalog items against its inventory and returns products where matches exist. Supports all catalog types: a job catalog finds job ad products, a product catalog finds sponsored product slots. Reference a synced catalog by catalog_id, or provide inline items.'
        ),
    ] = None
    account: Annotated[
        account_ref.AccountReference | None,
        Field(
            description="Account for product lookup. Returns products with pricing specific to this account's rate card."
        ),
    ] = None
    preferred_delivery_types: Annotated[
        list[delivery_type_1.DeliveryType] | None,
        Field(
            description='Delivery types the buyer prefers, in priority order. Unlike filters.delivery_type which excludes non-matching products, this signals preference for curation — the publisher may still include other delivery types when they match the brief well.',
            min_length=1,
        ),
    ] = None
    filters: product_filters.ProductFilters | None = None
    property_list: Annotated[
        property_list_ref.PropertyListReference | None,
        Field(
            description='[AdCP 3.0] Reference to an externally managed property list. When provided, the sales agent should filter products to only those available on properties in the list.'
        ),
    ] = None
    fields: Annotated[
        list[Field1] | None,
        Field(
            description='Specific product fields to include in the response. When omitted, all fields are returned. Use for lightweight discovery calls where only a subset of product data is needed (e.g., just IDs and pricing for comparison). Required fields (product_id, name) are always included regardless of selection.',
            min_length=1,
        ),
    ] = None
    time_budget: Annotated[
        duration.Duration | None,
        Field(
            description='Maximum time the buyer will commit to this request. The seller returns the best results achievable within this budget and does not start processes (human approvals, expensive external queries) that cannot complete in time. When omitted, the seller decides timing.'
        ),
    ] = None
    push_notification_config: Annotated[
        push_notification_config_1.PushNotificationConfig | None,
        Field(
            description='Optional webhook configuration for async terminal completion/failure notifications on curated discovery. Meaningful only for `buying_mode: "brief"` and `buying_mode: "refine"` requests that enter the async lifecycle. Submitted envelopes with `task_id` remain pollable through `get_task_status` (legacy `tasks/get`) whether or not this field is present. If a brief/refine request includes this field and the seller returns a Submitted envelope, the seller MUST deliver at least the terminal completion/failure notification to the configured URL; intermediate progress notifications are MAY. If the seller cannot honor the webhook channel, it MUST reject the request with a structured error instead of silently accepting. This field does not change wholesale timing semantics: sellers MUST NOT route `buying_mode: "wholesale"` requests through the async/Submitted arm or emit async delivery solely because `push_notification_config` is present; partial wholesale completion is reported via `incomplete[]`.'
        ),
    ] = None
    pagination: Annotated[
        pagination_request.PaginationRequest | None,
        Field(
            description="Cursor-based pagination controls for get_products. Valid in all buying modes. In brief mode, pagination bounds the seller's returned products[] for the curated answer to the brief and is not an exhaustive catalog-enumeration contract. In refine mode, pagination bounds the refined products[] result implied by refine[] and filters; proposals may accompany a page as plan metadata but are not independently counted by this pagination envelope. In wholesale mode, pagination walks the wholesale product feed and may be combined with wholesale feed versioning."
        ),
    ] = None
    if_wholesale_feed_version: Annotated[
        str | None,
        Field(
            description="Opaque wholesale_feed_version token returned by a prior wholesale-mode get_products response from this agent. Only valid when buying_mode is wholesale. When provided, the seller compares against its current wholesale product feed version for the buyer's cache_scope and MAY return an unchanged: true response (with products omitted) if nothing has changed. The token is scope-keyed: buyers cache `(cache_scope, wholesale_feed_version)` pairs. Scoping dimensions: (agent, buying_mode, filters, property_list, catalog) for cache_scope: 'public'; that tuple plus account_id for cache_scope: 'account'. pagination.cursor is NOT part of the scoping tuple. Backward-compatible: pre-v3.1 agents that ignore this field simply return the full payload, same as the unchanged-server path. See specs/wholesale-feed-webhooks.md for the full sync pattern."
        ),
    ] = None
    if_pricing_version: Annotated[
        str | None,
        Field(
            description="Opaque pricing_version token from a prior get_products response. MUST only be sent together with if_wholesale_feed_version — pricing version has no structural baseline to compare against on its own. Evaluation order: (1) if_wholesale_feed_version mismatch → seller returns the full payload (pricing is implicitly stale); (2) if_wholesale_feed_version matches but if_pricing_version mismatches → seller returns the full payload so the buyer sees updated pricing_options; (3) both match → seller MAY return unchanged: true. Agents that don't track pricing separately ignore if_pricing_version and fall back to if_wholesale_feed_version semantics. Useful for storefronts that re-price compositions far more often than they re-render product mirrors."
        ),
    ] = None
    context: context_1.ContextObject | None = None
    required_policies: Annotated[
        list[str] | None,
        Field(
            description='Registry policy IDs that the buyer requires to be enforced for products in this response. Sellers filter products to only those that comply with or already enforce the requested policies.'
        ),
    ] = None
    ext: ext_1.ExtensionObject | None = None

Base model for AdCP types with spec-compliant serialization.

Defaults to extra='ignore' so unknown fields from newer spec versions are silently dropped rather than causing validation errors. Generated types whose schemas set additionalProperties: true override this with extra='allow' in their own model_config.

Set ADCP_STRICT_VALIDATION=1 in the environment ("1", "true", "yes", "on" are accepted) to flip the default to extra='forbid'. Use this during spec upgrades to catch silently-dropped renamed fields in tests. See :func:_resolve_extra_policy.

Important

The env var is resolved once at module import time. Set it in your shell or CI environment before import adcp runs — mutating os.environ["ADCP_STRICT_VALIDATION"] after the first adcp import has no effect on already-imported model classes (they captured the policy at class-body evaluation).

Consumers who want per-model strict validation can override model_config on their subclass.

Create a new model by parsing and validating input data from keyword arguments.

Raises [ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.

self is explicitly positional-only to allow self as a field name.

Ancestors

  • adcp.types.generated_poc.core.version_envelope.AdcpVersionEnvelope
  • AdCPBaseModel
  • pydantic.main.BaseModel

Class variables

var account : adcp.types.generated_poc.core.account_ref.AccountReference | None
var brand : adcp.types.generated_poc.core.brand_ref.BrandReference | None
var brief : str | None
var buying_mode : adcp.types.generated_poc.media_buy.get_products_request.BuyingMode | None
var catalog : adcp.types.generated_poc.core.catalog.Catalog | None
var context : adcp.types.generated_poc.core.context.ContextObject | None
var ext : adcp.types.generated_poc.core.ext.ExtensionObject | None
var fields : list[adcp.types.generated_poc.media_buy.get_products_request.Field1] | None
var filters : adcp.types.generated_poc.core.product_filters.ProductFilters | None
var if_pricing_version : str | None
var if_wholesale_feed_version : str | None
var model_config
var pagination : adcp.types.generated_poc.core.pagination_request.PaginationRequest | None
var preferred_delivery_types : list[adcp.types.generated_poc.enums.delivery_type.DeliveryType] | None
var property_list : adcp.types.generated_poc.core.property_list_ref.PropertyListReference | None
var push_notification_config : adcp.types.generated_poc.core.push_notification_config.PushNotificationConfig | None
var refine : list[adcp.types.generated_poc.media_buy.get_products_request.Refine] | None
var required_policies : list[str] | None
var time_budget : adcp.types.generated_poc.core.duration.Duration | None
class GetProductsWholesaleRequest (**data: Any)
Expand source code
class GetProductsRequest(AdcpVersionEnvelope):
    model_config = ConfigDict(
        extra='allow',
    )
    buying_mode: Annotated[
        BuyingMode,
        Field(
            description="Declares buyer intent for this request. 'brief': publisher curates product recommendations from the provided brief. 'wholesale': buyer requests raw product inventory to apply their own audiences — brief must not be provided, and proposals are omitted. 'refine': iterate on products and proposals from a previous get_products response using the refine array of change requests. v3 clients MUST include buying_mode. Sellers receiving requests from pre-v3 clients without buying_mode SHOULD default to 'brief'. Timing semantics: 'wholesale' is a wholesale product feed read — sellers SHOULD return a synchronous response and MUST NOT route a 'wholesale' request through the async/Submitted arm; partial completion is signalled via the response's incomplete[] field (with optional estimated_wait), not via a task-handoff envelope. 'brief' and 'refine' MAY complete synchronously, or MAY return a Submitted envelope (see get-products-async-response-submitted.json) when curation requires upstream-system queries or HITL review the seller cannot complete inside time_budget. Buyers needing predictable fast wholesale product feed access MUST use 'wholesale'; buyers open to slower curation use 'brief' or 'refine'."
        ),
    ]
    brief: Annotated[
        str | None,
        Field(
            description="Natural language description of campaign requirements. Required when buying_mode is 'brief'. Must not be provided when buying_mode is 'wholesale' or 'refine'."
        ),
    ] = None
    refine: Annotated[
        list[Refine] | None,
        Field(
            description="Array of change requests for iterating on products and proposals from a previous get_products response. Each entry declares a scope (request, product, or proposal) and what the buyer is asking for. Only valid when buying_mode is 'refine'. The seller responds to each entry via refinement_applied in the response, matched by position.\n\nFinalize-exclusivity rule: if any entry has `action: 'finalize'`, ALL entries in the array MUST be proposal-scoped with `action: 'finalize'` — mixing finalize entries with `include`/`omit` entries or with request- / product-scoped entries MUST be rejected by the seller with `INVALID_REQUEST`. Finalize is a commit, not a refinement; the buyer expressing intent to commit means refinements have already converged. Buyers needing to refine AND commit in close succession sequence the calls: first a refine call (no finalize), then a finalize call against the resulting `proposal_id`(s).\n\nMulti-finalize semantics: multiple finalize entries against different `proposal_id` values in a single call are allowed and MUST be **atomic at the observation point** — sellers MUST NOT return a success response unless every named proposal has both completed and been persisted as committed. Pre-commit validation runs before any side-effects (inventory pull, terms lock, governance attestation); if any proposal fails validation, the seller MUST reject the entire call without committing any of the named proposals. There is no rollback operation in the spec — an `unfinalize` would itself be a new mutation surface; the atomicity guarantee runs entirely on the seller's pre-commit validation gate, not on post-commit reversal. Sellers that cannot guarantee atomic pre-commit validation MUST reject multi-finalize arrays with `MULTI_FINALIZE_UNSUPPORTED` (preferred — distinguishes seller-side capability gap from a malformed request) or `INVALID_REQUEST` (acceptable fallback for sellers on a pre-3.1 error catalog). If a mid-commit failure occurs *after* validation passed but before all proposals persist (e.g., a downstream ad server fails between commits one and two), the seller MUST return `INTERNAL_ERROR` with `refinement_applied[]` carrying per-position outcomes — the spec does NOT define a recovery path for this case, and buyers SHOULD treat the resulting state as undefined and re-read via `get_media_buys` / equivalent before retrying. Buyers MUST NOT assume multi-finalize support without a successful first attempt — there is no capability flag for this; the failure response is the discovery surface. Buyers whose intent specifically requires atomic commit (e.g., budget-shared proposals where one finalizing without the other is incoherent) MUST be prepared to abandon the intent if the seller returns `MULTI_FINALIZE_UNSUPPORTED` — there is no recovery for that loss of buyer intent beyond sequencing single-finalize calls and accepting the looser commit guarantee.",
            min_length=1,
        ),
    ] = None
    brand: Annotated[
        brand_ref.BrandReference | None,
        Field(
            description='Brand reference for product discovery context. Resolved to full brand identity at execution time.'
        ),
    ] = None
    catalog: Annotated[
        catalog_1.Catalog | None,
        Field(
            description='Catalog of items the buyer wants to promote. The seller matches catalog items against its inventory and returns products where matches exist. Supports all catalog types: a job catalog finds job ad products, a product catalog finds sponsored product slots. Reference a synced catalog by catalog_id, or provide inline items.'
        ),
    ] = None
    account: Annotated[
        account_ref.AccountReference | None,
        Field(
            description="Account for product lookup. Returns products with pricing specific to this account's rate card."
        ),
    ] = None
    preferred_delivery_types: Annotated[
        list[delivery_type_1.DeliveryType] | None,
        Field(
            description='Delivery types the buyer prefers, in priority order. Unlike filters.delivery_type which excludes non-matching products, this signals preference for curation — the publisher may still include other delivery types when they match the brief well.',
            min_length=1,
        ),
    ] = None
    filters: product_filters.ProductFilters | None = None
    property_list: Annotated[
        property_list_ref.PropertyListReference | None,
        Field(
            description='[AdCP 3.0] Reference to an externally managed property list. When provided, the sales agent should filter products to only those available on properties in the list.'
        ),
    ] = None
    fields: Annotated[
        list[Field1] | None,
        Field(
            description='Specific product fields to include in the response. When omitted, all fields are returned. Use for lightweight discovery calls where only a subset of product data is needed (e.g., just IDs and pricing for comparison). Required fields (product_id, name) are always included regardless of selection.',
            min_length=1,
        ),
    ] = None
    time_budget: Annotated[
        duration.Duration | None,
        Field(
            description='Maximum time the buyer will commit to this request. The seller returns the best results achievable within this budget and does not start processes (human approvals, expensive external queries) that cannot complete in time. When omitted, the seller decides timing.'
        ),
    ] = None
    push_notification_config: Annotated[
        push_notification_config_1.PushNotificationConfig | None,
        Field(
            description='Optional webhook configuration for async terminal completion/failure notifications on curated discovery. Meaningful only for `buying_mode: "brief"` and `buying_mode: "refine"` requests that enter the async lifecycle. Submitted envelopes with `task_id` remain pollable through `get_task_status` (legacy `tasks/get`) whether or not this field is present. If a brief/refine request includes this field and the seller returns a Submitted envelope, the seller MUST deliver at least the terminal completion/failure notification to the configured URL; intermediate progress notifications are MAY. If the seller cannot honor the webhook channel, it MUST reject the request with a structured error instead of silently accepting. This field does not change wholesale timing semantics: sellers MUST NOT route `buying_mode: "wholesale"` requests through the async/Submitted arm or emit async delivery solely because `push_notification_config` is present; partial wholesale completion is reported via `incomplete[]`.'
        ),
    ] = None
    pagination: Annotated[
        pagination_request.PaginationRequest | None,
        Field(
            description="Cursor-based pagination controls for get_products. Valid in all buying modes. In brief mode, pagination bounds the seller's returned products[] for the curated answer to the brief and is not an exhaustive catalog-enumeration contract. In refine mode, pagination bounds the refined products[] result implied by refine[] and filters; proposals may accompany a page as plan metadata but are not independently counted by this pagination envelope. In wholesale mode, pagination walks the wholesale product feed and may be combined with wholesale feed versioning."
        ),
    ] = None
    if_wholesale_feed_version: Annotated[
        str | None,
        Field(
            description="Opaque wholesale_feed_version token returned by a prior wholesale-mode get_products response from this agent. Only valid when buying_mode is wholesale. When provided, the seller compares against its current wholesale product feed version for the buyer's cache_scope and MAY return an unchanged: true response (with products omitted) if nothing has changed. The token is scope-keyed: buyers cache `(cache_scope, wholesale_feed_version)` pairs. Scoping dimensions: (agent, buying_mode, filters, property_list, catalog) for cache_scope: 'public'; that tuple plus account_id for cache_scope: 'account'. pagination.cursor is NOT part of the scoping tuple. Backward-compatible: pre-v3.1 agents that ignore this field simply return the full payload, same as the unchanged-server path. See specs/wholesale-feed-webhooks.md for the full sync pattern."
        ),
    ] = None
    if_pricing_version: Annotated[
        str | None,
        Field(
            description="Opaque pricing_version token from a prior get_products response. MUST only be sent together with if_wholesale_feed_version — pricing version has no structural baseline to compare against on its own. Evaluation order: (1) if_wholesale_feed_version mismatch → seller returns the full payload (pricing is implicitly stale); (2) if_wholesale_feed_version matches but if_pricing_version mismatches → seller returns the full payload so the buyer sees updated pricing_options; (3) both match → seller MAY return unchanged: true. Agents that don't track pricing separately ignore if_pricing_version and fall back to if_wholesale_feed_version semantics. Useful for storefronts that re-price compositions far more often than they re-render product mirrors."
        ),
    ] = None
    context: context_1.ContextObject | None = None
    required_policies: Annotated[
        list[str] | None,
        Field(
            description='Registry policy IDs that the buyer requires to be enforced for products in this response. Sellers filter products to only those that comply with or already enforce the requested policies.'
        ),
    ] = None
    ext: ext_1.ExtensionObject | None = None

Base model for AdCP types with spec-compliant serialization.

Defaults to extra='ignore' so unknown fields from newer spec versions are silently dropped rather than causing validation errors. Generated types whose schemas set additionalProperties: true override this with extra='allow' in their own model_config.

Set ADCP_STRICT_VALIDATION=1 in the environment ("1", "true", "yes", "on" are accepted) to flip the default to extra='forbid'. Use this during spec upgrades to catch silently-dropped renamed fields in tests. See :func:_resolve_extra_policy.

Important

The env var is resolved once at module import time. Set it in your shell or CI environment before import adcp runs — mutating os.environ["ADCP_STRICT_VALIDATION"] after the first adcp import has no effect on already-imported model classes (they captured the policy at class-body evaluation).

Consumers who want per-model strict validation can override model_config on their subclass.

Create a new model by parsing and validating input data from keyword arguments.

Raises [ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.

self is explicitly positional-only to allow self as a field name.

Ancestors

  • adcp.types.generated_poc.core.version_envelope.AdcpVersionEnvelope
  • AdCPBaseModel
  • pydantic.main.BaseModel

Class variables

var account : adcp.types.generated_poc.core.account_ref.AccountReference | None
var brand : adcp.types.generated_poc.core.brand_ref.BrandReference | None
var brief : str | None
var buying_mode : adcp.types.generated_poc.media_buy.get_products_request.BuyingMode | None
var catalog : adcp.types.generated_poc.core.catalog.Catalog | None
var context : adcp.types.generated_poc.core.context.ContextObject | None
var ext : adcp.types.generated_poc.core.ext.ExtensionObject | None
var fields : list[adcp.types.generated_poc.media_buy.get_products_request.Field1] | None
var filters : adcp.types.generated_poc.core.product_filters.ProductFilters | None
var if_pricing_version : str | None
var if_wholesale_feed_version : str | None
var model_config
var pagination : adcp.types.generated_poc.core.pagination_request.PaginationRequest | None
var preferred_delivery_types : list[adcp.types.generated_poc.enums.delivery_type.DeliveryType] | None
var property_list : adcp.types.generated_poc.core.property_list_ref.PropertyListReference | None
var push_notification_config : adcp.types.generated_poc.core.push_notification_config.PushNotificationConfig | None
var refine : list[adcp.types.generated_poc.media_buy.get_products_request.Refine] | None
var required_policies : list[str] | None
var time_budget : adcp.types.generated_poc.core.duration.Duration | None

Inherited members

class GetProductsResponse (**data: Any)
Expand source code
class GetProductsResponse(AdcpVersionEnvelope, ProtocolEnvelope):
    model_config = ConfigDict(
        extra='allow',
    )
    products: Annotated[
        list[product.Product] | None, Field(description='Array of matching products')
    ] = None
    extensions: Annotated[
        dict[Annotated[str, StringConstraints(pattern=r'^https?://[^@]+@sha256:[a-f0-9]{64}$')], Extensions] | None,
        Field(
            description='Bundled platform-extension definitions referenced by any product in `products`. Keyed by `<extension_uri>@<digest>` (e.g., `https://creative.adcontextprotocol.org/translated/meta/extensions/meta_pixel@sha256:abc...`). When present, lets buyers resolve `platform_extensions` references on product format declarations without a separate fetch. Buyer SDKs cache by URI@digest; subsequent get_products responses MAY omit definitions the buyer already has cached and rely on the digest match. Each value is an extension definition with `extends` (the canonical concept it extends, e.g., `tracking`), `fields` (the schema for additional fields the extension contributes), `version`, and optional `description`.'
        ),
    ] = None
    proposals: Annotated[
        list[proposal.Proposal] | None,
        Field(
            description='Optional array of proposed media plans with budget allocations across products. Publishers include proposals when they can provide strategic guidance based on the brief. Proposals are actionable - buyers can refine them via follow-up get_products calls within the same session, or execute them directly via create_media_buy.'
        ),
    ] = None
    errors: Annotated[
        list[error.Error] | None,
        Field(description='Task-specific errors and warnings (e.g., product filtering issues)'),
    ] = None
    property_list_applied: Annotated[
        bool | None,
        Field(
            description='[AdCP 3.0] Indicates whether property_list filtering was applied. True if the agent filtered products based on the provided property_list. Absent or false if property_list was not provided or not supported by this agent.'
        ),
    ] = None
    catalog_applied: Annotated[
        bool | None,
        Field(
            description='Whether the seller filtered results based on the provided catalog. True if the seller matched catalog items against its inventory. Absent or false if no catalog was provided or the seller does not support catalog matching.'
        ),
    ] = None
    refinement_applied: Annotated[
        list[RefinementApplied] | None,
        Field(
            description="Seller's response to each change request in the refine array, matched by position. Each entry acknowledges whether the corresponding ask was applied, partially applied, or unable to be fulfilled. MUST contain the same number of entries in the same order as the request's refine array. Only present when the request used buying_mode: 'refine'. Each entry MUST echo the request entry's scope and — for product and proposal scopes — the matching id field (product_id or proposal_id), so orchestrators can cross-validate alignment."
        ),
    ] = None
    incomplete: Annotated[
        list[IncompleteItem] | None,
        Field(
            description="Declares what the seller could not finish within the buyer's time_budget or due to internal limits. Each entry identifies a scope that is missing or partial. Absent when the response is fully complete.",
            min_length=1,
        ),
    ] = None
    filter_diagnostics: Annotated[
        FilterDiagnostics | None,
        Field(
            description="Optional non-fatal diagnostic block describing how the request's `filters` narrowed the candidate set. Use this to disambiguate empty/small result lists between 'no inventory matches the brief' and 'a specific filter excluded everything', without breaking the filter-not-fail convention (sellers still silently exclude unmatched products; this block is observability, not error reporting). Sellers MAY populate this when meaningful narrowing occurred; buyers MAY use it for triage UX without depending on its presence. Counts only — products are not enumerated by name to avoid leaking competitive intelligence about adjacent campaigns or seller inventory. `total_candidates` and `excluded_by` are independently optional — sellers whose baseline candidate set size is sensitive MAY emit `excluded_by` without `total_candidates`, or vice versa.",
            examples=[
                {
                    'semantics': 'only',
                    'total_candidates': 47,
                    'excluded_by': {
                        'required_metrics': {'count': 31, 'values': ['completed_views']},
                        'required_geo_targeting': {'count': 9},
                        'pricing_currencies': {'count': 3, 'values': ['USD']},
                        'budget_range': {'count': 7},
                    },
                }
            ],
        ),
    ] = None
    pagination: Annotated[
        pagination_response.PaginationResponse | None,
        Field(
            description="Cursor metadata for paginated get_products responses. In brief/refine mode, continuation pages bound returned products[] for the seller's curated or refined answer; proposals may accompany a page as plan metadata but are not independently counted by this pagination envelope, and pagination does not convert the response into an exhaustive feed contract. In wholesale mode, continuation pages walk the wholesale product feed."
        ),
    ] = None
    wholesale_feed_version: Annotated[
        str | None,
        Field(
            description="Opaque token representing the version of the wholesale product feed state used to compose this response. Sellers that implement conditional-fetch (if_wholesale_feed_version) MUST return this on every wholesale-mode response so buyers can cache and probe later. Buyers MUST treat the value as opaque — no format, no ordering, no inspection. The token is scope-keyed: it describes a version for the cache_scope declared on this response, NOT a global agent version. A buyer caches `(cache_scope, wholesale_feed_version)` pairs and presents the matching token on the next request. Scoping dimensions: (agent, buying_mode, filters, property_list, catalog) for cache_scope: 'public'; that tuple plus account_id for cache_scope: 'account'. pagination.cursor is NOT part of the scoping tuple. See specs/wholesale-feed-webhooks.md for the full cache layering model."
        ),
    ] = None
    pricing_version: Annotated[
        str | None,
        Field(
            description='Opaque token representing the version of the pricing layer, including product pricing_options and nested signal_targeting_options pricing_options. When the seller supports independent pricing versioning, pricing_version changes when prices move but wholesale_feed_version changes only when structure/metadata moves. Same cache_scope keying as wholesale_feed_version. Sellers not separating these MAY omit pricing_version and use wholesale_feed_version for both.'
        ),
    ] = None
    cache_scope: Annotated[
        CacheScope | None,
        Field(
            description="Declares whether the wholesale_feed_version and pricing_version on this response describe a universal layer or an account-specific overlay. REQUIRED on every 3.1+ response (the 3.1 schema enforces this — the safety property of the two-layer cache model depends on it). 'public': this response describes the seller's published rate card; the buyer MAY dedupe under (agent, buying_mode, filters, property_list, catalog) without scoping by account. 'account': this response includes account-specific overrides; the buyer MUST cache the version under (agent, buying_mode, filters, property_list, catalog, account_id). When the request did NOT include `account`, the seller MUST return `cache_scope: 'public'`. When the request included `account`, the seller MUST return either: 'public' (this account prices off the public rate card — buyer dedupes) or 'account' (account-specific overrides exist — buyer caches under the account key). Sellers MAY return 'public' on an account-scoped request that previously had overrides — buyers SHOULD interpret this as a downgrade and drop their account-overlay for the (agent, filters, mode) tuple. Without schema-required cache_scope, a seller silently omitting the field on an account-scoped response would cause buyers to mis-key the cache and serve account-overlay payloads to other accounts — the canonical safety invariant of the entire cache layering model. **Backward-compatibility note for 3.1 validators:** SDKs that validate strictly against the 3.1 schema MUST select the validator based on the server-declared `adcp_version` (release-precision version negotiation, 3.1). For responses with `adcp_version` starting `3.0`, the 3.1 cache_scope-required constraint MUST be relaxed — pre-3.1 sellers correctly emit no cache_scope and remain conformant to their declared version. This is a tightening within 3.1, not a 3.0 break."
        ),
    ] = CacheScope.public
    unchanged: Annotated[
        Literal[True] | None,
        Field(
            description="Present and `true` ONLY on wholesale-mode responses when the request carried if_wholesale_feed_version (and/or if_pricing_version) matching the seller's current version for the buyer's cache_scope, in which case products[] MUST be omitted; wholesale_feed_version (echoed), cache_scope (echoed), and pricing_version (echoed when used) MUST still be present. Buyers receiving unchanged: true MUST NOT mutate their local wholesale product mirror. **One shape per state:** sellers MUST NOT emit `unchanged: false` — the absence of the field IS the signal that the response carries products. Two shapes ({ unchanged: false, products: [...] } vs. { products: [...] }) for the same state would let some sellers always emit the field and some never would, creating an inconsistency the wire shouldn't carry."
        ),
    ] = None
    sandbox: Annotated[
        bool | None,
        Field(description='When true, this response contains simulated data from sandbox mode.'),
    ] = None
    context: context_1.ContextObject | None = None
    ext: ext_1.ExtensionObject | None = None

Base model for AdCP types with spec-compliant serialization.

Defaults to extra='ignore' so unknown fields from newer spec versions are silently dropped rather than causing validation errors. Generated types whose schemas set additionalProperties: true override this with extra='allow' in their own model_config.

Set ADCP_STRICT_VALIDATION=1 in the environment ("1", "true", "yes", "on" are accepted) to flip the default to extra='forbid'. Use this during spec upgrades to catch silently-dropped renamed fields in tests. See :func:_resolve_extra_policy.

Important

The env var is resolved once at module import time. Set it in your shell or CI environment before import adcp runs — mutating os.environ["ADCP_STRICT_VALIDATION"] after the first adcp import has no effect on already-imported model classes (they captured the policy at class-body evaluation).

Consumers who want per-model strict validation can override model_config on their subclass.

Create a new model by parsing and validating input data from keyword arguments.

Raises [ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.

self is explicitly positional-only to allow self as a field name.

Ancestors

  • adcp.types.generated_poc.core.version_envelope.AdcpVersionEnvelope
  • adcp.types.generated_poc.core.protocol_envelope.ProtocolEnvelope
  • AdCPBaseModel
  • pydantic.main.BaseModel

Class variables

var cache_scope : adcp.types.generated_poc.media_buy.get_products_response.CacheScope | None
var catalog_applied : bool | None
var context : adcp.types.generated_poc.core.context.ContextObject | None
var errors : list[adcp.types.generated_poc.core.error.Error] | None
var ext : adcp.types.generated_poc.core.ext.ExtensionObject | None
var extensions : dict[str, adcp.types.generated_poc.media_buy.get_products_response.Extensions] | None
var filter_diagnostics : adcp.types.generated_poc.media_buy.get_products_response.FilterDiagnostics | None
var incomplete : list[adcp.types.generated_poc.media_buy.get_products_response.IncompleteItem] | None
var model_config
var pagination : adcp.types.generated_poc.core.pagination_response.PaginationResponse | None
var pricing_version : str | None
var products : list[adcp.types.generated_poc.core.product.Product] | None
var property_list_applied : bool | None
var proposals : list[adcp.types.generated_poc.core.proposal.Proposal] | None
var refinement_applied : list[adcp.types.generated_poc.media_buy.get_products_response.RefinementApplied] | None
var sandbox : bool | None
var status : adcp.types.generated_poc.enums.task_status.TaskStatus | None
var unchanged : Literal[True] | None
var wholesale_feed_version : str | None
class GetProductsSuccessResponse (**data: Any)
Expand source code
class GetProductsResponse(AdcpVersionEnvelope, ProtocolEnvelope):
    model_config = ConfigDict(
        extra='allow',
    )
    products: Annotated[
        list[product.Product] | None, Field(description='Array of matching products')
    ] = None
    extensions: Annotated[
        dict[Annotated[str, StringConstraints(pattern=r'^https?://[^@]+@sha256:[a-f0-9]{64}$')], Extensions] | None,
        Field(
            description='Bundled platform-extension definitions referenced by any product in `products`. Keyed by `<extension_uri>@<digest>` (e.g., `https://creative.adcontextprotocol.org/translated/meta/extensions/meta_pixel@sha256:abc...`). When present, lets buyers resolve `platform_extensions` references on product format declarations without a separate fetch. Buyer SDKs cache by URI@digest; subsequent get_products responses MAY omit definitions the buyer already has cached and rely on the digest match. Each value is an extension definition with `extends` (the canonical concept it extends, e.g., `tracking`), `fields` (the schema for additional fields the extension contributes), `version`, and optional `description`.'
        ),
    ] = None
    proposals: Annotated[
        list[proposal.Proposal] | None,
        Field(
            description='Optional array of proposed media plans with budget allocations across products. Publishers include proposals when they can provide strategic guidance based on the brief. Proposals are actionable - buyers can refine them via follow-up get_products calls within the same session, or execute them directly via create_media_buy.'
        ),
    ] = None
    errors: Annotated[
        list[error.Error] | None,
        Field(description='Task-specific errors and warnings (e.g., product filtering issues)'),
    ] = None
    property_list_applied: Annotated[
        bool | None,
        Field(
            description='[AdCP 3.0] Indicates whether property_list filtering was applied. True if the agent filtered products based on the provided property_list. Absent or false if property_list was not provided or not supported by this agent.'
        ),
    ] = None
    catalog_applied: Annotated[
        bool | None,
        Field(
            description='Whether the seller filtered results based on the provided catalog. True if the seller matched catalog items against its inventory. Absent or false if no catalog was provided or the seller does not support catalog matching.'
        ),
    ] = None
    refinement_applied: Annotated[
        list[RefinementApplied] | None,
        Field(
            description="Seller's response to each change request in the refine array, matched by position. Each entry acknowledges whether the corresponding ask was applied, partially applied, or unable to be fulfilled. MUST contain the same number of entries in the same order as the request's refine array. Only present when the request used buying_mode: 'refine'. Each entry MUST echo the request entry's scope and — for product and proposal scopes — the matching id field (product_id or proposal_id), so orchestrators can cross-validate alignment."
        ),
    ] = None
    incomplete: Annotated[
        list[IncompleteItem] | None,
        Field(
            description="Declares what the seller could not finish within the buyer's time_budget or due to internal limits. Each entry identifies a scope that is missing or partial. Absent when the response is fully complete.",
            min_length=1,
        ),
    ] = None
    filter_diagnostics: Annotated[
        FilterDiagnostics | None,
        Field(
            description="Optional non-fatal diagnostic block describing how the request's `filters` narrowed the candidate set. Use this to disambiguate empty/small result lists between 'no inventory matches the brief' and 'a specific filter excluded everything', without breaking the filter-not-fail convention (sellers still silently exclude unmatched products; this block is observability, not error reporting). Sellers MAY populate this when meaningful narrowing occurred; buyers MAY use it for triage UX without depending on its presence. Counts only — products are not enumerated by name to avoid leaking competitive intelligence about adjacent campaigns or seller inventory. `total_candidates` and `excluded_by` are independently optional — sellers whose baseline candidate set size is sensitive MAY emit `excluded_by` without `total_candidates`, or vice versa.",
            examples=[
                {
                    'semantics': 'only',
                    'total_candidates': 47,
                    'excluded_by': {
                        'required_metrics': {'count': 31, 'values': ['completed_views']},
                        'required_geo_targeting': {'count': 9},
                        'pricing_currencies': {'count': 3, 'values': ['USD']},
                        'budget_range': {'count': 7},
                    },
                }
            ],
        ),
    ] = None
    pagination: Annotated[
        pagination_response.PaginationResponse | None,
        Field(
            description="Cursor metadata for paginated get_products responses. In brief/refine mode, continuation pages bound returned products[] for the seller's curated or refined answer; proposals may accompany a page as plan metadata but are not independently counted by this pagination envelope, and pagination does not convert the response into an exhaustive feed contract. In wholesale mode, continuation pages walk the wholesale product feed."
        ),
    ] = None
    wholesale_feed_version: Annotated[
        str | None,
        Field(
            description="Opaque token representing the version of the wholesale product feed state used to compose this response. Sellers that implement conditional-fetch (if_wholesale_feed_version) MUST return this on every wholesale-mode response so buyers can cache and probe later. Buyers MUST treat the value as opaque — no format, no ordering, no inspection. The token is scope-keyed: it describes a version for the cache_scope declared on this response, NOT a global agent version. A buyer caches `(cache_scope, wholesale_feed_version)` pairs and presents the matching token on the next request. Scoping dimensions: (agent, buying_mode, filters, property_list, catalog) for cache_scope: 'public'; that tuple plus account_id for cache_scope: 'account'. pagination.cursor is NOT part of the scoping tuple. See specs/wholesale-feed-webhooks.md for the full cache layering model."
        ),
    ] = None
    pricing_version: Annotated[
        str | None,
        Field(
            description='Opaque token representing the version of the pricing layer, including product pricing_options and nested signal_targeting_options pricing_options. When the seller supports independent pricing versioning, pricing_version changes when prices move but wholesale_feed_version changes only when structure/metadata moves. Same cache_scope keying as wholesale_feed_version. Sellers not separating these MAY omit pricing_version and use wholesale_feed_version for both.'
        ),
    ] = None
    cache_scope: Annotated[
        CacheScope | None,
        Field(
            description="Declares whether the wholesale_feed_version and pricing_version on this response describe a universal layer or an account-specific overlay. REQUIRED on every 3.1+ response (the 3.1 schema enforces this — the safety property of the two-layer cache model depends on it). 'public': this response describes the seller's published rate card; the buyer MAY dedupe under (agent, buying_mode, filters, property_list, catalog) without scoping by account. 'account': this response includes account-specific overrides; the buyer MUST cache the version under (agent, buying_mode, filters, property_list, catalog, account_id). When the request did NOT include `account`, the seller MUST return `cache_scope: 'public'`. When the request included `account`, the seller MUST return either: 'public' (this account prices off the public rate card — buyer dedupes) or 'account' (account-specific overrides exist — buyer caches under the account key). Sellers MAY return 'public' on an account-scoped request that previously had overrides — buyers SHOULD interpret this as a downgrade and drop their account-overlay for the (agent, filters, mode) tuple. Without schema-required cache_scope, a seller silently omitting the field on an account-scoped response would cause buyers to mis-key the cache and serve account-overlay payloads to other accounts — the canonical safety invariant of the entire cache layering model. **Backward-compatibility note for 3.1 validators:** SDKs that validate strictly against the 3.1 schema MUST select the validator based on the server-declared `adcp_version` (release-precision version negotiation, 3.1). For responses with `adcp_version` starting `3.0`, the 3.1 cache_scope-required constraint MUST be relaxed — pre-3.1 sellers correctly emit no cache_scope and remain conformant to their declared version. This is a tightening within 3.1, not a 3.0 break."
        ),
    ] = CacheScope.public
    unchanged: Annotated[
        Literal[True] | None,
        Field(
            description="Present and `true` ONLY on wholesale-mode responses when the request carried if_wholesale_feed_version (and/or if_pricing_version) matching the seller's current version for the buyer's cache_scope, in which case products[] MUST be omitted; wholesale_feed_version (echoed), cache_scope (echoed), and pricing_version (echoed when used) MUST still be present. Buyers receiving unchanged: true MUST NOT mutate their local wholesale product mirror. **One shape per state:** sellers MUST NOT emit `unchanged: false` — the absence of the field IS the signal that the response carries products. Two shapes ({ unchanged: false, products: [...] } vs. { products: [...] }) for the same state would let some sellers always emit the field and some never would, creating an inconsistency the wire shouldn't carry."
        ),
    ] = None
    sandbox: Annotated[
        bool | None,
        Field(description='When true, this response contains simulated data from sandbox mode.'),
    ] = None
    context: context_1.ContextObject | None = None
    ext: ext_1.ExtensionObject | None = None

Base model for AdCP types with spec-compliant serialization.

Defaults to extra='ignore' so unknown fields from newer spec versions are silently dropped rather than causing validation errors. Generated types whose schemas set additionalProperties: true override this with extra='allow' in their own model_config.

Set ADCP_STRICT_VALIDATION=1 in the environment ("1", "true", "yes", "on" are accepted) to flip the default to extra='forbid'. Use this during spec upgrades to catch silently-dropped renamed fields in tests. See :func:_resolve_extra_policy.

Important

The env var is resolved once at module import time. Set it in your shell or CI environment before import adcp runs — mutating os.environ["ADCP_STRICT_VALIDATION"] after the first adcp import has no effect on already-imported model classes (they captured the policy at class-body evaluation).

Consumers who want per-model strict validation can override model_config on their subclass.

Create a new model by parsing and validating input data from keyword arguments.

Raises [ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.

self is explicitly positional-only to allow self as a field name.

Ancestors

  • adcp.types.generated_poc.core.version_envelope.AdcpVersionEnvelope
  • adcp.types.generated_poc.core.protocol_envelope.ProtocolEnvelope
  • AdCPBaseModel
  • pydantic.main.BaseModel

Class variables

var cache_scope : adcp.types.generated_poc.media_buy.get_products_response.CacheScope | None
var catalog_applied : bool | None
var context : adcp.types.generated_poc.core.context.ContextObject | None
var errors : list[adcp.types.generated_poc.core.error.Error] | None
var ext : adcp.types.generated_poc.core.ext.ExtensionObject | None
var extensions : dict[str, adcp.types.generated_poc.media_buy.get_products_response.Extensions] | None
var filter_diagnostics : adcp.types.generated_poc.media_buy.get_products_response.FilterDiagnostics | None
var incomplete : list[adcp.types.generated_poc.media_buy.get_products_response.IncompleteItem] | None
var model_config
var pagination : adcp.types.generated_poc.core.pagination_response.PaginationResponse | None
var pricing_version : str | None
var products : list[adcp.types.generated_poc.core.product.Product] | None
var property_list_applied : bool | None
var proposals : list[adcp.types.generated_poc.core.proposal.Proposal] | None
var refinement_applied : list[adcp.types.generated_poc.media_buy.get_products_response.RefinementApplied] | None
var sandbox : bool | None
var status : adcp.types.generated_poc.enums.task_status.TaskStatus | None
var unchanged : Literal[True] | None
var wholesale_feed_version : str | None

Inherited members

class GetProductsSubmittedResponse (**data: Any)
Expand source code
class GetProductsSubmitted(AdCPBaseModel):
    model_config = ConfigDict(
        extra='allow',
    )
    status: Annotated[
        Literal['submitted'],
        Field(
            description='Task-level status literal. Discriminates this async envelope from the synchronous success shape, whose products array is issued in-line. See task-status.json for the full task-status enum.'
        ),
    ] = 'submitted'
    task_id: Annotated[
        str,
        Field(
            description='Task handle the buyer uses with tasks/get, and that the seller references on push-notification callbacks. The products array is issued on the completion artifact, not here. Per AdCP wire conventions this is snake_case; A2A adapters MAY surface it as taskId, but the payload field emitted by the agent is task_id.'
        ),
    ]
    message: Annotated[
        str | None,
        Field(
            description="Optional human-readable explanation of why the task is submitted — e.g., 'Custom curation queued; typical turnaround 10–30 minutes.' Plain text only. Buyers MUST treat this as untrusted seller input: escape before rendering to HTML UIs, and sanitize or isolate before passing to an LLM prompt context — a hostile seller may inject prompt-injection payloads aimed at the buyer's agent.",
            max_length=2000,
        ),
    ] = None
    estimated_completion: Annotated[
        AwareDatetime | None, Field(description='Estimated completion time for the search')
    ] = None
    errors: Annotated[
        list[error.Error] | None,
        Field(
            description='Optional advisory errors accompanying the submitted envelope. Use only for non-blocking warnings (e.g., throttled_severity advisories, governance observations). Terminal failures belong in the error branch, not here.'
        ),
    ] = None
    context: context_1.ContextObject | None = None
    ext: ext_1.ExtensionObject | None = None

Base model for AdCP types with spec-compliant serialization.

Defaults to extra='ignore' so unknown fields from newer spec versions are silently dropped rather than causing validation errors. Generated types whose schemas set additionalProperties: true override this with extra='allow' in their own model_config.

Set ADCP_STRICT_VALIDATION=1 in the environment ("1", "true", "yes", "on" are accepted) to flip the default to extra='forbid'. Use this during spec upgrades to catch silently-dropped renamed fields in tests. See :func:_resolve_extra_policy.

Important

The env var is resolved once at module import time. Set it in your shell or CI environment before import adcp runs — mutating os.environ["ADCP_STRICT_VALIDATION"] after the first adcp import has no effect on already-imported model classes (they captured the policy at class-body evaluation).

Consumers who want per-model strict validation can override model_config on their subclass.

Create a new model by parsing and validating input data from keyword arguments.

Raises [ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.

self is explicitly positional-only to allow self as a field name.

Ancestors

Class variables

var context : adcp.types.generated_poc.core.context.ContextObject | None
var errors : list[adcp.types.generated_poc.core.error.Error] | None
var estimated_completion : pydantic.types.AwareDatetime | None
var ext : adcp.types.generated_poc.core.ext.ExtensionObject | None
var message : str | None
var model_config
var status : Literal['submitted']
var task_id : str

Inherited members

class GetProductsWorkingResponse (**data: Any)
Expand source code
class GetProductsWorking(AdCPBaseModel):
    model_config = ConfigDict(
        extra='allow',
    )
    percentage: Annotated[
        float | None,
        Field(description='Progress percentage of the search operation', ge=0.0, le=100.0),
    ] = None
    current_step: Annotated[
        str | None,
        Field(
            description="Current step in the search process (e.g., 'searching_inventory', 'validating_availability')"
        ),
    ] = None
    total_steps: Annotated[
        int | None, Field(description='Total number of steps in the search process')
    ] = None
    step_number: Annotated[int | None, Field(description='Current step number (1-indexed)')] = None
    context: context_1.ContextObject | None = None
    ext: ext_1.ExtensionObject | None = None

Base model for AdCP types with spec-compliant serialization.

Defaults to extra='ignore' so unknown fields from newer spec versions are silently dropped rather than causing validation errors. Generated types whose schemas set additionalProperties: true override this with extra='allow' in their own model_config.

Set ADCP_STRICT_VALIDATION=1 in the environment ("1", "true", "yes", "on" are accepted) to flip the default to extra='forbid'. Use this during spec upgrades to catch silently-dropped renamed fields in tests. See :func:_resolve_extra_policy.

Important

The env var is resolved once at module import time. Set it in your shell or CI environment before import adcp runs — mutating os.environ["ADCP_STRICT_VALIDATION"] after the first adcp import has no effect on already-imported model classes (they captured the policy at class-body evaluation).

Consumers who want per-model strict validation can override model_config on their subclass.

Create a new model by parsing and validating input data from keyword arguments.

Raises [ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.

self is explicitly positional-only to allow self as a field name.

Ancestors

Class variables

var context : adcp.types.generated_poc.core.context.ContextObject | None
var current_step : str | None
var ext : adcp.types.generated_poc.core.ext.ExtensionObject | None
var model_config
var percentage : float | None
var step_number : int | None
var total_steps : int | None

Inherited members

class GetRightsRequest (**data: Any)
Expand source code
class GetRightsRequest(AdcpVersionEnvelope):
    model_config = ConfigDict(
        extra='allow',
    )
    query: Annotated[
        str,
        Field(
            description='Natural language description of desired rights. The agent interprets intent, budget signals, and compatibility from this text.',
            max_length=2000,
        ),
    ]
    uses: Annotated[
        list[right_use.RightUse],
        Field(
            description='Rights uses being requested. The agent returns options covering these uses, potentially bundled into composite pricing.',
            min_length=1,
        ),
    ]
    buyer_brand: Annotated[
        brand_ref.BrandReference | None,
        Field(
            description="The buyer's brand. The agent fetches the buyer's brand.json for compatibility filtering (e.g., dietary conflicts, competitor exclusions)."
        ),
    ] = None
    countries: Annotated[
        list[Country] | None,
        Field(
            description='Countries where rights are needed (ISO 3166-1 alpha-2). Filters to rights available in these markets.'
        ),
    ] = None
    brand_id: Annotated[
        str | None,
        Field(
            description="Search within a specific brand's rights. If omitted, searches across the agent's full roster."
        ),
    ] = None
    right_type: Annotated[
        right_type_1.RightType | None,
        Field(description='Filter by type of rights (talent, music, stock_media, etc.)'),
    ] = None
    include_excluded: Annotated[
        bool | None,
        Field(
            description='Include filtered-out results in the excluded array with reasons. Defaults to false.'
        ),
    ] = False
    pagination: Annotated[
        pagination_request.PaginationRequest | None,
        Field(description='Pagination parameters for large result sets'),
    ] = None
    context: context_1.ContextObject | None = None
    ext: ext_1.ExtensionObject | None = None

Base model for AdCP types with spec-compliant serialization.

Defaults to extra='ignore' so unknown fields from newer spec versions are silently dropped rather than causing validation errors. Generated types whose schemas set additionalProperties: true override this with extra='allow' in their own model_config.

Set ADCP_STRICT_VALIDATION=1 in the environment ("1", "true", "yes", "on" are accepted) to flip the default to extra='forbid'. Use this during spec upgrades to catch silently-dropped renamed fields in tests. See :func:_resolve_extra_policy.

Important

The env var is resolved once at module import time. Set it in your shell or CI environment before import adcp runs — mutating os.environ["ADCP_STRICT_VALIDATION"] after the first adcp import has no effect on already-imported model classes (they captured the policy at class-body evaluation).

Consumers who want per-model strict validation can override model_config on their subclass.

Create a new model by parsing and validating input data from keyword arguments.

Raises [ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.

self is explicitly positional-only to allow self as a field name.

Ancestors

  • adcp.types.generated_poc.core.version_envelope.AdcpVersionEnvelope
  • AdCPBaseModel
  • pydantic.main.BaseModel

Class variables

var brand_id : str | None
var buyer_brand : adcp.types.generated_poc.core.brand_ref.BrandReference | None
var context : adcp.types.generated_poc.core.context.ContextObject | None
var countries : list[adcp.types.generated_poc.brand.get_rights_request.Country] | None
var ext : adcp.types.generated_poc.core.ext.ExtensionObject | None
var include_excluded : bool | None
var model_config
var pagination : adcp.types.generated_poc.core.pagination_request.PaginationRequest | None
var query : str
var right_type : adcp.types.generated_poc.enums.right_type.RightType | None
var uses : list[adcp.types.generated_poc.enums.right_use.RightUse]

Inherited members

class PackageRequest (**data: Any)
Expand source code
class PackageRequest(AdcpVersionEnvelope):
    model_config = ConfigDict(
        extra='allow',
    )
    product_id: Annotated[
        str,
        Field(
            description='Product ID for this package. Sellers MUST echo this value on every response package object that represents this requested package.'
        ),
    ]
    format_ids: Annotated[
        list[format_id.FormatReferenceStructuredObject] | None,
        Field(
            description="Legacy named-format selector. Array of format IDs that will be used for this package - must be supported by the product. If omitted (and no 3.1+ format-option selector or direct canonical selector is present), defaults to all formats supported by the product.\n\nSellers comparing this selector to a product's `format_options[]` MUST first normalize each legacy `format_id` through the canonical mapping path (`canonical`, `v1_format_ref`, or registry projection). Exact `(agent_url, id)` comparison after projection is insufficient: a legacy fixed-size display ID can satisfy a canonical `image` product declaration with matching `width`/`height`. Product gating remains directional: if the product declares fixed dimensions or duration, the selected format must declare and match those constraints; an under-specified canonical request is not a wildcard for a fixed-size or fixed-duration product. Range constraints use containment, not overlap: a range-based request satisfies the product only when every value it permits falls within the product's accepted range.",
            min_length=1,
        ),
    ] = None
    format_option_refs: Annotated[
        list[format_option_ref.FormatOptionReference] | None,
        Field(
            description='3.1+ format-option selector. Array of structured format option references, each matching one of the target product\'s `format_options[]` entries. Publisher-catalog-backed options match by `{ scope: "publisher", publisher_domain, format_option_id }`; product-local options match by `{ scope: "product", format_option_id }`. If omitted along with `format_ids` and direct `format_kind`, all product formats are active.\n\n**Resolution rules (normative).**\n- **Both `format_option_refs` and `format_ids` present.** `format_option_refs` wins; the seller routes by structured references and MUST NOT validate `format_ids` for consistency with the resolved declarations. The `format_ids` value is a legacy-compat hint for intermediaries on the wire path; the resolving seller ignores it.\n- **`format_option_refs` only.** Seller looks up each entry against the package\'s target product `format_options[]` and uses the matching declaration (and that declaration\'s `v1_format_ref[]` when projecting to legacy named-format surfaces). This is the 3.1+ format-option authoring path. `scope: "product"` is scoped only by this target product; it is not a seller-wide identifier.\n- **`format_ids` only.** Existing named-format behavior; unchanged.\n- **`format_kind` only.** Direct canonical selector behavior; seller compares `{ format_kind, params }` against the product\'s `format_options[]` declarations using directional product satisfaction.\n- **None of `format_option_refs`, `format_ids`, or `format_kind`.** Default — all formats supported by the product are active.\n\n**Failure modes (normative).** Sellers MUST reject with `UNSUPPORTED_FEATURE` (with `field` pointing at the failing package and entry, e.g. `packages[0].format_option_refs[1]`) when:\n- Any entry references a format option not present in the target product\'s `format_options[]`, OR\n- The target product carries `format_ids` but no `format_options[]` (legacy-format-only product — there is no closed set to resolve against), OR\n- The target product carries `format_options[]` but none of the entries publish selectable `format_option_id` values. Sellers SHOULD set `error.details.reason` to `format_option_refs_not_published` in this case so buyers can distinguish it from an outright mismatch and fall back to `format_ids[]`.\n\n**Seller obligation.** For buyers to use the 3.1+ format-option path against a product, the seller MUST publish a selectable `format_option_id` on each `format_options[]` entry it expects buyers to select; if the option is publisher-catalog backed, include `publisher_domain` on the product declaration and require buyers to use `scope: "publisher"` in `FormatOptionRef`.\n\n**No legacy capability selector.** `capability_ids` was removed before GA; schemas reject it instead of treating it as an extension.\n\n**Dual emission.** Format-option-aware buyer SDKs targeting a heterogeneous seller population SHOULD emit `format_ids` alongside `format_option_refs` so legacy-format-only sellers — which ignore unknown fields per `additionalProperties: true` — still receive an explicit format set rather than silently defaulting to all formats supported by the product.',
            min_length=1,
        ),
    ] = None
    format_kind: Annotated[
        canonical_format_kind.CanonicalFormatKind | None,
        Field(
            description='3.1+ direct canonical selector. Names the canonical format shape this package targets when the buyer is authoring by canonical kind rather than by a product-local `format_option_ref` or legacy `format_id`. Pair with `params` when the product declaration requires dimensions, duration, sizes, codecs, or other canonical parameters. If `format_option_refs` is present, it wins over this direct selector. If `format_ids` is present without `format_option_refs`, sellers MUST normalize and validate the legacy selector; buyers SHOULD NOT also send `format_kind` unless it is an informational echo of the same normalized shape.\n\nProduct satisfaction is directional: a broad selector such as `{ format_kind: "image" }` does not satisfy a product whose `format_options[]` fixes `params.width` and `params.height`. Sellers MUST reject under-specified direct selectors with `UNSUPPORTED_FEATURE` or an equivalent format-selector validation error.'
        ),
    ] = None
    params: Annotated[
        dict[str, Any] | None,
        Field(
            description="Parameters for the direct canonical selector in `format_kind`. Shape follows the selected canonical's parameter vocabulary: dimensions (`width`, `height`, `sizes`), duration (`duration_ms_exact`, `duration_ms_range`), codecs, asset-source and slot narrowing, or other canonical-specific constraints. Omit when selecting by `format_option_refs` or `format_ids`; those selectors resolve their parameters from the product declaration or legacy catalog projection."
        ),
    ] = None
    budget: Annotated[
        float,
        Field(description="Budget allocation for this package in the media buy's currency", ge=0.0),
    ]
    pacing: pacing_1.Pacing | None = None
    pricing_option_id: Annotated[
        str,
        Field(
            description="ID of the selected pricing option from the product's pricing_options array"
        ),
    ]
    bid_price: Annotated[
        float | None,
        Field(
            description="Bid price for auction-based pricing options. This is the exact bid/price to honor unless selected pricing_option has max_bid=true, in which case bid_price is the buyer's maximum willingness to pay (ceiling).",
            ge=0.0,
        ),
    ] = None
    impressions: Annotated[
        float | None, Field(description='Impression goal for this package', ge=0.0)
    ] = None
    start_time: Annotated[
        AwareDatetime | None,
        Field(
            description="Flight start date/time for this package in ISO 8601 format. When omitted, the package inherits the media buy's start_time. Must fall within the media buy's date range."
        ),
    ] = None
    end_time: Annotated[
        AwareDatetime | None,
        Field(
            description="Flight end date/time for this package in ISO 8601 format. When omitted, the package inherits the media buy's end_time. Must fall within the media buy's date range."
        ),
    ] = None
    paused: Annotated[
        bool | None,
        Field(
            description='Whether this package should be created in a paused state. Paused packages do not deliver impressions. Defaults to false.'
        ),
    ] = False
    catalogs: Annotated[
        list[catalog.Catalog] | None,
        Field(
            description='Catalogs this package promotes. Each catalog MUST have a distinct type (e.g., one product catalog, one store catalog). This constraint is enforced at the application level — sellers MUST reject requests containing multiple catalogs of the same type with a validation_error. Makes the package catalog-driven: one budget envelope, platform optimizes across items.'
        ),
    ] = None
    optimization_goals: Annotated[
        list[optimization_goal.OptimizationGoal] | None,
        Field(
            description='Optimization targets for this package. The seller optimizes delivery toward these goals in priority order. Common pattern: event goals (purchase, install) as primary targets at priority 1; metric goals (clicks, views) as secondary proxy signals at priority 2+.',
            min_length=1,
        ),
    ] = None
    targeting_overlay: targeting.TargetingOverlay | None = None
    measurement_terms: Annotated[
        measurement_terms_1.MeasurementTerms | None,
        Field(
            description="Buyer's proposed billing measurement and makegood terms. Overrides product defaults. Seller accepts (echoed on confirmed package), rejects with TERMS_REJECTED, or adjusts. When absent, product's measurement_terms apply."
        ),
    ] = None
    performance_standards: Annotated[
        list[performance_standard.PerformanceStandard] | None,
        Field(
            description="Buyer's proposed performance standards for this package. Overrides product defaults. Seller accepts, rejects with TERMS_REJECTED, or adjusts. When absent, product's performance_standards apply.",
            min_length=1,
        ),
    ] = None
    committed_metrics: Annotated[
        list[CommittedMetrics6] | None,
        Field(
            description="Buyer's proposed reporting contract for this package — the metrics the buyer wants the seller to commit to populating in delivery reports. Same negotiation pattern as `measurement_terms` and `performance_standards`: seller accepts (echoes on confirmed package with `committed_at` stamped), rejects with `TERMS_REJECTED` (with explanation of which entries were unworkable), or normalizes (echoes a different but compatible list — buyer can accept by retrying with the normalized terms). When absent, the seller decides what to commit based on the product's `available_metrics` and the buyer's `required_metrics` filter on `get_products`. Each entry uses an explicit `scope` discriminator (`standard` or `vendor`) and identifies the metric — request-side entries do NOT carry `committed_at`; that timestamp is stamped by the seller on accept. Constraints on what the buyer MAY propose: each `scope: standard` entry's `metric_id` MUST be in the product's `available_metrics`, and each `scope: vendor` entry's `(vendor, metric_id)` MUST appear in the product's `vendor_metrics` — sellers SHOULD reject with `TERMS_REJECTED` and reference the offending entry when the proposal exceeds product capability.",
            min_length=1,
        ),
    ] = None
    creative_assignments: Annotated[
        list[creative_assignment.CreativeAssignment] | None,
        Field(
            description='Assign existing library creatives to this package with optional weights and placement targeting',
            min_length=1,
        ),
    ] = None
    creatives: Annotated[
        Sequence[creative_asset.CreativeAsset] | None,
        Field(
            description="Upload creative assets inline and assign to this package. When the seller also advertises creative.has_creative_library: true, these creatives enter the seller's creative library and can be reused by creative_id while retained; inline-only sellers may store them as package-scoped assets. Use creative_assignments instead for existing library creatives.",
            max_length=100,
            min_length=1,
        ),
    ] = None
    agency_estimate_number: Annotated[
        str | None,
        Field(
            description='Agency estimate or authorization number for this package. Overrides the media buy-level estimate number when different packages correspond to different agency estimates (e.g., different stations or flights within the same buy).',
            max_length=100,
        ),
    ] = None
    context: Annotated[
        context_1.ContextObject | None,
        Field(
            description='Opaque package-level correlation data echoed unchanged in the package response, webhooks, and read surfaces. Buyers targeting mixed seller populations SHOULD include a per-package correlation value here, commonly context_1.buyer_ref, so responses from legacy sellers that do not echo product_id can still be mapped back to the requested product or line item. Do not use deprecated top-level buyer_ref for v3 correlation.'
        ),
    ] = None
    ext: ext_1.ExtensionObject | None = None

Base model for AdCP types with spec-compliant serialization.

Defaults to extra='ignore' so unknown fields from newer spec versions are silently dropped rather than causing validation errors. Generated types whose schemas set additionalProperties: true override this with extra='allow' in their own model_config.

Set ADCP_STRICT_VALIDATION=1 in the environment ("1", "true", "yes", "on" are accepted) to flip the default to extra='forbid'. Use this during spec upgrades to catch silently-dropped renamed fields in tests. See :func:_resolve_extra_policy.

Important

The env var is resolved once at module import time. Set it in your shell or CI environment before import adcp runs — mutating os.environ["ADCP_STRICT_VALIDATION"] after the first adcp import has no effect on already-imported model classes (they captured the policy at class-body evaluation).

Consumers who want per-model strict validation can override model_config on their subclass.

Create a new model by parsing and validating input data from keyword arguments.

Raises [ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.

self is explicitly positional-only to allow self as a field name.

Ancestors

  • adcp.types.generated_poc.core.version_envelope.AdcpVersionEnvelope
  • AdCPBaseModel
  • pydantic.main.BaseModel

Class variables

var agency_estimate_number : str | None
var bid_price : float | None
var budget : float
var catalogs : list[adcp.types.generated_poc.core.catalog.Catalog] | None
var committed_metrics : list[adcp.types.generated_poc.media_buy.package_request.CommittedMetrics6] | None
var context : adcp.types.generated_poc.core.context.ContextObject | None
var creative_assignments : list[adcp.types.generated_poc.core.creative_assignment.CreativeAssignment] | None
var creatives : collections.abc.Sequence[adcp.types.generated_poc.core.creative_asset.CreativeAsset] | None
var end_time : pydantic.types.AwareDatetime | None
var ext : adcp.types.generated_poc.core.ext.ExtensionObject | None
var format_ids : list[adcp.types.generated_poc.core.format_id.FormatReferenceStructuredObject] | None
var format_kind : adcp.types.generated_poc.core.canonical_format_kind.CanonicalFormatKind | None
var format_option_refs : list[adcp.types.generated_poc.core.format_option_ref.FormatOptionReference] | None
var impressions : float | None
var measurement_terms : adcp.types.generated_poc.core.measurement_terms.MeasurementTerms | None
var model_config
var optimization_goals : list[adcp.types.generated_poc.core.optimization_goal.OptimizationGoal] | None
var pacing : adcp.types.generated_poc.enums.pacing.Pacing | None
var params : dict[str, typing.Any] | None
var paused : bool | None
var performance_standards : list[adcp.types.generated_poc.core.performance_standard.PerformanceStandard] | None
var pricing_option_id : str
var product_id : str
var start_time : pydantic.types.AwareDatetime | None
var targeting_overlay : adcp.types.generated_poc.core.targeting.TargetingOverlay | None

Inherited members

class PerformanceFeedback (**data: Any)
Expand source code
class PerformanceFeedback(AdCPBaseModel):
    model_config = ConfigDict(
        extra='allow',
    )
    feedback_id: Annotated[
        str, Field(description='Unique identifier for this performance feedback submission')
    ]
    media_buy_id: Annotated[str, Field(description="Publisher's media buy identifier")]
    package_id: Annotated[
        str | None,
        Field(
            description='Specific package within the media buy (if feedback is package-specific)'
        ),
    ] = None
    creative_id: Annotated[
        str | None, Field(description='Specific creative asset (if feedback is creative-specific)')
    ] = None
    measurement_period: Annotated[
        MeasurementPeriod, Field(description='Time period for performance measurement')
    ]
    performance_index: Annotated[
        float,
        Field(
            description='Normalized performance score (0.0 = no value, 1.0 = expected, >1.0 = above expected)',
            ge=0.0,
        ),
    ]
    metric_type: Annotated[
        metric_type_1.MetricTypeDeprecated | None,
        Field(
            description='**Deprecated as of this minor.** The legacy free-form metric enum that mixes metrics, verification, and attribution into one list. New implementations SHOULD use `metric` (the discriminated `(scope, metric_id, qualifier)` row shape) and populate `metric_type` with a best-effort string for one-minor backwards compatibility. When both `metric` and `metric_type` are present, consumers MUST use `metric` for dispatch. Removed at the next major. See [docs/measurement/taxonomy](https://docs.adcontextprotocol.org/docs/measurement/taxonomy) for why the layered shape replaces the flat enum.'
        ),
    ] = None
    metric: Annotated[
        Metric | Metric7 | None,
        Field(
            description='The metric this feedback row pertains to, using the same `(scope, metric_id, qualifier)` row shape as `committed_metrics` and `metric_aggregates`. Preferred over the legacy `metric_type` field for new implementations. Brings performance-feedback into the same atomic unit and dispatch model as the rest of the measurement surface — buyer agents reconcile feedback against the contract surface using the row-level join on `(scope, metric_id, qualifier)`. **Optional and may be omitted entirely for holistic feedback** (e.g., a trader flagging a campaign as underperforming without a specific metric in mind — `performance_index` plus the response narrative carry the signal). Senders SHOULD populate `metric` when the feedback is metric-specific so consumers can route it to the right optimization path; senders MAY omit it for general performance feedback.',
            discriminator='scope',
        ),
    ] = None
    feedback_source: Annotated[
        feedback_source_1.FeedbackSource, Field(description='Source of the performance data')
    ]
    vendor: Annotated[
        brand_ref.BrandReference | None,
        Field(
            description="Vendor that produced this feedback. SHOULD be populated when `feedback_source` is `third_party_measurement` or `verification_partner` AND a single attesting vendor exists — without it, the row is unattributed and consumers can't verify authorization, resolve metric definitions, or route disputes. OMIT for blended outputs where no single vendor owns the result: MMM mixes (Nielsen MMM, Analytic Partners, in-house mix models combining multiple vendor inputs), multi-touch attribution outputs that join across vendors, and clean-room outputs (LiveRamp, Habu, AWS Clean Rooms) where the clean room is not the measurement source. For these cases, leave `vendor` absent and use the response's narrative payload to describe provenance. Optional for `buyer_attribution` and `platform_analytics` (those sources are implicit from context). The vendor's `brand.json` `agents[type='measurement']` is the discovery anchor; metric definitions live on the agent's `get_adcp_capabilities.measurement.metrics[]` block. Same identity discipline as `vendor_metric_value.vendor` and `performance-standard.vendor`."
        ),
    ] = None
    status: Annotated[Status, Field(description='Processing status of the performance feedback')]
    submitted_at: Annotated[
        AwareDatetime, Field(description='ISO 8601 timestamp when feedback was submitted')
    ]
    applied_at: Annotated[
        AwareDatetime | None,
        Field(
            description='ISO 8601 timestamp when feedback was applied to optimization algorithms'
        ),
    ] = None

Base model for AdCP types with spec-compliant serialization.

Defaults to extra='ignore' so unknown fields from newer spec versions are silently dropped rather than causing validation errors. Generated types whose schemas set additionalProperties: true override this with extra='allow' in their own model_config.

Set ADCP_STRICT_VALIDATION=1 in the environment ("1", "true", "yes", "on" are accepted) to flip the default to extra='forbid'. Use this during spec upgrades to catch silently-dropped renamed fields in tests. See :func:_resolve_extra_policy.

Important

The env var is resolved once at module import time. Set it in your shell or CI environment before import adcp runs — mutating os.environ["ADCP_STRICT_VALIDATION"] after the first adcp import has no effect on already-imported model classes (they captured the policy at class-body evaluation).

Consumers who want per-model strict validation can override model_config on their subclass.

Create a new model by parsing and validating input data from keyword arguments.

Raises [ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.

self is explicitly positional-only to allow self as a field name.

Ancestors

Class variables

var applied_at : pydantic.types.AwareDatetime | None
var creative_id : str | None
var feedback_id : str
var feedback_source : adcp.types.generated_poc.enums.feedback_source.FeedbackSource
var measurement_period : adcp.types.generated_poc.core.performance_feedback.MeasurementPeriod
var media_buy_id : str
var metric : adcp.types.generated_poc.core.performance_feedback.Metric | adcp.types.generated_poc.core.performance_feedback.Metric7 | None
var metric_type : adcp.types.generated_poc.enums.metric_type.MetricTypeDeprecated | None
var model_config
var package_id : str | None
var performance_index : float
var status : adcp.types.generated_poc.core.performance_feedback.Status
var submitted_at : pydantic.types.AwareDatetime
var vendor : adcp.types.generated_poc.core.brand_ref.BrandReference | None

Inherited members

class PriceGuidance (**data: Any)
Expand source code
class PriceGuidance(AdCPBaseModel):
    model_config = ConfigDict(
        extra='allow',
    )
    p25: Annotated[
        float | None, Field(description='25th percentile of recent winning bids', ge=0.0)
    ] = None
    p50: Annotated[float | None, Field(description='Median of recent winning bids', ge=0.0)] = None
    p75: Annotated[
        float | None, Field(description='75th percentile of recent winning bids', ge=0.0)
    ] = None
    p90: Annotated[
        float | None, Field(description='90th percentile of recent winning bids', ge=0.0)
    ] = None

Base model for AdCP types with spec-compliant serialization.

Defaults to extra='ignore' so unknown fields from newer spec versions are silently dropped rather than causing validation errors. Generated types whose schemas set additionalProperties: true override this with extra='allow' in their own model_config.

Set ADCP_STRICT_VALIDATION=1 in the environment ("1", "true", "yes", "on" are accepted) to flip the default to extra='forbid'. Use this during spec upgrades to catch silently-dropped renamed fields in tests. See :func:_resolve_extra_policy.

Important

The env var is resolved once at module import time. Set it in your shell or CI environment before import adcp runs — mutating os.environ["ADCP_STRICT_VALIDATION"] after the first adcp import has no effect on already-imported model classes (they captured the policy at class-body evaluation).

Consumers who want per-model strict validation can override model_config on their subclass.

Create a new model by parsing and validating input data from keyword arguments.

Raises [ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.

self is explicitly positional-only to allow self as a field name.

Ancestors

Class variables

var model_config
var p25 : float | None
var p50 : float | None
var p75 : float | None
var p90 : float | None

Inherited members

class PricingCurrency (root: RootModelRootType = PydanticUndefined, **data)
Expand source code
class PricingCurrency(RootModel[str]):
    root: Annotated[
        str,
        Field(
            description="ISO 4217 currency code (e.g., 'USD', 'EUR', 'GBP')", pattern='^[A-Z]{3}$'
        ),
    ]

Usage Documentation

RootModel and Custom Root Types

A Pydantic BaseModel for the root object of the model.

Attributes

root
The root object of the model.
__pydantic_root_model__
Whether the model is a RootModel.
__pydantic_private__
Private fields in the model.
__pydantic_extra__
Extra fields in the model.

Create a new model by parsing and validating input data from keyword arguments.

Raises [ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.

self is explicitly positional-only to allow self as a field name.

Ancestors

  • pydantic.root_model.RootModel[str]
  • pydantic.root_model.RootModel
  • pydantic.main.BaseModel
  • typing.Generic

Class variables

var model_config
var root : str
class PricingModel (*args, **kwds)
Expand source code
class PricingModel(StrEnum):
    cpm = 'cpm'
    vcpm = 'vcpm'
    cpc = 'cpc'
    cpcv = 'cpcv'
    cpv = 'cpv'
    cpp = 'cpp'
    cpa = 'cpa'
    flat_rate = 'flat_rate'
    time = 'time'

Enum where members are also (and must be) strings

Ancestors

  • enum.StrEnum
  • builtins.str
  • enum.ReprEnum
  • enum.Enum

Class variables

var cpa
var cpc
var cpcv
var cpm
var cpp
var cpv
var flat_rate
var time
var vcpm
class Product (**data: Any)
Expand source code
class Product(AdCPBaseModel):
    model_config = ConfigDict(
        extra='allow',
    )


    @model_validator(mode='before')
    @classmethod
    def _coerce_publisher_property_models(cls, data: Any) -> Any:
        if isinstance(data, dict) and isinstance(data.get('publisher_properties'), list):
            coerced = []
            changed = False
            for item in data['publisher_properties']:
                if hasattr(item, 'model_dump'):
                    coerced.append(item.model_dump(mode='json', exclude_none=True))
                    changed = True
                else:
                    coerced.append(item)
            if changed:
                data = dict(data)
                data['publisher_properties'] = coerced
        return data
    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')
    ]
    publisher_properties: Annotated[
        list[PublisherProperty],
        Field(
            description="SDK implementers MUST enforce singular-only at runtime: each entry uses the singular `publisher_domain` form; the compact `publisher_domains[]` form is rejected on products. Codegen toolchains (json-schema-to-typescript, quicktype, datamodel-code-generator, openapi-typescript-codegen) often flatten the `allOf + $ref + not.required` restriction below poorly and may drop the rejection constraint silently, emitting an unrestricted type — runtime enforcement is the safety net. Publisher properties covered by this product. Buyers fetch actual property definitions from each publisher's adagents.json and validate agent authorization. Selection patterns mirror the authorization patterns in adagents.json for consistency. The compact `publisher_domains[]` form is reserved for adagents.json `authorized_agents[].publisher_properties[]` so that buy-side traffic-and-pricing flatteners can always treat each entry as exactly one publisher.",
            min_length=1,
        ),
    ]
    channels: Annotated[
        list[channels_1.MediaChannel] | None,
        Field(
            description="Advertising channels this product is sold as. Products inherit from their properties' supported_channels but may narrow the scope. For example, a product covering YouTube properties might be sold as ['ctv'] even though those properties support ['olv', 'social', 'ctv']."
        ),
    ] = None
    format_ids: Annotated[
        list[format_id.FormatReferenceStructuredObject] | None,
        Field(
            description="Legacy named-format path: array of supported creative format IDs (structured format_id objects with agent_url and id). Products MUST carry `format_ids`, `format_options`, or BOTH; at least one is required. Named formats predate 3.1 and remain supported through the deprecation calendar (2027-Q4 floor / 2029-Q1 ceiling).\n\n**Dual emission**: A product MAY carry both `format_ids` and `format_options` simultaneously during the migration window. This is the recommended seller pattern — author once, SDK projects to both wire shapes via the [canonical mapping registry](/schemas/registries/v1-canonical-mapping.json), every buyer reads what it knows. When both are present, the two MUST refer to the SAME underlying format declaration (the `format_options[i]` narrows the canonical that the named format in `format_ids[i]` resolves to via the registry / explicit `canonical` field). SDKs that derive both shapes from one source guarantee this invariant; SDKs that don't MUST treat divergence as a build error and refuse to emit. **Buyer rule**: when both are present, prefer `format_options`; treat `format_ids` as fallback for legacy-format buyers. **Non-projectable formats**: when a named format has no clean 3.1+ format-option projection (no registry entry, no explicit `canonical` declaration on the named format, no structural match), SDKs MUST NOT emit `format_options` for that product — only `format_ids` ships, and the product remains legacy-format-only until the seller adds an explicit `canonical` field or files a registry entry."
        ),
    ] = None
    format_options: Annotated[
        list[product_format_declaration.ProductFormatDeclaration] | None,
        Field(
            description="3.1+ format-option path: one or more inline format declarations the product accepts. Each element narrows a canonical format with parameters, slots, and platform_extensions. The 90% case is a single-element array (one canonical narrowed for the product). Multi-element use cases: a product that accepts EITHER a third-party-hosted creative (for example, externally served `html5`) OR an internal `display_tag`; a video product that accepts a hosted `video_hosted` upload OR a `video_vast` tag. Buyers pick which option they're shipping at `sync_creatives` time by aligning their manifest to the matching declaration's `format_kind` and slots.\n\nProducts MUST carry `format_ids`, `format_options`, or BOTH; at least one is required. See `format_ids` description for the dual-emission contract (same underlying declaration when both are present; SDK derives one from the other; buyers prefer `format_options` when both are present).\n\nWhen `placements[]` also declare `format_ids` or `format_options`, product-level formats are the upper bound for the sellable product. Placement-level formats narrow the product-wide accepted set for that placement; they MUST NOT introduce a format the product does not accept. Buyers compute the effective accepted set for a placement as the intersection of product-level and placement-level declarations. For format options, match publisher-declared options by `{ publisher_domain, format_option_id }`, match product-local options by `format_option_id` when `publisher_domain` is omitted, and otherwise match declarations with the same `format_kind` whose placement parameters narrow the product declaration. If a placement has no format declaration, it inherits the product-level formats.",
            min_length=1,
        ),
    ] = None
    placements: Annotated[
        list[placement.Placement] | None,
        Field(
            description="Optional array of specific public placements within this product. Placement IDs are scoped by publisher domain. Product placements declare `kind` to distinguish publisher-referenced placements (`publisher_ref`) from seller-defined inline placements (`seller_inline`). Publisher-referenced placements carry `publisher_domain` plus `placement_id` and may omit `name` because buyers resolve the name from the publisher's adagents.json placement declarations. Seller-inline placements carry buyer-facing `name` directly; when `publisher_domain` is omitted, buyers MAY interpret the placement ID relative to the seller agent's own publisher domain only during the legacy single-publisher transition. Community-maintained fallback files are resolver/source metadata, not a distinct placement kind. Each placement MUST declare `mode: 'targetable'` (buyer may select the placement by PlacementRef, for example in creative assignments) or `mode: 'included'` (part of the public product composition but not buyer-selectable). Placement-level format declarations narrow the product-level creative contract and MUST NOT broaden it. Seller-private delivery objects, source/origin details, and ad-server mappings MUST NOT be exposed here.",
            min_length=1,
        ),
    ] = None
    video_placement_types: Annotated[
        list[video_placement_type.VideoPlacementType] | None,
        Field(
            description='Declared video placement types that may be included in this product, using IAB Tech Lab/OpenRTB 2.6 video.plcmt definitions with AdCP-native names. Use on OLV, CTV, and other video products when buyers need to distinguish instream, accompanying-content, interstitial, and standalone/no-content inventory. Aggregate products and ad-network products MAY declare multiple values. When `placements[]` also carry `video_placement_types`, this product-level array SHOULD be the union of the placement-level declarations the seller may deliver under the product. This is seller-declared discovery metadata, not independent verification of inventory quality or delivery context.',
            min_length=1,
        ),
    ] = None
    audio_distribution_types: Annotated[
        list[audio_distribution_type.AudioDistributionType] | None,
        Field(
            description='Declared audio distribution types that may be included in this product, using IAB Tech Lab/OpenRTB 2.6 audio.feed definitions with AdCP-native names. Use on radio, streaming-audio, podcast, gaming, and other audio products when buyers need to distinguish music streaming services, FM/AM broadcast, podcasts, catch-up radio, web radio, video-game audio, and text-to-speech inventory without changing the buyer-facing channel or adagents.json property type. Aggregate products and ad-network products MAY declare multiple values. When `placements[]` also carry `audio_distribution_types`, this product-level array SHOULD be the union of the placement-level declarations the seller may deliver under the product. This is seller-declared discovery metadata, not independent verification of inventory quality or delivery context.',
            min_length=1,
        ),
    ] = None
    sponsored_placement_types: Annotated[
        list[sponsored_placement_type.SponsoredPlacementType] | None,
        Field(
            description='Declared sponsored-placement types that may be included in this product, distinguishing where catalog-driven retail-media placements render on the retailer surface (sponsored search, sponsored display, or sponsored native). Use on retail-media products when buyers need to distinguish search-keyed, display, and native in-grid sponsored inventory. Aggregate products and ad-network products MAY declare multiple values. When `placements[]` also carry `sponsored_placement_types`, this product-level array SHOULD be the union of the placement-level declarations the seller may deliver under the product. This is seller-declared discovery metadata, not independent verification of inventory quality or delivery context.',
            min_length=1,
        ),
    ] = None
    social_placement_surfaces: Annotated[
        list[social_placement_surface.SocialPlacementSurface] | None,
        Field(
            description='Declared social-placement surfaces that may be included in this product, distinguishing the in-app surface where social placements render (feed, stories, short_video, explore, or search). Use on social products when buyers need to distinguish feed, story, short-video, and discovery surfaces. Aggregate products and ad-network products MAY declare multiple values. When `placements[]` also carry `social_placement_surfaces`, this product-level array SHOULD be the union of the placement-level declarations the seller may deliver under the product. This is seller-declared discovery metadata, not independent verification of inventory quality or delivery context.',
            min_length=1,
        ),
    ] = None
    delivery_type: delivery_type_1.DeliveryType
    exclusivity: Annotated[
        exclusivity_1.Exclusivity | None,
        Field(
            description="Whether this product offers exclusive access to its inventory. Defaults to 'none' when absent. Most relevant for guaranteed products tied to specific collections or placements."
        ),
    ] = None
    pricing_options: Annotated[
        list[pricing_option.PricingOption],
        Field(description='Available pricing models for this product', min_length=1),
    ]
    forecast: Annotated[
        delivery_forecast.DeliveryForecast | None,
        Field(
            description='Forecasted delivery metrics for this product. Gives buyers an estimate of expected performance before requesting a proposal.'
        ),
    ] = None
    outcome_measurement: Annotated[
        outcome_measurement_1.OutcomeMeasurementDeprecated | None,
        Field(
            description='**Deprecated as of this minor.** Outcome capabilities (incremental sales lift, brand lift, foot traffic, etc.) are now declared via `reporting_capabilities.available_metrics` (the same path used for impressions, conversions, ROAS) with `qualifier.attribution_methodology` and `qualifier.attribution_window` carrying the methodology and window on commit. New implementations SHOULD use the unified pattern; this field is retained for one-minor backwards compatibility and removed at the next major. See `outcome-measurement.json` description for migration guidance.'
        ),
    ] = None
    delivery_measurement: Annotated[
        DeliveryMeasurement | None,
        Field(
            description='Measurement vendors and methodology for delivery metrics. The buyer accepts the declared vendors as the source of truth for the buy. When absent, buyers should apply their own measurement defaults. Senders SHOULD populate `vendors` (structured BrandRef array) for new implementations; the legacy `provider` string field is deprecated and retained for one-minor backwards compatibility.'
        ),
    ] = None
    measurement_terms: Annotated[
        measurement_terms_1.MeasurementTerms | None,
        Field(
            description="Seller's default billing measurement and makegood terms. Declares who counts the billing metric and what remedies apply when thresholds are breached. Buyers may propose different terms at media buy creation — sellers accept, reject (TERMS_REJECTED), or adjust per their policy."
        ),
    ] = None
    performance_standards: Annotated[
        list[performance_standard.PerformanceStandard] | None,
        Field(
            description="Seller's default performance standards for this product: viewability, IVT, completion rate, brand safety, attention score. Buyers may propose different standards at media buy creation. When absent, no structured performance standards apply.",
            min_length=1,
        ),
    ] = None
    cancellation_policy: Annotated[
        cancellation_policy_1.CancellationPolicy | None,
        Field(
            description='Cancellation terms for this product. Declares the minimum notice period required before cancellation takes effect and any penalties for insufficient notice. Relevant for guaranteed delivery products. Buyers accept these terms by creating a media buy against the product.'
        ),
    ] = None
    allowed_actions: Annotated[
        list[product_allowed_action.ProductAllowedAction] | None,
        Field(
            description='Actions buyers may perform on buys created against this product, scoped to statuses and modes. Advisory template — the authoritative per-buy capability is `available_actions[]` on the buy response, which resolves modes against current buy state, account tier, and negotiated terms. Buyers SHOULD use this for pre-flight product selection ("which products let me self-serve cancel within 72hr?") and read `available_actions[]` for runtime decisions. The array is uniquely keyed by `action` — sellers MUST NOT emit two entries with the same `action` value. Absence means the seller has not declared a structured action surface for this product — buyers fall back to `valid_actions[]` on buy responses for the flat string vocabulary.',
            min_length=1,
        ),
    ] = None
    reporting_capabilities: reporting_capabilities_1.ReportingCapabilities
    creative_policy: creative_policy_1.CreativePolicy | None = None
    is_custom: Annotated[bool | None, Field(description='Whether this is a custom product')] = None
    property_targeting_allowed: Annotated[
        bool | None,
        Field(
            description="Whether buyers can filter this product to a subset of its publisher_properties. When false (default), the product is 'all or nothing' - buyers must accept all properties or the product is excluded from property_list filtering results."
        ),
    ] = False
    data_provider_signals: Annotated[
        list[data_provider_signal_selector.DataProviderSignalSelector] | None,
        Field(
            deprecated=True,
            description='Deprecated. Legacy/non-selectable metadata for data-provider signals already bundled into or associated with this product. This field does not provide buyer-selectable options, prices, or seller activation handles. Use included_signals for non-selectable product signal metadata, or signal_targeting_options for selectable package-level signal groups.',
        ),
    ] = None
    included_signals: Annotated[
        list[signal_listing.SignalListing] | None,
        Field(
            description="Non-selectable signal metadata for signals already included in, bundled with, or planned into this product. These signals describe what the product is; buyers do not select them in packages[].targeting_overlay.signal_targeting_groups and this field does not imply package-level signal targeting. Use signal_ref scope 'data_provider' or 'signal_source' to reference externally defined signals without redefining their name or value_type. Use signal_ref scope 'product' with name and value_type when the included signal is defined only by this product.",
            min_length=1,
        ),
    ] = None
    signal_targeting_options: Annotated[
        list[product_signal_targeting_option.ProductSignalTargetingOption] | None,
        Field(
            description="Inline seller-offered signals that may be applied to packages for this product at create_media_buy time. Each entry references a named signal definition with signal_ref scope 'product' for a product-local signal option, scope 'data_provider' for an external signal definition published in adagents.json signals[] that the seller is authorized to apply, or scope 'signal_source' for a source-native signal. Product-local options define name and value_type inline; data-provider and signal-source options may omit those fields when the referenced definition or source is authoritative. Use this field when the selectable menu is product-specific, has product-specific pricing or activation handles, is the relevant subset for a brief/refine result, or should be rendered without an additional get_signals call. Wholesale products may omit this field and rely on get_signals for the selectable signal feed. Buyers select eligible signals through packages[].targeting_overlay.signal_targeting_groups when signal_targeting_rules allow; fixed/default entries are applied by the seller and echoed on the package state. Sellers MUST set signal_targeting_allowed to true whenever this field is present. Bundled, non-selectable signal metadata belongs in included_signals; legacy data_provider_signals may appear only for backwards compatibility.",
            min_length=1,
        ),
    ] = None
    signal_targeting_rules: Annotated[
        signal_targeting_rules_1.SignalTargetingRules | None,
        Field(
            description='Composition rules for selecting signals on this product. The selectable signal menu may come from inline signal_targeting_options or from get_signals when a wholesale product omits inline options. This is product-scoped because products may be backed by different ad servers with different Boolean targeting support and group limits.'
        ),
    ] = None
    signal_targeting_allowed: Annotated[
        bool | None,
        Field(
            description='Whether this product has a package-level signal_targeting_groups surface. When false (default), signals are bundled into the product terms and cannot be selected or explicitly echoed as package signal groups. When true, eligible signals from inline signal_targeting_options or from get_signals may be buyer-selected or seller-applied according to signal_targeting_rules and are represented through packages[].targeting_overlay.signal_targeting_groups. Editability is controlled by signal_targeting_rules; fixed/default-only products still set this to true when applied signal groups are echoed.'
        ),
    ] = False
    catalog_types: Annotated[
        list[catalog_type.CatalogType] | None,
        Field(
            description='Catalog types this product supports for catalog-driven campaigns. A sponsored product listing declares ["product"], a job board declares ["job", "offering"]. Buyers match synced catalogs to products via this field.',
            min_length=1,
        ),
    ] = None
    metric_optimization: Annotated[
        MetricOptimization | None,
        Field(
            description="Metric optimization capabilities for this product. Presence indicates the product supports optimization_goals with kind: 'metric'. No event source or conversion tracking setup required — the seller tracks these metrics natively."
        ),
    ] = None
    vendor_metric_optimization: Annotated[
        vendor_metric_optimization_1.VendorMetricOptimization | None,
        Field(
            description="Vendor-attested metric optimization capabilities for this product. Presence indicates the product supports `optimization_goals` with `kind: 'vendor_metric'` — the seller's bidding stack can steer delivery toward a specific vendor's measurement (e.g., DV/IAS/Adelaide attention, Scope3 emissions, Kantar brand lift, retail-media partner metrics). Distinct from `metric_optimization` (seller-native metrics with no vendor binding) and from `reporting_capabilities.vendor_metrics` (which declares what the product can *report* rather than what it can *optimize against*). A product may report a vendor metric without being able to optimize for it. Buyers MUST verify the goal's `(vendor, metric_id)` is in `supported_metrics` AND that the package's `committed_metrics[]` includes a matching `{ scope: 'vendor', vendor, metric_id }` entry — optimization without committed reporting is unverifiable and is rejected at the wire level."
        ),
    ] = None
    max_optimization_goals: Annotated[
        int | None,
        Field(
            description='Maximum number of optimization_goals this product accepts on a package. When absent, no limit is declared. Most social platforms accept only 1 goal — buyers sending arrays longer than this value should expect the seller to use only the highest-priority (lowest priority number) goal.',
            ge=1,
        ),
    ] = None
    measurement_readiness: Annotated[
        measurement_readiness_1.MeasurementReadiness | None,
        Field(
            description="Assessment of whether the buyer's event source setup is sufficient for this product to optimize effectively. Only present when the seller can evaluate the buyer's account context. Buyers should check this before creating media buys with event-based optimization goals."
        ),
    ] = None
    conversion_tracking: Annotated[
        ConversionTracking | None,
        Field(
            description="Conversion event tracking for this product. Presence indicates the product supports optimization_goals with kind: 'event'. Seller-level capabilities (supported event types, UID types, attribution windows) are declared in get_adcp_capabilities."
        ),
    ] = None
    catalog_match: Annotated[
        CatalogMatch | None,
        Field(
            description='When the buyer provides a catalog on get_products, indicates which catalog items are eligible for this product. Only present for products where catalog matching is relevant (e.g., sponsored product listings, job boards, hotel ads).'
        ),
    ] = None
    brief_relevance: Annotated[
        str | None,
        Field(
            description='Explanation of why this product matches the brief (only included when brief is provided)'
        ),
    ] = None
    expires_at: Annotated[
        AwareDatetime | None,
        Field(
            description='Expiration timestamp. After this time, the product may no longer be available for purchase and create_media_buy may reject packages referencing it.'
        ),
    ] = None
    product_card: Annotated[
        ProductCard | None,
        Field(
            description='Optional standard visual card for displaying this product in user interfaces (catalog browsers, dashboards, agent UIs). Distinct from `format` — product_card describes the UI rendering of the product itself, not the ad creative the product accepts. Typed inline; no format_id indirection. Receivers render the card directly from these fields.'
        ),
    ] = None
    product_card_detailed: Annotated[
        ProductCardDetailed | None,
        Field(
            description='Optional detailed card with hero + carousel + structured specifications, for rich product presentation (media-kit-style pages, full product detail views). Distinct from `format` — describes the UI rendering of the product itself, not the ad creative the product accepts. Typed inline; no format_id indirection.'
        ),
    ] = None
    collections: Annotated[
        list[collection_selector.CollectionSelector] | None,
        Field(
            description='Collections available in this product. Each entry references collections declared in an adagents.json by domain and collection ID. Buyers resolve full collection objects from the referenced adagents.json.',
            min_length=1,
        ),
    ] = None
    collection_targeting_allowed: Annotated[
        bool | None,
        Field(
            description="Whether buyers can target a subset of this product's collections. When false (default), the product is a bundle — buyers get all listed collections. When true, buyers can select specific collections in the media buy."
        ),
    ] = False
    installments: Annotated[
        list[installment.Installment] | None,
        Field(
            description='Specific installments included in this product. Each installment references its parent collection via collection_id when the product spans multiple collections. When absent with collections present, the product covers the collections broadly (run-of-collection).'
        ),
    ] = None
    enforced_policies: Annotated[
        list[str] | None,
        Field(
            description='Registry policy IDs the seller enforces for this product. Enforcement level comes from the policy registry. Buyers can filter products by required policies.'
        ),
    ] = None
    trusted_match: Annotated[
        TrustedMatch | None,
        Field(
            description='Trusted Match Protocol capabilities for this product. When present, the product supports real-time contextual and/or identity matching via TMP. Buyers use this to determine what response types the publisher can accept and whether brands can be selected dynamically at match time.'
        ),
    ] = None
    material_submission: Annotated[
        MaterialSubmission | None,
        Field(
            description="Instructions for submitting physical creative materials (print, static OOH, cinema). Present only for products requiring physical delivery outside the digital creative assignment flow. Buyer agents MUST validate url and email domains against the seller's known domains (from adagents.json) before submitting materials. Never auto-submit without human confirmation."
        ),
    ] = None
    ext: ext_1.ExtensionObject | None = None

Base model for AdCP types with spec-compliant serialization.

Defaults to extra='ignore' so unknown fields from newer spec versions are silently dropped rather than causing validation errors. Generated types whose schemas set additionalProperties: true override this with extra='allow' in their own model_config.

Set ADCP_STRICT_VALIDATION=1 in the environment ("1", "true", "yes", "on" are accepted) to flip the default to extra='forbid'. Use this during spec upgrades to catch silently-dropped renamed fields in tests. See :func:_resolve_extra_policy.

Important

The env var is resolved once at module import time. Set it in your shell or CI environment before import adcp runs — mutating os.environ["ADCP_STRICT_VALIDATION"] after the first adcp import has no effect on already-imported model classes (they captured the policy at class-body evaluation).

Consumers who want per-model strict validation can override model_config on their subclass.

Create a new model by parsing and validating input data from keyword arguments.

Raises [ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.

self is explicitly positional-only to allow self as a field name.

Ancestors

Class variables

var allowed_actions : list[adcp.types.generated_poc.core.product_allowed_action.ProductAllowedAction] | None
var audio_distribution_types : list[adcp.types.generated_poc.enums.audio_distribution_type.AudioDistributionType] | None
var brief_relevance : str | None
var cancellation_policy : adcp.types.generated_poc.core.cancellation_policy.CancellationPolicy | None
var catalog_match : adcp.types.generated_poc.core.product.CatalogMatch | None
var catalog_types : list[adcp.types.generated_poc.enums.catalog_type.CatalogType] | None
var channels : list[adcp.types.generated_poc.enums.channels.MediaChannel] | None
var collection_targeting_allowed : bool | None
var collections : list[adcp.types.generated_poc.core.collection_selector.CollectionSelector] | None
var conversion_tracking : adcp.types.generated_poc.core.product.ConversionTracking | None
var creative_policy : adcp.types.generated_poc.core.creative_policy.CreativePolicy | None
var data_provider_signals : list[adcp.types.generated_poc.core.data_provider_signal_selector.DataProviderSignalSelector] | None
var delivery_measurement : adcp.types.generated_poc.core.product.DeliveryMeasurement | None
var delivery_type : adcp.types.generated_poc.enums.delivery_type.DeliveryType
var description : str
var enforced_policies : list[str] | None
var exclusivity : adcp.types.generated_poc.enums.exclusivity.Exclusivity | None
var expires_at : pydantic.types.AwareDatetime | None
var ext : adcp.types.generated_poc.core.ext.ExtensionObject | None
var forecast : adcp.types.generated_poc.core.delivery_forecast.DeliveryForecast | None
var format_ids : list[adcp.types.generated_poc.core.format_id.FormatReferenceStructuredObject] | None
var format_options : list[adcp.types.generated_poc.core.product_format_declaration.ProductFormatDeclaration] | None
var included_signals : list[adcp.types.generated_poc.core.signal_listing.SignalListing] | None
var installments : list[adcp.types.generated_poc.core.installment.Installment] | None
var is_custom : bool | None
var material_submission : adcp.types.generated_poc.core.product.MaterialSubmission | None
var max_optimization_goals : int | None
var measurement_readiness : adcp.types.generated_poc.core.measurement_readiness.MeasurementReadiness | None
var measurement_terms : adcp.types.generated_poc.core.measurement_terms.MeasurementTerms | None
var metric_optimization : adcp.types.generated_poc.core.product.MetricOptimization | None
var model_config
var name : str
var outcome_measurement : adcp.types.generated_poc.core.outcome_measurement.OutcomeMeasurementDeprecated | None
var performance_standards : list[adcp.types.generated_poc.core.performance_standard.PerformanceStandard] | None
var placements : list[adcp.types.generated_poc.core.placement.Placement] | None
var pricing_options : list[adcp.types.generated_poc.core.pricing_option.PricingOption]
var product_card : adcp.types.generated_poc.core.product.ProductCard | None
var product_card_detailed : adcp.types.generated_poc.core.product.ProductCardDetailed | None
var product_id : str
var property_targeting_allowed : bool | None
var publisher_properties : list[adcp.types.generated_poc.core.product.PublisherProperty]
var reporting_capabilities : adcp.types.generated_poc.core.reporting_capabilities.ReportingCapabilities
var signal_targeting_allowed : bool | None
var signal_targeting_options : list[adcp.types.generated_poc.core.product_signal_targeting_option.ProductSignalTargetingOption] | None
var signal_targeting_rules : adcp.types.generated_poc.core.signal_targeting_rules.SignalTargetingRules | None
var social_placement_surfaces : list[adcp.types.generated_poc.enums.social_placement_surface.SocialPlacementSurface] | None
var sponsored_placement_types : list[adcp.types.generated_poc.enums.sponsored_placement_type.SponsoredPlacementType] | None
var trusted_match : adcp.types.generated_poc.core.product.TrustedMatch | None
var vendor_metric_optimization : adcp.types.generated_poc.core.vendor_metric_optimization.VendorMetricOptimization | None
var video_placement_types : list[adcp.types.generated_poc.enums.video_placement_type.VideoPlacementType] | None

Inherited members

class ProductCard (**data: Any)
Expand source code
class ProductCard(AdCPBaseModel):
    title: Annotated[bound_value.A2UiBoundValue, Field(description='Product name')]
    price: Annotated[bound_value.A2UiBoundValue, Field(description='Price display string')]
    image: Annotated[bound_value.A2UiBoundValue | None, Field(description='Product image URL')] = (
        None
    )
    description: Annotated[
        bound_value.A2UiBoundValue | None, Field(description='Product description')
    ] = None
    badge: Annotated[
        bound_value.A2UiBoundValue | None, Field(description="Badge text (e.g., 'Best Seller')")
    ] = None
    ctaLabel: Annotated[
        bound_value.A2UiBoundValue | None, Field(description='CTA button label')
    ] = None
    action: Action6 | None = None

Base model for AdCP types with spec-compliant serialization.

Defaults to extra='ignore' so unknown fields from newer spec versions are silently dropped rather than causing validation errors. Generated types whose schemas set additionalProperties: true override this with extra='allow' in their own model_config.

Set ADCP_STRICT_VALIDATION=1 in the environment ("1", "true", "yes", "on" are accepted) to flip the default to extra='forbid'. Use this during spec upgrades to catch silently-dropped renamed fields in tests. See :func:_resolve_extra_policy.

Important

The env var is resolved once at module import time. Set it in your shell or CI environment before import adcp runs — mutating os.environ["ADCP_STRICT_VALIDATION"] after the first adcp import has no effect on already-imported model classes (they captured the policy at class-body evaluation).

Consumers who want per-model strict validation can override model_config on their subclass.

Create a new model by parsing and validating input data from keyword arguments.

Raises [ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.

self is explicitly positional-only to allow self as a field name.

Ancestors

Class variables

var action : adcp.types.generated_poc.a2ui.si_catalog.Action6 | None
var badge : adcp.types.generated_poc.a2ui.bound_value.A2UiBoundValue | None
var ctaLabel : adcp.types.generated_poc.a2ui.bound_value.A2UiBoundValue | None
var description : adcp.types.generated_poc.a2ui.bound_value.A2UiBoundValue | None
var image : adcp.types.generated_poc.a2ui.bound_value.A2UiBoundValue | None
var model_config
var price : adcp.types.generated_poc.a2ui.bound_value.A2UiBoundValue
var title : adcp.types.generated_poc.a2ui.bound_value.A2UiBoundValue

Inherited members

class ProductCardDetailed (**data: Any)
Expand source code
class ProductCardDetailed(AdCPBaseModel):
    model_config = ConfigDict(
        extra='allow',
    )
    hero_image: Annotated[
        image_asset.ImageAsset | None,
        Field(description='Primary hero image at the top of the detailed view.'),
    ] = None
    carousel_images: Annotated[
        list[image_asset.ImageAsset] | None,
        Field(description='Additional images for a swipeable carousel below the hero.'),
    ] = None
    title: Annotated[str | None, Field(description='Page title (typically the product name).')] = (
        None
    )
    description: Annotated[
        str | None,
        Field(
            description='Full descriptive copy. Markdown allowed in client renderers that support it; otherwise treat as plain text.'
        ),
    ] = None
    specifications: Annotated[
        list[Specification] | None,
        Field(
            description="Structured key/value specifications (e.g., 'Aspect ratio: 9:16', 'Duration: 30s'). Each item is a labeled fact about the product."
        ),
    ] = None
    price_label: Annotated[str | None, Field(description='Formatted price or pricing summary.')] = (
        None
    )
    cta_label: Annotated[str | None, Field(description='Call-to-action button label.')] = None

Base model for AdCP types with spec-compliant serialization.

Defaults to extra='ignore' so unknown fields from newer spec versions are silently dropped rather than causing validation errors. Generated types whose schemas set additionalProperties: true override this with extra='allow' in their own model_config.

Set ADCP_STRICT_VALIDATION=1 in the environment ("1", "true", "yes", "on" are accepted) to flip the default to extra='forbid'. Use this during spec upgrades to catch silently-dropped renamed fields in tests. See :func:_resolve_extra_policy.

Important

The env var is resolved once at module import time. Set it in your shell or CI environment before import adcp runs — mutating os.environ["ADCP_STRICT_VALIDATION"] after the first adcp import has no effect on already-imported model classes (they captured the policy at class-body evaluation).

Consumers who want per-model strict validation can override model_config on their subclass.

Create a new model by parsing and validating input data from keyword arguments.

Raises [ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.

self is explicitly positional-only to allow self as a field name.

Ancestors

Class variables

var carousel_images : list[adcp.types.generated_poc.core.assets.image_asset.ImageAsset] | None
var cta_label : str | None
var description : str | None
var hero_image : adcp.types.generated_poc.core.assets.image_asset.ImageAsset | None
var model_config
var price_label : str | None
var specifications : list[adcp.types.generated_poc.core.product.Specification] | None
var title : str | None

Inherited members

class ProductFilters (**data: Any)
Expand source code
class ProductFilters(AdCPBaseModel):
    model_config = ConfigDict(
        extra='allow',
    )
    delivery_type: delivery_type_1.DeliveryType | None = None
    exclusivity: Annotated[
        exclusivity_1.Exclusivity | None,
        Field(
            description="Filter by exclusivity level. Returns products matching the specified exclusivity (e.g., 'exclusive' returns only sole-sponsorship products)."
        ),
    ] = None
    is_fixed_price: Annotated[
        bool | None,
        Field(
            description='Filter by pricing availability and returned pricing options: true = products offering fixed pricing (at least one option with fixed_price), false = products offering auction pricing (at least one option without fixed_price). Products with both fixed and auction options match both true and false, but sellers MUST return only the pricing_options entries matching the requested pricing type so buyers can deterministically select from the returned options.'
        ),
    ] = None
    pricing_currencies: Annotated[
        list[PricingCurrency] | None,
        Field(
            description='Filter by currencies the buyer can use for the media product transaction, using ISO 4217 currency codes. Products match when they offer at least one product-level pricing_options entry in one of the requested currencies and any seller-applied or otherwise mandatory product-scoped signal charges are satisfiable in one of those currencies or have no incremental price. Mandatory custom signal pricing without currency is not satisfiable for this filter unless the seller can truthfully treat it as having no incremental price. Sellers MUST return only product pricing_options entries whose currency is in this list so buyers can select deterministically from discovery. This filter does not require pruning optional signal or vendor add-on pricing; buyers should avoid optional add-ons priced only in unsupported currencies.',
            min_length=1,
        ),
    ] = None
    format_ids: Annotated[
        list[format_id.FormatReferenceStructuredObject] | None,
        Field(description='Filter by specific format IDs', min_length=1),
    ] = None
    standard_formats_only: Annotated[
        bool | None, Field(description='Only return products accepting IAB standard formats')
    ] = None
    min_exposures: Annotated[
        int | None,
        Field(description='Minimum exposures/impressions needed for measurement validity', ge=1),
    ] = None
    start_date: Annotated[
        date_aliased | None,
        Field(
            description='Campaign start date (ISO 8601 date format: YYYY-MM-DD) for availability checks'
        ),
    ] = None
    end_date: Annotated[
        date_aliased | None,
        Field(
            description='Campaign end date (ISO 8601 date format: YYYY-MM-DD) for availability checks'
        ),
    ] = None
    budget_range: Annotated[
        BudgetRange | None, Field(description='Budget range to filter appropriate products')
    ] = None
    countries: Annotated[
        list[Country] | None,
        Field(
            description="Filter by country coverage using ISO 3166-1 alpha-2 codes (e.g., ['US', 'CA', 'GB']). Works for all inventory types.",
            min_length=1,
        ),
    ] = None
    regions: Annotated[
        list[Region] | None,
        Field(
            description="Filter by region coverage using ISO 3166-2 codes (e.g., ['US-NY', 'US-CA', 'GB-SCT']). Use for locally-bound inventory (regional OOH, local TV) where products have region-specific coverage.",
            min_length=1,
        ),
    ] = None
    metros: Annotated[
        list[Metro] | None,
        Field(
            description='Filter by metro coverage for locally-bound inventory (radio, DOOH, local TV). Use when products have DMA/metro-specific coverage. For digital inventory where products have broad coverage, use required_geo_targeting instead to filter by seller capability.',
            min_length=1,
        ),
    ] = None
    channels: Annotated[
        list[channels_1.MediaChannel] | None,
        Field(
            description="Filter by advertising channels (e.g., ['display', 'ctv', 'dooh'])",
            min_length=1,
        ),
    ] = None
    video_placement_types: Annotated[
        list[video_placement_type.VideoPlacementType] | None,
        Field(
            description='Filter video products by acceptable declared video placement types, using IAB Tech Lab/OpenRTB 2.6 video.plcmt definitions with AdCP-native names. Sellers SHOULD return only products they can satisfy with at least one requested type. Products whose only available delivery is a mixed, non-targetable bundle that includes unrequested video placement types SHOULD NOT match unless the seller can constrain delivery to the requested type during planning or purchase. This filter has set semantics for wholesale feed canonicalization.',
            min_length=1,
        ),
    ] = None
    audio_distribution_types: Annotated[
        list[audio_distribution_type.AudioDistributionType] | None,
        Field(
            description='Filter audio products by acceptable declared audio distribution types, using IAB Tech Lab/OpenRTB 2.6 audio.feed definitions with AdCP-native names. Sellers SHOULD return only products they can satisfy with at least one requested type. Products whose only available delivery is a mixed, non-targetable bundle that includes unrequested audio distribution types SHOULD NOT match unless the seller can constrain delivery to the requested type during planning or purchase. This filter has set semantics for wholesale feed canonicalization.',
            min_length=1,
        ),
    ] = None
    sponsored_placement_types: Annotated[
        list[sponsored_placement_type.SponsoredPlacementType] | None,
        Field(
            description='Filter retail-media products by acceptable declared sponsored-placement types (sponsored search, sponsored display, or sponsored native). Sellers SHOULD return only products they can satisfy with at least one requested type. Products whose only available delivery is a mixed, non-targetable bundle that includes unrequested sponsored-placement types SHOULD NOT match unless the seller can constrain delivery to the requested type during planning or purchase. This filter has set semantics for wholesale feed canonicalization.',
            min_length=1,
        ),
    ] = None
    social_placement_surfaces: Annotated[
        list[social_placement_surface.SocialPlacementSurface] | None,
        Field(
            description='Filter social products by acceptable declared social-placement surfaces (feed, stories, short_video, explore, or search). Sellers SHOULD return only products they can satisfy with at least one requested surface. Products whose only available delivery is a mixed, non-targetable bundle that includes unrequested surfaces SHOULD NOT match unless the seller can constrain delivery to the requested surface during planning or purchase. This filter has set semantics for wholesale feed canonicalization.',
            min_length=1,
        ),
    ] = None
    required_axe_integrations: Annotated[
        list[AnyUrl] | None,
        Field(
            deprecated=True,
            description='Deprecated: Use trusted_match filter instead. Filter to products executable through specific agentic ad exchanges. URLs are canonical identifiers.',
        ),
    ] = None
    trusted_match: Annotated[
        TrustedMatch | None,
        Field(
            description='Filter products by Trusted Match Protocol capabilities. Only products with matching TMP support are returned.'
        ),
    ] = None
    required_features: Annotated[
        media_buy_features.MediaBuyFeatures | None,
        Field(
            description='Filter to products from sellers supporting specific protocol features. Only features set to true are used for filtering.'
        ),
    ] = None
    required_geo_targeting: Annotated[
        list[RequiredGeoTargetingItem] | None,
        Field(
            description='Filter to products from sellers supporting specific geo targeting capabilities. Each entry specifies a targeting level (country, region, metro, postal_area) and optionally a system for levels that have multiple classification systems. For native postal_area filters, include country plus the country-local postal system.',
            min_length=1,
        ),
    ] = None
    signal_targeting: Annotated[
        list[SignalTargetingItem] | None,
        Field(
            description="Filter to products where the requested signals are buyer-selectable and jointly composable: the signals are available through inline signal_targeting_options and/or through get_signals for wholesale products that allow signal targeting but omit inline options, signal_targeting_allowed is true, and the requested set can coexist under the product's signal_targeting_rules. Each filter entry uses signal_ref, with deprecated signal_id accepted during the SignalRef migration window, and may include targeting_mode='include' or 'exclude' to require the product option or product rules to support that use. When targeting_mode is omitted, include is assumed. SignalRef scope 'product' is seller-local exact option matching only, not a portable semantic identifier across products or sellers; buyers wanting portable discovery should use scope 'data_provider' or get_signals. included_signals and deprecated bundled/non-selectable data_provider_signals do not satisfy this filter because they cannot be selected on create_media_buy.",
            min_length=1,
        ),
    ] = None
    postal_areas: Annotated[
        list[postal_area.PostalArea] | None,
        Field(
            description='Filter by postal area coverage for locally-bound inventory (direct mail, DOOH, local campaigns). Prefer the native country + postal system form. Deprecated legacy country-fused postal-system tokens remain accepted for compatibility. For digital inventory where products have broad coverage, use required_geo_targeting instead to filter by seller capability.',
            min_length=1,
        ),
    ] = None
    geo_proximity: Annotated[
        list[GeoProximityItem] | None,
        Field(
            description='Filter by proximity to geographic points. Returns products with inventory coverage near these locations. Follows the same format as the targeting overlay — each entry uses exactly one method: travel_time + transport_mode, radius, or geometry. For locally-bound inventory (DOOH, radio), filters to products with coverage in the area. For digital inventory, filters to products from sellers supporting geo_proximity targeting.',
            min_length=1,
        ),
    ] = None
    required_performance_standards: Annotated[
        list[performance_standard.PerformanceStandard] | None,
        Field(
            description="Filter to products that can meet the buyer's performance standard requirements. Each entry specifies a metric, minimum threshold, and optionally a required vendor and standard. Products that cannot meet these thresholds or do not support the specified vendors are excluded. Use this to tell the seller upfront: 'I need DoubleVerify for viewability at 70% MRC.'",
            min_length=1,
        ),
    ] = None
    required_metrics: Annotated[
        list[available_metric.AvailableMetric] | None,
        Field(
            description="Filter to products whose `reporting_capabilities.available_metrics` is a superset of these metrics — i.e., products that commit to reporting all listed metrics in delivery responses. Use this for capability-level discovery (e.g., 'I need products that report `completed_views` for a CTV CPCV buy'); guarantee-level requirements with thresholds belong in `required_performance_standards` and `measurement_terms`. Sellers MUST silently exclude products that cannot meet this list (filter-not-fail; do not return an error). The product's declared `available_metrics` becomes the binding reporting contract carried into the resulting media buy — the same metric vocabulary is used to compute `missing_metrics` on `get_media_buy_delivery`.",
            examples=[
                ['completed_views'],
                ['completed_views', 'completion_rate'],
                ['impressions', 'spend', 'engagements'],
            ],
            min_length=1,
        ),
    ] = None
    required_vendor_metrics: Annotated[
        list[RequiredVendorMetric] | None,
        Field(
            description="Filter to products whose `reporting_capabilities.vendor_metrics` matches these criteria. Each entry pins a `vendor` (matches any metric from that vendor), a `metric_id` (matches the metric across any vendor that uses that identifier), or both (specific vendor's specific metric). A product matches if its declared `vendor_metrics` covers ALL listed entries (AND across entries; pins within an entry are conjunctive). Cross-vendor discovery (e.g., 'I need attention measurement from any vendor that does it') is the buyer agent's responsibility — the agent resolves which vendors offer a category via the vendors' `brand.json` records, then enumerates them as filter entries. AdCP does not carry vendor-side metric metadata (category, methodology, standard alignment) in the filter surface; that lives at the vendor and is queried out-of-band. Sellers MUST silently exclude non-matching products (filter-not-fail; do not return an error) — same convention as the other `required_*` filters.",
            examples=[
                [{'vendor': {'domain': 'attentionvendor.example'}}],
                [
                    {
                        'vendor': {'domain': 'panelmeasurement.example'},
                        'metric_id': 'demographic_reach',
                    }
                ],
                [
                    {'vendor': {'domain': 'attentionvendor.example'}},
                    {'vendor': {'domain': 'secondattentionvendor.example'}},
                ],
            ],
            min_length=1,
        ),
    ] = None
    keywords: Annotated[
        list[Keyword] | None,
        Field(
            description='Filter by keyword relevance for search and retail media platforms. Returns products that support keyword targeting for these terms. Allows the sell-side agent to assess keyword availability and recommend appropriate products. Use match_type to indicate the desired precision.',
            min_length=1,
        ),
    ] = None
    ext: Annotated[
        ext_1.ExtensionObject | None,
        Field(
            description='Vendor-namespaced extension parameters for seller-specific filter criteria not covered by standard fields. Keys MUST be namespaced under a vendor or platform key (e.g., ext.gam, ext.platform_x). Sellers MUST treat all values as untrusted buyer input; do not interpolate into LLM prompts, SQL queries, or system commands without sanitization. Persistent use of an extension key across multiple buyers is a signal to propose standardization.'
        ),
    ] = None

Base model for AdCP types with spec-compliant serialization.

Defaults to extra='ignore' so unknown fields from newer spec versions are silently dropped rather than causing validation errors. Generated types whose schemas set additionalProperties: true override this with extra='allow' in their own model_config.

Set ADCP_STRICT_VALIDATION=1 in the environment ("1", "true", "yes", "on" are accepted) to flip the default to extra='forbid'. Use this during spec upgrades to catch silently-dropped renamed fields in tests. See :func:_resolve_extra_policy.

Important

The env var is resolved once at module import time. Set it in your shell or CI environment before import adcp runs — mutating os.environ["ADCP_STRICT_VALIDATION"] after the first adcp import has no effect on already-imported model classes (they captured the policy at class-body evaluation).

Consumers who want per-model strict validation can override model_config on their subclass.

Create a new model by parsing and validating input data from keyword arguments.

Raises [ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.

self is explicitly positional-only to allow self as a field name.

Ancestors

Class variables

var audio_distribution_types : list[adcp.types.generated_poc.enums.audio_distribution_type.AudioDistributionType] | None
var budget_range : adcp.types.generated_poc.core.product_filters.BudgetRange | None
var channels : list[adcp.types.generated_poc.enums.channels.MediaChannel] | None
var countries : list[adcp.types.generated_poc.core.product_filters.Country] | None
var delivery_type : adcp.types.generated_poc.enums.delivery_type.DeliveryType | None
var end_date : datetime.date | None
var exclusivity : adcp.types.generated_poc.enums.exclusivity.Exclusivity | None
var ext : adcp.types.generated_poc.core.ext.ExtensionObject | None
var format_ids : list[adcp.types.generated_poc.core.format_id.FormatReferenceStructuredObject] | None
var geo_proximity : list[adcp.types.generated_poc.core.product_filters.GeoProximityItem] | None
var is_fixed_price : bool | None
var keywords : list[adcp.types.generated_poc.core.product_filters.Keyword] | None
var metros : list[adcp.types.generated_poc.core.product_filters.Metro] | None
var min_exposures : int | None
var model_config
var postal_areas : list[adcp.types.generated_poc.core.postal_area.PostalArea] | None
var pricing_currencies : list[adcp.types.generated_poc.core.product_filters.PricingCurrency] | None
var regions : list[adcp.types.generated_poc.core.product_filters.Region] | None
var required_axe_integrations : list[pydantic.networks.AnyUrl] | None
var required_features : adcp.types.generated_poc.core.media_buy_features.MediaBuyFeatures | None
var required_geo_targeting : list[adcp.types.generated_poc.core.product_filters.RequiredGeoTargetingItem] | None
var required_metrics : list[adcp.types.generated_poc.enums.available_metric.AvailableMetric] | None
var required_performance_standards : list[adcp.types.generated_poc.core.performance_standard.PerformanceStandard] | None
var required_vendor_metrics : list[adcp.types.generated_poc.core.product_filters.RequiredVendorMetric] | None
var signal_targeting : list[adcp.types.generated_poc.core.product_filters.SignalTargetingItem] | None
var social_placement_surfaces : list[adcp.types.generated_poc.enums.social_placement_surface.SocialPlacementSurface] | None
var sponsored_placement_types : list[adcp.types.generated_poc.enums.sponsored_placement_type.SponsoredPlacementType] | None
var standard_formats_only : bool | None
var start_date : datetime.date | None
var trusted_match : adcp.types.generated_poc.core.product_filters.TrustedMatch | None
var video_placement_types : list[adcp.types.generated_poc.enums.video_placement_type.VideoPlacementType] | None

Inherited members

class ProvidePerformanceFeedbackRequest (**data: Any)
Expand source code
class ProvidePerformanceFeedbackRequest(AdcpVersionEnvelope):
    model_config = ConfigDict(
        extra='allow',
    )
    media_buy_id: Annotated[str, Field(description="Seller's media buy identifier", min_length=1)]
    idempotency_key: Annotated[
        str,
        Field(
            description='Client-generated unique key for this request. Prevents duplicate feedback submissions on retries. MUST be unique per (seller, request) pair to prevent cross-seller correlation. Use a fresh UUID v4 for each request.',
            max_length=255,
            min_length=16,
            pattern='^[A-Za-z0-9_.:-]{16,255}$',
        ),
    ]
    measurement_period: Annotated[
        datetime_range.DatetimeRange, Field(description='Time period for performance measurement')
    ]
    performance_index: Annotated[
        float,
        Field(
            description='Normalized performance score (0.0 = no value, 1.0 = expected, >1.0 = above expected)',
            ge=0.0,
        ),
    ]
    package_id: Annotated[
        str | None,
        Field(
            description='Specific package within the media buy (if feedback is package-specific)',
            min_length=1,
        ),
    ] = None
    creative_id: Annotated[
        str | None,
        Field(
            description='Specific creative asset (if feedback is creative-specific)', min_length=1
        ),
    ] = None
    metric_type: Annotated[
        metric_type_1.MetricTypeDeprecated | None,
        Field(description='The business metric being measured'),
    ] = metric_type_1.MetricTypeDeprecated.overall_performance
    feedback_source: Annotated[
        feedback_source_1.FeedbackSource | None, Field(description='Source of the performance data')
    ] = feedback_source_1.FeedbackSource.buyer_attribution
    context: context_1.ContextObject | None = None
    ext: ext_1.ExtensionObject | None = None

Base model for AdCP types with spec-compliant serialization.

Defaults to extra='ignore' so unknown fields from newer spec versions are silently dropped rather than causing validation errors. Generated types whose schemas set additionalProperties: true override this with extra='allow' in their own model_config.

Set ADCP_STRICT_VALIDATION=1 in the environment ("1", "true", "yes", "on" are accepted) to flip the default to extra='forbid'. Use this during spec upgrades to catch silently-dropped renamed fields in tests. See :func:_resolve_extra_policy.

Important

The env var is resolved once at module import time. Set it in your shell or CI environment before import adcp runs — mutating os.environ["ADCP_STRICT_VALIDATION"] after the first adcp import has no effect on already-imported model classes (they captured the policy at class-body evaluation).

Consumers who want per-model strict validation can override model_config on their subclass.

Create a new model by parsing and validating input data from keyword arguments.

Raises [ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.

self is explicitly positional-only to allow self as a field name.

Ancestors

  • adcp.types.generated_poc.core.version_envelope.AdcpVersionEnvelope
  • AdCPBaseModel
  • pydantic.main.BaseModel

Class variables

var context : adcp.types.generated_poc.core.context.ContextObject | None
var creative_id : str | None
var ext : adcp.types.generated_poc.core.ext.ExtensionObject | None
var feedback_source : adcp.types.generated_poc.enums.feedback_source.FeedbackSource | None
var idempotency_key : str
var measurement_period : adcp.types.generated_poc.core.datetime_range.DatetimeRange
var media_buy_id : str
var metric_type : adcp.types.generated_poc.enums.metric_type.MetricTypeDeprecated | None
var model_config
var package_id : str | None
var performance_index : float
class ProvidePerformanceFeedbackByMediaBuyRequest (**data: Any)
Expand source code
class ProvidePerformanceFeedbackRequest(AdcpVersionEnvelope):
    model_config = ConfigDict(
        extra='allow',
    )
    media_buy_id: Annotated[str, Field(description="Seller's media buy identifier", min_length=1)]
    idempotency_key: Annotated[
        str,
        Field(
            description='Client-generated unique key for this request. Prevents duplicate feedback submissions on retries. MUST be unique per (seller, request) pair to prevent cross-seller correlation. Use a fresh UUID v4 for each request.',
            max_length=255,
            min_length=16,
            pattern='^[A-Za-z0-9_.:-]{16,255}$',
        ),
    ]
    measurement_period: Annotated[
        datetime_range.DatetimeRange, Field(description='Time period for performance measurement')
    ]
    performance_index: Annotated[
        float,
        Field(
            description='Normalized performance score (0.0 = no value, 1.0 = expected, >1.0 = above expected)',
            ge=0.0,
        ),
    ]
    package_id: Annotated[
        str | None,
        Field(
            description='Specific package within the media buy (if feedback is package-specific)',
            min_length=1,
        ),
    ] = None
    creative_id: Annotated[
        str | None,
        Field(
            description='Specific creative asset (if feedback is creative-specific)', min_length=1
        ),
    ] = None
    metric_type: Annotated[
        metric_type_1.MetricTypeDeprecated | None,
        Field(description='The business metric being measured'),
    ] = metric_type_1.MetricTypeDeprecated.overall_performance
    feedback_source: Annotated[
        feedback_source_1.FeedbackSource | None, Field(description='Source of the performance data')
    ] = feedback_source_1.FeedbackSource.buyer_attribution
    context: context_1.ContextObject | None = None
    ext: ext_1.ExtensionObject | None = None

Base model for AdCP types with spec-compliant serialization.

Defaults to extra='ignore' so unknown fields from newer spec versions are silently dropped rather than causing validation errors. Generated types whose schemas set additionalProperties: true override this with extra='allow' in their own model_config.

Set ADCP_STRICT_VALIDATION=1 in the environment ("1", "true", "yes", "on" are accepted) to flip the default to extra='forbid'. Use this during spec upgrades to catch silently-dropped renamed fields in tests. See :func:_resolve_extra_policy.

Important

The env var is resolved once at module import time. Set it in your shell or CI environment before import adcp runs — mutating os.environ["ADCP_STRICT_VALIDATION"] after the first adcp import has no effect on already-imported model classes (they captured the policy at class-body evaluation).

Consumers who want per-model strict validation can override model_config on their subclass.

Create a new model by parsing and validating input data from keyword arguments.

Raises [ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.

self is explicitly positional-only to allow self as a field name.

Ancestors

  • adcp.types.generated_poc.core.version_envelope.AdcpVersionEnvelope
  • AdCPBaseModel
  • pydantic.main.BaseModel

Class variables

var context : adcp.types.generated_poc.core.context.ContextObject | None
var creative_id : str | None
var ext : adcp.types.generated_poc.core.ext.ExtensionObject | None
var feedback_source : adcp.types.generated_poc.enums.feedback_source.FeedbackSource | None
var idempotency_key : str
var measurement_period : adcp.types.generated_poc.core.datetime_range.DatetimeRange
var media_buy_id : str
var metric_type : adcp.types.generated_poc.enums.metric_type.MetricTypeDeprecated | None
var model_config
var package_id : str | None
var performance_index : float
class ProvidePerformanceFeedbackByBuyerRefRequest (**data: Any)
Expand source code
class ProvidePerformanceFeedbackRequest(AdcpVersionEnvelope):
    model_config = ConfigDict(
        extra='allow',
    )
    media_buy_id: Annotated[str, Field(description="Seller's media buy identifier", min_length=1)]
    idempotency_key: Annotated[
        str,
        Field(
            description='Client-generated unique key for this request. Prevents duplicate feedback submissions on retries. MUST be unique per (seller, request) pair to prevent cross-seller correlation. Use a fresh UUID v4 for each request.',
            max_length=255,
            min_length=16,
            pattern='^[A-Za-z0-9_.:-]{16,255}$',
        ),
    ]
    measurement_period: Annotated[
        datetime_range.DatetimeRange, Field(description='Time period for performance measurement')
    ]
    performance_index: Annotated[
        float,
        Field(
            description='Normalized performance score (0.0 = no value, 1.0 = expected, >1.0 = above expected)',
            ge=0.0,
        ),
    ]
    package_id: Annotated[
        str | None,
        Field(
            description='Specific package within the media buy (if feedback is package-specific)',
            min_length=1,
        ),
    ] = None
    creative_id: Annotated[
        str | None,
        Field(
            description='Specific creative asset (if feedback is creative-specific)', min_length=1
        ),
    ] = None
    metric_type: Annotated[
        metric_type_1.MetricTypeDeprecated | None,
        Field(description='The business metric being measured'),
    ] = metric_type_1.MetricTypeDeprecated.overall_performance
    feedback_source: Annotated[
        feedback_source_1.FeedbackSource | None, Field(description='Source of the performance data')
    ] = feedback_source_1.FeedbackSource.buyer_attribution
    context: context_1.ContextObject | None = None
    ext: ext_1.ExtensionObject | None = None

Base model for AdCP types with spec-compliant serialization.

Defaults to extra='ignore' so unknown fields from newer spec versions are silently dropped rather than causing validation errors. Generated types whose schemas set additionalProperties: true override this with extra='allow' in their own model_config.

Set ADCP_STRICT_VALIDATION=1 in the environment ("1", "true", "yes", "on" are accepted) to flip the default to extra='forbid'. Use this during spec upgrades to catch silently-dropped renamed fields in tests. See :func:_resolve_extra_policy.

Important

The env var is resolved once at module import time. Set it in your shell or CI environment before import adcp runs — mutating os.environ["ADCP_STRICT_VALIDATION"] after the first adcp import has no effect on already-imported model classes (they captured the policy at class-body evaluation).

Consumers who want per-model strict validation can override model_config on their subclass.

Create a new model by parsing and validating input data from keyword arguments.

Raises [ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.

self is explicitly positional-only to allow self as a field name.

Ancestors

  • adcp.types.generated_poc.core.version_envelope.AdcpVersionEnvelope
  • AdCPBaseModel
  • pydantic.main.BaseModel

Class variables

var context : adcp.types.generated_poc.core.context.ContextObject | None
var creative_id : str | None
var ext : adcp.types.generated_poc.core.ext.ExtensionObject | None
var feedback_source : adcp.types.generated_poc.enums.feedback_source.FeedbackSource | None
var idempotency_key : str
var measurement_period : adcp.types.generated_poc.core.datetime_range.DatetimeRange
var media_buy_id : str
var metric_type : adcp.types.generated_poc.enums.metric_type.MetricTypeDeprecated | None
var model_config
var package_id : str | None
var performance_index : float

Inherited members

class Refine (root: RootModelRootType = PydanticUndefined, **data)
Expand source code
class Refine(RootModel[Refine1 | Refine2 | Refine3]):
    root: Annotated[Refine1 | Refine2 | Refine3, Field(discriminator='scope')]
    def __getattr__(self, name: str) -> Any:
        """Proxy attribute access to the wrapped type."""
        if name.startswith('_'):
            raise AttributeError(name)
        return getattr(self.root, name)

Usage Documentation

RootModel and Custom Root Types

A Pydantic BaseModel for the root object of the model.

Attributes

root
The root object of the model.
__pydantic_root_model__
Whether the model is a RootModel.
__pydantic_private__
Private fields in the model.
__pydantic_extra__
Extra fields in the model.

Create a new model by parsing and validating input data from keyword arguments.

Raises [ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.

self is explicitly positional-only to allow self as a field name.

Ancestors

  • pydantic.root_model.RootModel[Union[Refine1, Refine2, Refine3]]
  • pydantic.root_model.RootModel
  • pydantic.main.BaseModel
  • typing.Generic

Class variables

var model_config
var root : adcp.types.generated_poc.media_buy.get_products_request.Refine1 | adcp.types.generated_poc.media_buy.get_products_request.Refine2 | adcp.types.generated_poc.media_buy.get_products_request.Refine3
class RefinementApplied (root: RootModelRootType = PydanticUndefined, **data)
Expand source code
class RefinementApplied(RootModel[RefinementApplied1 | RefinementApplied2 | RefinementApplied3]):
    root: Annotated[
        RefinementApplied1 | RefinementApplied2 | RefinementApplied3, Field(discriminator='scope')
    ]
    def __getattr__(self, name: str) -> Any:
        """Proxy attribute access to the wrapped type."""
        if name.startswith('_'):
            raise AttributeError(name)
        return getattr(self.root, name)

Usage Documentation

RootModel and Custom Root Types

A Pydantic BaseModel for the root object of the model.

Attributes

root
The root object of the model.
__pydantic_root_model__
Whether the model is a RootModel.
__pydantic_private__
Private fields in the model.
__pydantic_extra__
Extra fields in the model.

Create a new model by parsing and validating input data from keyword arguments.

Raises [ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.

self is explicitly positional-only to allow self as a field name.

Ancestors

  • pydantic.root_model.RootModel[Union[RefinementApplied1, RefinementApplied2, RefinementApplied3]]
  • pydantic.root_model.RootModel
  • pydantic.main.BaseModel
  • typing.Generic

Class variables

var model_config
var root : adcp.types.generated_poc.media_buy.get_products_response.RefinementApplied1 | adcp.types.generated_poc.media_buy.get_products_response.RefinementApplied2 | adcp.types.generated_poc.media_buy.get_products_response.RefinementApplied3
class RightsPricingOption (**data: Any)
Expand source code
class RightsPricingOption(AdCPBaseModel):
    model_config = ConfigDict(
        extra='allow',
    )
    pricing_option_id: Annotated[
        str,
        Field(
            description='Unique identifier for this pricing option. Referenced in acquire_rights and report_usage.'
        ),
    ]
    model: Annotated[
        pricing_model.PricingModel, Field(description='Pricing model (cpm, flat_rate, etc.)')
    ]
    price: Annotated[
        float,
        Field(
            description='Price amount. Interpretation depends on model: CPM = cost per 1,000 impressions, flat_rate = fixed cost per period.',
            ge=0.0,
        ),
    ]
    currency: Annotated[str, Field(description='ISO 4217 currency code', pattern='^[A-Z]{3}$')]
    uses: Annotated[
        list[right_use.RightUse],
        Field(
            description='Which rights uses this pricing option covers. A single option can bundle multiple uses (e.g., likeness + voice).',
            min_length=1,
        ),
    ]
    period: Annotated[
        rights_billing_period.RightsBillingPeriod | None,
        Field(description='Billing period for flat_rate and time-based models'),
    ] = None
    impression_cap: Annotated[
        int | None,
        Field(description='Maximum impressions included in this pricing option per period', ge=1),
    ] = None
    overage_cpm: Annotated[
        float | None,
        Field(description='CPM rate applied to impressions exceeding the impression_cap', ge=0.0),
    ] = None
    description: Annotated[
        str | None, Field(description='Human-readable description of this pricing option')
    ] = None
    ext: ext_1.ExtensionObject | None = None

Base model for AdCP types with spec-compliant serialization.

Defaults to extra='ignore' so unknown fields from newer spec versions are silently dropped rather than causing validation errors. Generated types whose schemas set additionalProperties: true override this with extra='allow' in their own model_config.

Set ADCP_STRICT_VALIDATION=1 in the environment ("1", "true", "yes", "on" are accepted) to flip the default to extra='forbid'. Use this during spec upgrades to catch silently-dropped renamed fields in tests. See :func:_resolve_extra_policy.

Important

The env var is resolved once at module import time. Set it in your shell or CI environment before import adcp runs — mutating os.environ["ADCP_STRICT_VALIDATION"] after the first adcp import has no effect on already-imported model classes (they captured the policy at class-body evaluation).

Consumers who want per-model strict validation can override model_config on their subclass.

Create a new model by parsing and validating input data from keyword arguments.

Raises [ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.

self is explicitly positional-only to allow self as a field name.

Ancestors

Class variables

var currency : str
var description : str | None
var ext : adcp.types.generated_poc.core.ext.ExtensionObject | None
var impression_cap : int | None
var model : adcp.types.generated_poc.enums.pricing_model.PricingModel
var model_config
var overage_cpm : float | None
var period : adcp.types.generated_poc.enums.rights_billing_period.RightsBillingPeriod | None
var price : float
var pricing_option_id : str
var uses : list[adcp.types.generated_poc.enums.right_use.RightUse]

Inherited members

class RightsTerms (**data: Any)
Expand source code
class RightsTerms(AdCPBaseModel):
    model_config = ConfigDict(
        extra='allow',
    )
    pricing_option_id: str
    amount: Annotated[float, Field(ge=0.0)]
    currency: Annotated[str, Field(pattern='^[A-Z]{3}$')]
    period: rights_billing_period.RightsBillingPeriod | None = None
    uses: list[right_use.RightUse]
    impression_cap: Annotated[int | None, Field(ge=1)] = None
    overage_cpm: Annotated[float | None, Field(ge=0.0)] = None
    start_date: date_aliased | None = None
    end_date: date_aliased | None = None
    exclusivity: Annotated[
        Exclusivity | None, Field(description='Exclusivity terms if applicable')
    ] = None

Base model for AdCP types with spec-compliant serialization.

Defaults to extra='ignore' so unknown fields from newer spec versions are silently dropped rather than causing validation errors. Generated types whose schemas set additionalProperties: true override this with extra='allow' in their own model_config.

Set ADCP_STRICT_VALIDATION=1 in the environment ("1", "true", "yes", "on" are accepted) to flip the default to extra='forbid'. Use this during spec upgrades to catch silently-dropped renamed fields in tests. See :func:_resolve_extra_policy.

Important

The env var is resolved once at module import time. Set it in your shell or CI environment before import adcp runs — mutating os.environ["ADCP_STRICT_VALIDATION"] after the first adcp import has no effect on already-imported model classes (they captured the policy at class-body evaluation).

Consumers who want per-model strict validation can override model_config on their subclass.

Create a new model by parsing and validating input data from keyword arguments.

Raises [ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.

self is explicitly positional-only to allow self as a field name.

Ancestors

Class variables

var amount : float
var currency : str
var end_date : datetime.date | None
var exclusivity : adcp.types.generated_poc.brand.rights_terms.Exclusivity | None
var impression_cap : int | None
var model_config
var overage_cpm : float | None
var period : adcp.types.generated_poc.enums.rights_billing_period.RightsBillingPeriod | None
var pricing_option_id : str
var start_date : datetime.date | None
var uses : list[adcp.types.generated_poc.enums.right_use.RightUse]

Inherited members

class TargetingOverlay (**data: Any)
Expand source code
class TargetingOverlay(AdCPBaseModel):
    model_config = ConfigDict(
        extra='allow',
    )
    geo_countries: Annotated[
        list[GeoCountry] | None,
        Field(
            description="Restrict delivery to specific countries. ISO 3166-1 alpha-2 codes (e.g., 'US', 'GB', 'DE').",
            min_length=1,
        ),
    ] = None
    geo_countries_exclude: Annotated[
        Sequence[GeoCountriesExcludeItem] | None,
        Field(
            description="Exclude specific countries from delivery. ISO 3166-1 alpha-2 codes (e.g., 'US', 'GB', 'DE').",
            min_length=1,
        ),
    ] = None
    geo_regions: Annotated[
        list[GeoRegion] | None,
        Field(
            description="Restrict delivery to specific regions/states. ISO 3166-2 subdivision codes (e.g., 'US-CA', 'GB-SCT').",
            min_length=1,
        ),
    ] = None
    geo_regions_exclude: Annotated[
        Sequence[GeoRegionsExcludeItem] | None,
        Field(
            description="Exclude specific regions/states from delivery. ISO 3166-2 subdivision codes (e.g., 'US-CA', 'GB-SCT').",
            min_length=1,
        ),
    ] = None
    geo_metros: Annotated[
        list[GeoMetro] | None,
        Field(
            description='Restrict delivery to specific metro areas. Each entry specifies the classification system and target values. Seller must declare supported systems in get_adcp_capabilities.',
            min_length=1,
        ),
    ] = None
    geo_metros_exclude: Annotated[
        Sequence[GeoMetrosExcludeItem] | None,
        Field(
            description='Exclude specific metro areas from delivery. Each entry specifies the classification system and excluded values. Seller must declare supported systems in get_adcp_capabilities.',
            min_length=1,
        ),
    ] = None
    geo_postal_areas: Annotated[
        list[postal_area.PostalArea] | None,
        Field(
            description='Restrict delivery to specific postal areas. Prefer the native country + postal system form. The deprecated legacy country-fused postal-system tokens remain accepted for compatibility. Seller must declare supported systems in get_adcp_capabilities.',
            min_length=1,
        ),
    ] = None
    geo_postal_areas_exclude: Annotated[
        Sequence[postal_area.PostalArea] | None,
        Field(
            description='Exclude specific postal areas from delivery. Prefer the native country + postal system form. The deprecated legacy country-fused postal-system tokens remain accepted for compatibility. Seller must declare supported systems in get_adcp_capabilities.',
            min_length=1,
        ),
    ] = None
    daypart_targets: Annotated[
        list[daypart_target.DaypartTarget] | None,
        Field(
            description='Restrict delivery to specific time windows. Each entry specifies days of week and an hour range.',
            min_length=1,
        ),
    ] = None
    axe_include_segment: Annotated[
        str | None,
        Field(
            deprecated=True,
            description='Deprecated: Use TMP provider fields instead. AXE segment ID to include for targeting.',
        ),
    ] = None
    axe_exclude_segment: Annotated[
        str | None,
        Field(
            deprecated=True,
            description='Deprecated: Use TMP provider fields instead. AXE segment ID to exclude from targeting.',
        ),
    ] = None
    audience_include: Annotated[
        list[str] | None,
        Field(
            description='Restrict delivery to members of these first-party CRM audiences. Only users present in the uploaded lists are eligible. References audience_id values from sync_audiences on the same seller account — audience IDs are not portable across sellers. Not for lookalike expansion — express that intent in the campaign brief. Seller must declare support in get_adcp_capabilities.',
            min_length=1,
        ),
    ] = None
    audience_exclude: Annotated[
        list[str] | None,
        Field(
            description='Suppress delivery to members of these first-party CRM audiences. Matched users are excluded regardless of other targeting. References audience_id values from sync_audiences on the same seller account — audience IDs are not portable across sellers. Seller must declare support in get_adcp_capabilities.',
            min_length=1,
        ),
    ] = None
    signal_targeting_groups: Annotated[
        package_signal_targeting_groups.PackageSignalTargetingGroups | None,
        Field(
            description="Basic Boolean grouping for seller-offered signals. v1 supports a required top-level operator 'all' and child groups with operator 'any' for include groups or 'none' for exclusion groups. Example semantics: group 1 any(A, B) plus group 2 none(C, D) means (A OR B) AND NOT (C OR D). Signal entries reference named signal definitions with signal_ref scope 'product' for product-local signal options or scope 'data_provider' for external signals published in adagents.json signals[]. For simple include-only targeting, send one child group with operator 'any'. Sellers SHOULD reject entries that are not available for the product through inline signal_targeting_options or get_signals, are not active for the account, or exceed the product's signal_targeting_allowed/signal_targeting_rules/product terms. Signal targeting limits are product-scoped, not declared in get_adcp_capabilities, because products may be backed by different ad servers. Sellers MUST echo applied signal_targeting_groups on the resulting package state, including fixed/default selections. On update_media_buy, sellers MAY reject changes that require repricing with REQUOTE_REQUIRED."
        ),
    ] = None
    signal_targeting: Annotated[
        list[signal_targeting_1.SignalTargeting] | None,
        Field(
            deprecated=True,
            description='DEPRECATED. Use signal_targeting_groups for package-level signal targeting. Legacy flat signal_targeting remains accepted during the SignalRef migration window but cannot express grouped include/exclude composition or product-scoped pricing.',
            min_length=1,
        ),
    ] = None
    frequency_cap: frequency_cap_1.FrequencyCap | None = None
    property_list: Annotated[
        property_list_ref.PropertyListReference | None,
        Field(
            description="Reference to a property list for targeting specific properties within this product. The package runs on the intersection of the product's publisher_properties and this list. Sellers SHOULD return a validation error if the product has property_targeting_allowed: false."
        ),
    ] = None
    collection_list: Annotated[
        collection_list_ref.CollectionListReference | None,
        Field(
            description='Reference to a collection list for including specific collections (programs, shows) within this product. The package runs on the intersection of matched collections and this list. Use for inclusion-based collection targeting. Seller must declare support in get_adcp_capabilities.'
        ),
    ] = None
    collection_list_exclude: Annotated[
        collection_list_ref.CollectionListReference | None,
        Field(
            description="Reference to a collection list for excluding specific collections (programs, shows) from this product. Matched collections must not carry the buyer's ads. Use for brand safety do-not-air lists. Seller must declare support in get_adcp_capabilities."
        ),
    ] = None
    age_restriction: Annotated[
        AgeRestriction | None,
        Field(
            description='Age restriction for compliance. Use for legal requirements (alcohol, gambling), not audience targeting.'
        ),
    ] = None
    device_platform: Annotated[
        list[device_platform_1.DevicePlatform] | None,
        Field(
            description='Restrict to specific platforms. Use for technical compatibility (app only works on iOS). Values from Sec-CH-UA-Platform standard, extended for CTV.',
            min_length=1,
        ),
    ] = None
    device_type: Annotated[
        list[device_type_1.DeviceType] | None,
        Field(
            description='Restrict to specific device form factors. Use for campaigns targeting hardware categories rather than operating systems (e.g., mobile-only promotions, CTV campaigns).',
            min_length=1,
        ),
    ] = None
    device_type_exclude: Annotated[
        list[device_type_1.DeviceType] | None,
        Field(
            description='Exclude specific device form factors from delivery (e.g., exclude CTV for app-install campaigns).',
            min_length=1,
        ),
    ] = None
    store_catchments: Annotated[
        list[StoreCatchment] | None,
        Field(
            description='Target users within store catchment areas from a synced store catalog. Each entry references a store-type catalog and optionally narrows to specific stores or catchment zones.',
            min_length=1,
        ),
    ] = None
    geo_proximity: Annotated[
        list[GeoProximityItem] | None,
        Field(
            description='Target users within travel time, distance, or a custom boundary around arbitrary geographic points. Multiple entries use OR semantics — a user within range of any listed point is eligible. For campaigns targeting 10+ locations, consider using store_catchments with a location catalog instead. Seller must declare support in get_adcp_capabilities.',
            min_length=1,
        ),
    ] = None
    language: Annotated[
        list[LanguageItem] | None,
        Field(
            description="Restrict to users with specific language preferences. ISO 639-1 codes (e.g., 'en', 'es', 'fr').",
            min_length=1,
        ),
    ] = None
    keyword_targets: Annotated[
        list[KeywordTarget] | None,
        Field(
            description='Keyword targeting for search and retail media platforms. Restricts delivery to queries matching the specified keywords. Each keyword is identified by the tuple (keyword, match_type) — the same keyword string with different match types are distinct targets. Sellers SHOULD reject duplicate (keyword, match_type) pairs within a single request. Seller must declare support in get_adcp_capabilities.',
            min_length=1,
        ),
    ] = None
    negative_keywords: Annotated[
        list[NegativeKeyword] | None,
        Field(
            description='Keywords to exclude from delivery. Queries matching these keywords will not trigger the ad. Each negative keyword is identified by the tuple (keyword, match_type). Seller must declare support in get_adcp_capabilities.',
            min_length=1,
        ),
    ] = None

Base model for AdCP types with spec-compliant serialization.

Defaults to extra='ignore' so unknown fields from newer spec versions are silently dropped rather than causing validation errors. Generated types whose schemas set additionalProperties: true override this with extra='allow' in their own model_config.

Set ADCP_STRICT_VALIDATION=1 in the environment ("1", "true", "yes", "on" are accepted) to flip the default to extra='forbid'. Use this during spec upgrades to catch silently-dropped renamed fields in tests. See :func:_resolve_extra_policy.

Important

The env var is resolved once at module import time. Set it in your shell or CI environment before import adcp runs — mutating os.environ["ADCP_STRICT_VALIDATION"] after the first adcp import has no effect on already-imported model classes (they captured the policy at class-body evaluation).

Consumers who want per-model strict validation can override model_config on their subclass.

Create a new model by parsing and validating input data from keyword arguments.

Raises [ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.

self is explicitly positional-only to allow self as a field name.

Ancestors

Class variables

var age_restriction : adcp.types.generated_poc.core.targeting.AgeRestriction | None
var audience_exclude : list[str] | None
var audience_include : list[str] | None
var axe_exclude_segment : str | None
var axe_include_segment : str | None
var collection_list : adcp.types.generated_poc.core.collection_list_ref.CollectionListReference | None
var collection_list_exclude : adcp.types.generated_poc.core.collection_list_ref.CollectionListReference | None
var daypart_targets : list[adcp.types.generated_poc.core.daypart_target.DaypartTarget] | None
var device_platform : list[adcp.types.generated_poc.enums.device_platform.DevicePlatform] | None
var device_type : list[adcp.types.generated_poc.enums.device_type.DeviceType] | None
var device_type_exclude : list[adcp.types.generated_poc.enums.device_type.DeviceType] | None
var frequency_cap : adcp.types.generated_poc.core.frequency_cap.FrequencyCap | None
var geo_countries : list[adcp.types.generated_poc.core.targeting.GeoCountry] | None
var geo_countries_exclude : collections.abc.Sequence[adcp.types.generated_poc.core.targeting.GeoCountriesExcludeItem] | None
var geo_metros : list[adcp.types.generated_poc.core.targeting.GeoMetro] | None
var geo_metros_exclude : collections.abc.Sequence[adcp.types.generated_poc.core.targeting.GeoMetrosExcludeItem] | None
var geo_postal_areas : list[adcp.types.generated_poc.core.postal_area.PostalArea] | None
var geo_postal_areas_exclude : collections.abc.Sequence[adcp.types.generated_poc.core.postal_area.PostalArea] | None
var geo_proximity : list[adcp.types.generated_poc.core.targeting.GeoProximityItem] | None
var geo_regions : list[adcp.types.generated_poc.core.targeting.GeoRegion] | None
var geo_regions_exclude : collections.abc.Sequence[adcp.types.generated_poc.core.targeting.GeoRegionsExcludeItem] | None
var keyword_targets : list[adcp.types.generated_poc.core.targeting.KeywordTarget] | None
var language : list[adcp.types.generated_poc.core.targeting.LanguageItem] | None
var model_config
var negative_keywords : list[adcp.types.generated_poc.core.targeting.NegativeKeyword] | None
var property_list : adcp.types.generated_poc.core.property_list_ref.PropertyListReference | None
var signal_targeting : list[adcp.types.generated_poc.core.signal_targeting.SignalTargeting] | None
var signal_targeting_groups : adcp.types.generated_poc.core.package_signal_targeting_groups.PackageSignalTargetingGroups | None
var store_catchments : list[adcp.types.generated_poc.core.targeting.StoreCatchment] | None

Inherited members

class UpdateMediaBuyRequest (**data: Any)
Expand source code
class UpdateMediaBuyRequest(AdcpVersionEnvelope):
    model_config = ConfigDict(
        extra='allow',
    )
    account: Annotated[
        account_ref.AccountReference,
        Field(
            description='Account that owns this media buy. Pass a natural key (brand, operator, optional sandbox) or a seller-assigned account_id from list_accounts. Required for governance checks and account resolution.'
        ),
    ]
    media_buy_id: Annotated[str, Field(description="Seller's ID of the media buy to update")]
    revision: Annotated[
        int | None,
        Field(
            description="Expected current revision for optimistic concurrency. Optional for backward compatibility. When provided, sellers MUST reject the update with CONFLICT if the media buy's current revision does not match, and MUST enforce that comparison atomically with the write. Obtain from get_media_buys or the most recent create/update response.",
            ge=1,
        ),
    ] = None
    paused: Annotated[
        bool | None,
        Field(description='Pause/resume the entire media buy (true = paused, false = active)'),
    ] = None
    canceled: Annotated[
        Literal[True] | None,
        Field(
            description='Cancel the entire media buy. Cancellation is irreversible — canceled media buys cannot be reactivated. Sellers MAY reject with NOT_CANCELLABLE if the media buy cannot be canceled in its current state.'
        ),
    ] = None
    cancellation_reason: Annotated[
        str | None,
        Field(
            description='Reason for cancellation. Sellers SHOULD store this and return it in subsequent get_media_buys responses.',
            max_length=500,
        ),
    ] = None
    start_time: start_timing.StartTiming | None = None
    end_time: Annotated[
        AwareDatetime | None, Field(description='New end date/time in ISO 8601 format')
    ] = None
    packages: Annotated[
        Sequence[package_update.PackageUpdate] | None,
        Field(description='Package-specific updates for existing packages', min_length=1),
    ] = None
    invoice_recipient: Annotated[
        business_entity.BusinessEntity | None,
        Field(
            description="Update who receives the invoice for this buy. When provided, the seller invoices this entity instead of the account's default billing_entity. The seller MUST validate the invoice recipient is authorized for this account. When governance_agents are configured, the seller MUST include invoice_recipient in the check_governance request."
        ),
    ] = None
    new_packages: Annotated[
        list[package_request.PackageRequest] | None,
        Field(
            description='New packages to add to this media buy. Uses the same schema as create_media_buy packages. Sellers that support mid-flight package additions advertise `add_packages` in both `valid_actions[]` (deprecated) and as an entry in `available_actions[]` (authoritative). Sellers that do not support this MUST reject with ACTION_NOT_ALLOWED (preferred) or UNSUPPORTED_FEATURE (legacy).',
            min_length=1,
        ),
    ] = None
    reporting_webhook: Annotated[
        reporting_webhook_1.ReportingWebhook | None,
        Field(
            description='Optional webhook configuration for automated reporting delivery. Updates the reporting configuration for this media buy.'
        ),
    ] = None
    push_notification_config: Annotated[
        push_notification_config_1.PushNotificationConfig | None,
        Field(
            description='Optional webhook configuration for async update notifications. Publisher will send webhook when update completes if operation takes longer than immediate response time. This is separate from reporting_webhook which configures ongoing campaign reporting.'
        ),
    ] = None
    idempotency_key: Annotated[
        str,
        Field(
            description='Client-generated idempotency key for safe retries. If an update fails without a response, resending with the same idempotency_key guarantees the update is applied at most once. MUST be unique per (seller, request) pair to prevent cross-seller correlation. Use a fresh UUID v4 for each request.',
            max_length=255,
            min_length=16,
            pattern='^[A-Za-z0-9_.:-]{16,255}$',
        ),
    ]
    context: context_1.ContextObject | None = None
    ext: ext_1.ExtensionObject | None = None

Base model for AdCP types with spec-compliant serialization.

Defaults to extra='ignore' so unknown fields from newer spec versions are silently dropped rather than causing validation errors. Generated types whose schemas set additionalProperties: true override this with extra='allow' in their own model_config.

Set ADCP_STRICT_VALIDATION=1 in the environment ("1", "true", "yes", "on" are accepted) to flip the default to extra='forbid'. Use this during spec upgrades to catch silently-dropped renamed fields in tests. See :func:_resolve_extra_policy.

Important

The env var is resolved once at module import time. Set it in your shell or CI environment before import adcp runs — mutating os.environ["ADCP_STRICT_VALIDATION"] after the first adcp import has no effect on already-imported model classes (they captured the policy at class-body evaluation).

Consumers who want per-model strict validation can override model_config on their subclass.

Create a new model by parsing and validating input data from keyword arguments.

Raises [ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.

self is explicitly positional-only to allow self as a field name.

Ancestors

  • adcp.types.generated_poc.core.version_envelope.AdcpVersionEnvelope
  • AdCPBaseModel
  • pydantic.main.BaseModel

Class variables

var account : adcp.types.generated_poc.core.account_ref.AccountReference
var canceled : Literal[True] | None
var cancellation_reason : str | None
var context : adcp.types.generated_poc.core.context.ContextObject | None
var end_time : pydantic.types.AwareDatetime | None
var ext : adcp.types.generated_poc.core.ext.ExtensionObject | None
var idempotency_key : str
var invoice_recipient : adcp.types.generated_poc.core.business_entity.BusinessEntity | None
var media_buy_id : str
var model_config
var new_packages : list[adcp.types.generated_poc.media_buy.package_request.PackageRequest] | None
var packages : collections.abc.Sequence[adcp.types.generated_poc.media_buy.package_update.PackageUpdate] | None
var paused : bool | None
var push_notification_config : adcp.types.generated_poc.core.push_notification_config.PushNotificationConfig | None
var reporting_webhook : adcp.types.generated_poc.core.reporting_webhook.ReportingWebhook | None
var revision : int | None
var start_time : adcp.types.generated_poc.core.start_timing.StartTiming | None

Inherited members

class VerifyBrandClaimsRequest (**data: Any)
Expand source code
class VerifyBrandClaimsRequest(VerifyBrandClaimsRequestBulk):
    pass

Base model for AdCP types with spec-compliant serialization.

Defaults to extra='ignore' so unknown fields from newer spec versions are silently dropped rather than causing validation errors. Generated types whose schemas set additionalProperties: true override this with extra='allow' in their own model_config.

Set ADCP_STRICT_VALIDATION=1 in the environment ("1", "true", "yes", "on" are accepted) to flip the default to extra='forbid'. Use this during spec upgrades to catch silently-dropped renamed fields in tests. See :func:_resolve_extra_policy.

Important

The env var is resolved once at module import time. Set it in your shell or CI environment before import adcp runs — mutating os.environ["ADCP_STRICT_VALIDATION"] after the first adcp import has no effect on already-imported model classes (they captured the policy at class-body evaluation).

Consumers who want per-model strict validation can override model_config on their subclass.

Create a new model by parsing and validating input data from keyword arguments.

Raises [ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.

self is explicitly positional-only to allow self as a field name.

Ancestors

  • adcp.types.generated_poc.brand.verify_brand_claims_request.VerifyBrandClaimsRequestBulk
  • adcp.types.generated_poc.core.version_envelope.AdcpVersionEnvelope
  • AdCPBaseModel
  • pydantic.main.BaseModel

Class variables

var model_config

Inherited members