Module adcp.types.domains.core.package

Classes

class Cancellation (**data: Any)
Expand source code
class Cancellation(AdCPBaseModel):
    model_config = ConfigDict(
        extra='forbid',
    )
    canceled_at: Annotated[
        AwareDatetime, Field(description='ISO 8601 timestamp when this package was canceled.')
    ]
    canceled_by: Annotated[
        canceled_by_1.CanceledBy,
        Field(description='Which party initiated the package cancellation.'),
    ]
    reason: Annotated[
        str | None, Field(description='Reason the package was canceled.', max_length=500)
    ] = None
    acknowledged_at: Annotated[
        AwareDatetime | None,
        Field(
            description='ISO 8601 timestamp when the seller acknowledged the cancellation. Confirms inventory has been released and billing stopped. Absent until the seller processes the cancellation.'
        ),
    ] = 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 acknowledged_at : pydantic.types.AwareDatetime | None
var canceled_at : pydantic.types.AwareDatetime
var canceled_by : CanceledBy
var model_config
var reason : str | None

Inherited members

class Package (**data: Any)
Expand source code
class Package(AdCPBaseModel):
    model_config = ConfigDict(
        extra='allow',
    )
    package_id: Annotated[str, Field(description="Seller's unique identifier for the package")]
    product_id: Annotated[
        str | None,
        Field(
            description="ID of the product this package is based on. For packages created from an explicit create_media_buy package request, sellers MUST echo the request package's product_id on every response package object that represents that requested package."
        ),
    ] = None
    audience_evidence_selections: Annotated[
        list[audience_evidence_selection.AudienceEvidenceSelection] | None,
        Field(
            description='Exact immutable audience-evidence snapshots that affected recommendation, eligibility, or package construction. A confirmed package MUST include a package_construction selection matching every buyer audience_evidence_pin and every snapshot used to satisfy package audience_evidence_requirements; this readback remains mandatory on subsequent package read surfaces. This is decision provenance only; applied targeting remains exclusively in targeting_overlay and targeting_resolution.demographics.',
            min_length=1,
        ),
    ] = None
    budget: Annotated[
        StrictFloat | None,
        Field(
            description='Hard lifetime spend cap for this package in the media-buy currency. Every selected pricing option in an AdCP-authored media buy MUST declare that same currency. In seller-optimized allocation mode this is a ceiling, not a current allocation. May be omitted when the package is bounded only by the shared media-buy total.',
            ge=0.0,
        ),
    ] = None
    min_spend_target: Annotated[
        StrictFloat | None,
        Field(
            description='Soft lifetime spend target accepted for this package under seller-optimized budget allocation. This is an allocation preference, not a billing or delivery guarantee.',
            ge=0.0,
        ),
    ] = None
    daily_budget_cap: Annotated[
        StrictFloat | None,
        Field(
            description="The hard package spend ceiling per shared media-buy cap day, in the media buy's currency. Sellers MUST echo this whenever a package daily cap is set. It is a subordinate ceiling, not a reserved or current allocation; the media buy's budget_cap_timezone defines its day boundary.",
            ge=0.0,
        ),
    ] = None
    pacing: pacing_1.Pacing | None = None
    pricing_option_id: Annotated[
        str | None,
        Field(
            description="ID of the selected pricing option from the product's pricing_options array"
        ),
    ] = None
    bid_price: Annotated[
        StrictFloat | None,
        Field(
            deprecated=True,
            description='DEPRECATED legacy bidding representation. 3.2 sellers normalize accepted legacy input and SHOULD echo bidding instead. Removed in the next major.',
            ge=0.0,
        ),
    ] = None
    bidding: Annotated[
        bidding_policy.BiddingPolicy | None,
        Field(
            description='Package-authored bidding policy, echoed only when the buyer authored a package override. `{automatic:true}` is an explicit automatic-bidding override. Omission means the package inherits media-buy bidding or, when both scopes are absent, uses provider automatic delivery. Monetary fields are denominated in the media-buy currency. Sellers MUST NOT materialize inherited media-buy policy here.'
        ),
    ] = None
    price_breakdown: Annotated[
        price_breakdown_1.PriceBreakdown | None,
        Field(
            description="Breakdown of the effective price for this package. On fixed-price packages, echoes the pricing option's breakdown. On auction packages, shows the clearing price breakdown including any commission or settlement terms."
        ),
    ] = None
    impressions: Annotated[
        StrictFloat | None, Field(description='Impression goal for this package', ge=0.0)
    ] = None
    catalogs: Annotated[
        list[catalog.Catalog] | None,
        Field(
            description='Catalogs this package promotes. Each catalog MUST have a distinct type (e.g., one product catalog, one store catalog). This constraint is enforced at the application level — sellers MUST reject requests containing multiple catalogs of the same type with a validation_error. Echoed from the create_media_buy request.'
        ),
    ] = None
    format_ids: Annotated[
        list[format_id.FormatReferenceStructuredObject] | None,
        Field(
            deprecated=True,
            description='Deprecated in AdCP 3.2; removed in AdCP 4.0. Legacy named-format IDs supplied for this package on create_media_buy. Sellers SHOULD echo this field whenever the request included it, including dual-emission cases where `format_option_refs` was the winning selector, so read surfaces preserve the original wire contract. Omitted means the request did not carry legacy format_ids unless the seller cannot reconstruct legacy requests created before this field was persisted.',
        ),
    ] = None
    format_option_refs: Annotated[
        list[format_option_ref.FormatOptionReference] | None,
        Field(
            description='Structured 3.1+ format option references supplied for this package on create_media_buy. Sellers SHOULD echo this field whenever the request included it. Publisher-catalog-backed options are identified by `{ scope: "publisher", publisher_domain, format_option_id }`; product-local options are identified by `{ scope: "product", format_option_id }` and resolve only against this package\'s target product. Omitted means the request did not carry format_option_refs unless the seller cannot reconstruct legacy requests created before this field was persisted.',
            min_length=1,
        ),
    ] = None
    format_kind: Annotated[
        str | None,
        Field(
            description='Direct canonical selector supplied for this package on create_media_buy. Sellers SHOULD echo this field whenever the request included it, including informational-echo cases where `format_ids` was the winning selector, so read surfaces preserve the original wire contract.'
        ),
    ] = None
    params: Annotated[
        dict[str, Any] | None,
        Field(
            description='Parameters for the direct canonical selector in `format_kind`, echoed from the create_media_buy request whenever the request included it. Requires `format_kind`; omitted only when the request did not carry direct canonical params or when the seller cannot reconstruct legacy requests created before this field was persisted.'
        ),
    ] = None
    targeting_overlay: Annotated[
        targeting.TargetingOverlay | None,
        Field(
            description='Complete effective targeting accepted for this package, including targeting bound through configured product selection plus package-specific targeting. Sellers MUST echo an applied package frequency_cap independently from any MediaBuy root cap. Sellers MUST also echo placement, property, and collection selection so buyers can audit purchased inventory: placements via placement_selection, collections via collection_selection (the committed concrete selectors, materialized even when the selection was produced through collection_list references).'
        ),
    ] = None
    targeting_resolution: Annotated[
        package_targeting_resolution.PackageTargetingResolution | None,
        Field(
            description="Execution details for the package's accepted targeting. Sellers MUST include targeting_resolution.demographics whenever demographic targeting was requested or applied."
        ),
    ] = None
    measurement_terms: Annotated[
        measurement_terms_1.MeasurementTerms | None,
        Field(
            description="Agreed billing measurement and makegood terms for this package. Reflects what was negotiated — may differ from the buyer's proposal or the product's defaults. When present, these terms are binding for the package's duration."
        ),
    ] = None
    performance_standards: Annotated[
        list[performance_standard.PerformanceStandard] | None,
        Field(
            description='Agreed performance standards for this package. When any entry specifies a vendor, creatives assigned to this package MUST include corresponding tracker_script or tracker_pixel assets from that vendor.',
            min_length=1,
        ),
    ] = None
    committed_metrics: Annotated[
        list[committed_metric.CommittedMetric] | None,
        Field(
            description="The binding reporting contract for this package — what the seller has agreed to populate in delivery reports. Each entry carries an explicit `committed_at` timestamp, so the array also serves as the contract amendment ledger: day-1 commitments share `committed_at = create_media_buy.confirmed_at`; mid-flight additions carry their own timestamps. When `create_media_buy.confirmed_at` is null for a provisional buy, sellers MUST omit `committed_metrics` until commitment. The first response that sets `confirmed_at` MAY include the initial committed-metrics set, and each such entry's `committed_at` MUST equal `confirmed_at`. The `missing_metrics` field on `get_media_buy_delivery` reconciles against this list, filtering to entries where `committed_at < reporting_period.end` (a metric committed mid-flight is only audited from its commitment timestamp forward). Sellers stamp the day-1 set on the `create_media_buy` response; mid-flight additions are appended via `update_media_buy` (append-only — sellers MUST reject attempts to modify or remove existing entries with `validation_error`, suggested code: `IMMUTABLE_FIELD`). Optional in v1; absence means the seller does not provide an audit-grade contract and `missing_metrics` falls back to the product's live `available_metrics` (a known audit gap — buyers SHOULD treat absence as 'no audit-grade contract' rather than 'clean delivery'). Each entry uses an explicit `scope` discriminator: `standard` for entries from the closed `available-metric.json` enum, `vendor` for vendor-defined metrics anchored on a BrandRef. Standard entries are symmetric with `by_package[].metric_values`; vendor entries reconcile to `by_package[].vendor_metric_values`; both use `by_package[].missing_metrics` for gaps. The atomic key remains `(scope, metric_id, qualifier)`, with vendor identity included for vendor scope. Replaces the parallel-array design that shipped briefly in #3510.",
            examples=[
                [
                    {
                        'scope': 'standard',
                        'metric_id': 'impressions',
                        'committed_at': '2026-04-29T10:53:00Z',
                    },
                    {
                        'scope': 'standard',
                        'metric_id': 'spend',
                        'committed_at': '2026-04-29T10:53:00Z',
                    },
                    {
                        'scope': 'standard',
                        'metric_id': 'completed_views',
                        'committed_at': '2026-04-29T10:53:00Z',
                    },
                    {
                        'scope': 'vendor',
                        'vendor': {'domain': 'attentionvendor.example'},
                        'metric_id': 'attention_units',
                        'committed_at': '2026-04-29T10:53:00Z',
                    },
                    {
                        'scope': 'standard',
                        'metric_id': 'viewable_rate',
                        'qualifier': {'viewability_standard': 'mrc'},
                        'committed_at': '2026-05-30T14:22:00Z',
                    },
                ]
            ],
            min_length=1,
        ),
    ] = None
    creative_assignments: Annotated[
        list[creative_assignment.CreativeAssignment] | None,
        Field(
            description='Creative assets assigned to this package, including the committed package-scoped rotation policy. Omitted rotation_mode reads as weighted for backward compatibility; all assignments resolve to one effective mode, and sequential positions are unique within each package-local group.'
        ),
    ] = None
    formats_to_provide: Annotated[
        list[package_format_snapshot.PackageFormatSnapshot] | None,
        Field(
            description='Immutable canonical creative contracts established for this package. Each entry is a PackageFormatSnapshot of the selected effective Product format declaration. A package whose selected format carries tracker_execution_contract MUST retain and return this checklist even after creative coverage is complete; the live Product is never substituted for the package snapshot.',
            min_length=1,
        ),
    ] = None
    formats_pending: Annotated[
        list[package_format_snapshot.PackageFormatSnapshot] | None,
        Field(
            description='PackageFormatSnapshot entries from formats_to_provide that do not yet have creative coverage through sync_creatives or inline assignment. Every entry MUST equal its formats_to_provide snapshot after RFC 8785 canonicalization and, when product_snapshot_digest is present, carry the identical digest. An empty emitted array means every required format is covered. Absence means readiness was not reported.'
        ),
    ] = None
    format_ids_to_provide: Annotated[
        list[format_id.FormatReferenceStructuredObject] | None,
        Field(
            deprecated=True,
            description='**DEPRECATED in 3.2.** Legacy named-format projection of formats_to_provide retained for older 3.x peers. New sellers emit canonical formats_to_provide declarations.',
        ),
    ] = None
    format_ids_pending: Annotated[
        list[format_id.FormatReferenceStructuredObject] | None,
        Field(
            deprecated=True,
            description='**DEPRECATED in 3.2.** Legacy named-format projection of formats_pending retained for older 3.x peers. New sellers emit canonical formats_pending declarations. An empty emitted array means every projected requirement is covered. Absence means legacy readiness was not reported and MUST NOT be interpreted as full coverage.',
        ),
    ] = 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
    start_time: Annotated[
        AwareDatetime | None,
        Field(
            description="Flight start date/time for this package in ISO 8601 format. When omitted, the package inherits the media buy's start_time. Sellers SHOULD always include the resolved value in responses, even when inherited."
        ),
    ] = None
    end_time: Annotated[
        AwareDatetime | None,
        Field(
            description="Flight end date/time for this package in ISO 8601 format. When omitted, the package inherits the media buy's end_time. Sellers SHOULD always include the resolved value in responses, even when inherited."
        ),
    ] = None
    paused: Annotated[
        StrictBool | None,
        Field(
            description='Whether this package is paused by the buyer. Paused packages do not deliver impressions. Defaults to false.'
        ),
    ] = False
    canceled: Annotated[
        StrictBool | None,
        Field(
            description='Whether this package has been canceled. Canceled packages stop delivery and cannot be reactivated. Defaults to false.'
        ),
    ] = False
    cancellation: Annotated[
        Cancellation | None,
        Field(description='Cancellation metadata. Present only when canceled is true.'),
    ] = None
    agency_estimate_number: Annotated[
        str | None,
        Field(
            description="Agency estimate or authorization number for this package. Echoed from the buyer's request. When present on the package, takes precedence over the media buy-level estimate number.",
            max_length=100,
        ),
    ] = None
    creative_deadline: Annotated[
        AwareDatetime | None,
        Field(
            description="ISO 8601 timestamp for creative upload or change deadline for this package. After this deadline, creative changes are rejected. When absent, the media buy's creative_deadline applies."
        ),
    ] = None
    context: Annotated[
        context_1.ContextObject | None,
        Field(
            description='Opaque package-level correlation data echoed unchanged in responses, webhooks, and read surfaces. Buyers targeting mixed seller populations SHOULD include a per-package correlation value here, commonly context.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. Sellers MUST preserve this object unchanged and MUST NOT parse it for business logic.'
        ),
    ] = 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

Subclasses

Class variables

var agency_estimate_number : str | None
var audience_evidence_selections : list[AudienceEvidenceSelection] | None
var bid_price : float | None
var bidding : BiddingPolicy | None
var budget : float | None
var canceled : bool | None
var cancellation : Cancellation | None
var catalogs : list[Catalog] | None
var committed_metrics : list[CommittedMetric1 | CommittedMetric2] | None
var context : ContextObject | None
var creative_assignments : list[CreativeAssignment] | None
var creative_deadline : pydantic.types.AwareDatetime | None
var daily_budget_cap : float | None
var end_time : pydantic.types.AwareDatetime | None
var ext : ExtensionObject | None
var format_ids : list[FormatReferenceStructuredObject] | None
var format_ids_pending : list[FormatReferenceStructuredObject] | None
var format_ids_to_provide : list[FormatReferenceStructuredObject] | None
var format_kind : str | None
var format_option_refs : list[FormatOptionReference1 | FormatOptionReference2] | None
var formats_pending : list[PackageFormatSnapshot18 | PackageFormatSnapshot19 | PackageFormatSnapshot20 | PackageFormatSnapshot21 | PackageFormatSnapshot22 | PackageFormatSnapshot23 | PackageFormatSnapshot24 | PackageFormatSnapshot25 | PackageFormatSnapshot26 | PackageFormatSnapshot27 | PackageFormatSnapshot28 | PackageFormatSnapshot29 | PackageFormatSnapshot30 | PackageFormatSnapshot31 | PackageFormatSnapshot32 | PackageFormatSnapshot33] | None
var formats_to_provide : list[PackageFormatSnapshot18 | PackageFormatSnapshot19 | PackageFormatSnapshot20 | PackageFormatSnapshot21 | PackageFormatSnapshot22 | PackageFormatSnapshot23 | PackageFormatSnapshot24 | PackageFormatSnapshot25 | PackageFormatSnapshot26 | PackageFormatSnapshot27 | PackageFormatSnapshot28 | PackageFormatSnapshot29 | PackageFormatSnapshot30 | PackageFormatSnapshot31 | PackageFormatSnapshot32 | PackageFormatSnapshot33] | None
var impressions : float | None
var measurement_terms : MeasurementTerms | None
var min_spend_target : float | None
var model_config
var optimization_goals : list[OptimizationGoal8 | OptimizationGoal9 | OptimizationGoal10] | None
var pacing : Pacing | None
var package_id : str
var params : dict[str, typing.Any] | None
var paused : bool | None
var performance_standards : list[PerformanceStandard] | None
var price_breakdown : PriceBreakdown | None
var pricing_option_id : str | None
var product_id : str | None
var start_time : pydantic.types.AwareDatetime | None
var targeting_overlay : TargetingOverlay | None
var targeting_resolution : PackageTargetingResolution | None

Inherited members