Skip to main content
Create a media buy from selected packages or execute a proposal. Handles validation, approval if needed, and campaign creation. Supports two modes:
  • Manual Mode: Provide packages array with explicit line item configurations
  • Proposal Mode: Provide proposal_id and total_budget to execute a proposal from get_products
Response Time: Instant to days (returns completed, working < 120s, or submitted for hours/days) Request Schema: /schemas/v3/media-buy/create-media-buy-request.json Response Schema: /schemas/v3/media-buy/create-media-buy-response.json

Quick Start

Create a simple media buy with two packages:

Request Parameters

* Either packages OR (proposal_id + total_budget) must be provided. When executing a proposal, proposal_status on the returned proposal determines whether create_media_buy is valid. committed proposals can be executed before expires_at; draft proposals require a prior get_products refine call with action: "finalize". Finalization is seller commitment to firm terms, not buyer acceptance. This create_media_buy call is the acceptance/execution step.

TotalBudget Object

Package Object

Response

Success Response

confirmed_at is seller commitment time, not a delivery-status timestamp. Do not update it when a buy later pauses, resumes, starts delivery, completes, or reports performance. A committed synchronous create stamps it immediately. Use the submitted response branch when no media_buy_id is being returned to the buyer. Sellers MAY instead return synchronous success with media_buy_id, packages, and confirmed_at: null for a provisional buy; such buys MUST be retrievable via get_media_buys and MUST transition by setting confirmed_at exactly once on commitment. A provisional buy with confirmed_at: null MUST NOT be active and MUST NOT include packages[].committed_metrics.

Reporting contract on confirmed packages

Each package in the response MAY carry committed_metrics — the binding reporting contract the seller has agreed to populate in delivery reports for this package. The field is a unified array carrying both standard metrics (from the closed available-metric.json enum) and vendor-defined metrics (anchored on a BrandRef), with each entry tagged by an explicit scope discriminator and timestamped via committed_at: When confirmed_at is null, sellers MUST omit packages[].committed_metrics. 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.
How the contract works:
  • Day-1 entries share committed_at = confirmed_at. The seller stamps the day-1 set on the create_media_buy response based on what they’re prepared to deliver from the product’s reporting_capabilities.
  • Mid-flight additions are appended via update_media_buy — append-only with their own committed_at timestamps. This lets a seller honestly say “Adelaide attention is now part of the contract from day 30 onward” without having to cancel and reissue the buy.
  • Existing entries are immutable. Sellers MUST reject update_media_buy requests that attempt to modify or remove existing entries with a validation_error (suggested code: IMMUTABLE_FIELD). New entries can be appended.
  • Qualifiers on standard metrics. Some metrics have multiple incompatible measurement paths and need disambiguation:
    • viewability_standard — when metric_id is one of viewable_impressions, viewable_rate, measurable_impressions and the seller commits to a specific viewability standard (MRC and GroupM are materially different thresholds — see the viewability-standard enum), the entry MUST carry qualifier.viewability_standard. Symmetric on missing_metrics: a buyer expecting MRC viewability flags a GroupM-only delivery report as missing the MRC commitment.
    • completion_source — when metric_id is completion_rate and the seller commits to a specific source (the player/ad server’s own completion event vs. a third-party measurement vendor anchored on performance_standard.vendor), the entry MUST carry qualifier.completion_source (seller_attested or vendor_attested). The two paths can yield materially different rates, particularly in SSAI environments. Symmetric on missing_metrics.
    • attribution_methodology — when metric_id is an outcome metric (conversions, conversion_value, roas, cost_per_acquisition, incremental_sales_lift, brand_lift, foot_traffic, conversion_lift, brand_search_lift, units_sold, new_to_brand_rate, new_to_brand_units, leads) and the seller commits to a specific attribution methodology, the entry SHOULD carry qualifier.attribution_methodology (deterministic_purchase for retail-media closed-loop; probabilistic, panel_based, or modeled for other paths). Two outcome rows under different methodologies are not interchangeable; symmetric on missing_metrics.
    • attribution_window — when metric_id is an outcome metric and the seller commits to a specific lookback window, the entry SHOULD carry qualifier.attribution_window as a structured duration ({ interval: 14, unit: "days" }). Two outcome rows over different windows are reported as separate rows so buyers don’t accidentally aggregate across periods.
    Without the qualifier, the contract is ambiguous and reconciliation falls back to whatever the delivery report happens to carry. The qualifier vocabulary is closed (additionalProperties: false); new keys ship explicitly in subsequent minors.
  • Reconciliation: missing_metrics on get_media_buy_delivery filters committed_metrics to entries where committed_at < reporting_period.end, then flags any that aren’t populated in the report. A metric committed mid-flight is only audited from its commitment timestamp forward. Qualifiers are matched verbatim — a committed {viewable_rate, mrc} is not satisfied by a delivered viewable_rate carrying viewability.standard: groupm.
  • Optional in v1. Sellers without per-package snapshot infrastructure can adopt incrementally. Absence is conformant but carries a known audit gap: without the snapshot, missing_metrics reconciles against the product’s live available_metrics at report time, which may not reflect what was committed at create time. Sellers that omit committed_metrics accept this risk; buyers SHOULD treat absence as “no audit-grade contract” rather than “clean delivery.” Expected to become required at the next major.

Error Response

Submitted Response

Returned when the buy cannot be confirmed synchronously — e.g., guaranteed buys awaiting IO signing, governance review queued, or batched processing. The completion artifact (delivered via tasks/get or push-notification webhook) carries media_buy_id and packages. There is no proposal-specific acceptance webhook. Proposal execution that needs human approval, IO signing, or asynchronous processing uses this same submitted task envelope and the standard task/webhook completion path. Note: Responses are mutually exclusive across these three shapes. Dispatch on status first: "submitted" → async envelope, otherwise check errors before accessing success fields.

When to return Submitted vs synchronous Success (normative)

The choice between submitted and synchronous success is per-call, driven by per-product attributes and the seller’s policy on each specific create — not a uniform per-seller rule. A sales-guaranteed seller may legitimately return synchronous success on some create_media_buy calls and submitted on others within the same session; conformant SDK skills MUST NOT instruct agents to return submitted for every create_media_buy regardless of input. Sellers that uniformly return submitted fail the non-IO-approval paths in the sales-guaranteed compliance storyboard. Sellers MUST return submitted when:
  • The request references one or more products with delivery_type: "guaranteed" and the seller declares the requires_io_approval capability — the human-approval handshake cannot complete inside the response. The completion artifact is delivered via tasks/get or webhook once IO signing finishes.
  • The request triggers a seller-side governance review that cannot complete synchronously (e.g., manual brand-safety review for a regulated vertical).
  • The request enters a batched-processing queue the seller cannot drain inside the response timeout.
Sellers MUST return synchronous success when:
  • All referenced products have delivery_type: "non_guaranteed". The buy is created and acknowledged in-line; media_buy_id and packages are issued immediately. This applies regardless of the seller’s specialism — a sales-guaranteed seller serving a non-guaranteed product returns synchronous success.
  • The request references guaranteed products and the seller does NOT declare requires_io_approval (rare; typically retail-SKU or quoted-rate guaranteed flows where the seller has pre-cleared approval).
  • The buy enters a known non-terminal state immediately observable to the buyer (pending_creatives / pending_start / active / paused).
The compliance grader observes both paths against the same seller via separate storyboard scenarios: the create_buy_submitted scenario seeds a guaranteed product with requires_io_approval; four shared scenarios (measurement_terms_rejected, pending_creatives_to_start, inventory_list_targeting, invalid_transitions) seed non-guaranteed products and expect synchronous media_buy_id returns. Sellers that return submitted on the synchronous-expected scenarios fail compliance — see sales-guaranteed specialism for the fixture pattern (non-guaranteed products listed first so open-brief get_products calls resolve to a synchronous-create path). This rule resolves the skill ↔ storyboard contradiction tracked at #3822: an SDK skill that instructs agents to “return a task envelope for every create_media_buy” is non-conformant; the correct skill instructs agents to dispatch on per-product delivery_type and the seller’s requires_io_approval capability.

Common Scenarios

Campaign with Targeting

Add geographic restrictions and frequency capping:

Campaign with Conversion Optimization

Set a per_ad_spend target for conversion-optimized delivery. The product must declare support in conversion_tracking.supported_targets, and you must have an event source configured via sync_event_sources:

Catalog-driven packages

A catalog-driven package allocates a single budget envelope to an entire catalog of items. Instead of creating separate packages per item, the platform optimizes delivery across all catalog items based on performance. This is the AdCP equivalent of catalog-based campaign types such as Google Performance Max or Meta Dynamic Product Ads. Include the catalogs field in a package to make it catalog-driven. Each catalog should have a distinct type (e.g., one product catalog, one store catalog). The referenced catalogs must already be synced via sync_catalogs. Job campaign with synced job catalog:
test=false
Retail media with product catalog and store catchment targeting:
test=false
The platform distributes budget across catalog items based on performance. For per-item reporting, use get_media_buy_delivery which returns by_catalog_item breakdowns. Creative variants for catalog-driven packages represent individual catalog items rendered as ads. Package with explicit signal targeting: Use targeting_overlay.signal_targeting_groups when the buyer wants seller-offered signals applied to a specific package. The selected product must set signal_targeting_allowed: true and make the signal eligible through inline signal_targeting_options when present, through get_signals for wholesale products that omit inline options, and through signal_targeting_rules. The grouped expression shape is always used: top-level operator: "all" with child groups using operator: "any" for include groups and operator: "none" for exclusion groups. For simple include-only targeting, send one any group. For binary signals, send value: true in both include and exclusion groups; exclusion is expressed by the parent none group, not by value: false. Signals are referenced with signal_ref: use scope: "product" for a product-local signal option, scope: "data_provider" with data_provider_domain for a signal defined in a data provider’s published adagents.json signals[], or scope: "signal_source" with signal_source_url for a source-native signal. This is distinct from audience_include / audience_exclude, which only reference first-party audiences registered through sync_audiences. Send signal_agent_segment_id only when the selected product option or get_signals result exposed it as a separate execution handle required by the seller. When a creative carries a build-time signal_condition (from build_creative’s signal_conditions fan-out, #5240), assigning it to a package whose signal targeting is incompatible — e.g. a sun creative to a rain-targeted package — is rejected with SIGNAL_TARGETING_INCOMPATIBLE. Compatibility is matched on the same shared signal_ref identity used here. See the signals specification for the normative trafficking-compatibility contract.
test=false
Include plus exclusion example:
test=false

Campaign with Inline Creatives

Upload creatives at the same time as creating the campaign:

Campaign with Reporting Webhook

Receive automated reporting notifications:

Executing a Proposal

Execute a proposal from get_products without manually constructing packages:
When executing a proposal:
  • The publisher converts allocation percentages to actual budgets using total_budget
  • Packages are created automatically based on the proposal’s allocations
  • All other fields (brand, start_time, end_time, etc.) work the same as manual mode
See Proposals for the complete workflow.

Context for Correlation

The context field is an opaque object that sellers echo unchanged in responses and webhooks. Use it to map seller-assigned IDs back to your internal systems without needing to maintain a separate lookup table. Context works at two levels:
  • Media buy level — echoed in the create_media_buy response
  • Package level — echoed in each package’s response, webhooks, and read surfaces, useful for mapping package_id back to your internal line items. For explicit package requests, sellers MUST also echo product_id.
When targeting mixed seller populations, include package context such as context.buyer_ref as a legacy-safe fallback for older sellers that may not echo product_id. Mapping to internal campaign and line item IDs:
test=false
The seller’s response echoes your context back alongside the seller-assigned IDs:
test=false
Sellers must never parse or act on context data — it exists purely for the buyer’s internal use.

Error Handling

Common errors and resolutions: Example error response:

Key Concepts

Format Specification

Each package SHOULD specify the formats it will use, via format_ids[] (legacy named-format path — structured {agent_url, id} references), format_option_refs[] (3.1+ format-option path — references into the product’s format_options[]), or a direct canonical selector (format_kind plus optional params). Omitting all format selectors defaults to all formats supported by the product. Specifying lets the system:
  • Publish placeholder creatives in ad servers
  • Pin exactly what creative assets are needed
  • Validate that the product supports the requested formats
  • Track which assets are missing
Selector precedence is deterministic: format_option_refs[] wins when present; otherwise format_ids[] wins when present; otherwise direct format_kind/params is used; otherwise the package defaults to all product formats. Use format_option_refs[] when the buyer’s codebase reads Product.format_options[] and the product publishes selectable format_option_id values; use format_ids[] when integrating with legacy-format-only sellers or libraries. Use direct format_kind only when the buyer has enough canonical parameters to satisfy the target product declaration without a product-local reference. Dual-emission of format_option_refs[] and format_ids[] is allowed and recommended for buyer SDKs targeting a mixed seller population — see the format_ids row above. 3.1+ format-option example (buyer authoring against a publisher-scoped Product.format_options[] entry):
test=false
See Format Workflow below for complete details.

Brand reference

The brand field identifies the advertiser for policy compliance and business purposes.
Full brand identity data (colors, fonts, product catalog) is resolved from brand.json at execution time. See brand.json.

Pricing & Currency

Each package specifies its pricing_option_id, which determines:
  • Currency (USD, EUR, etc.)
  • Pricing model (CPM, CPCV, CPP, etc.)
  • Rate and whether it’s fixed or auction-based
Packages can use different currencies when sellers support it. See Pricing Models.

Targeting Overlays

Use sparingly - most targeting should be in your brief and handled through product selection. Use overlays only for:
  • Geographic restrictions (RCT testing, regulatory compliance)
  • Frequency capping
  • AXE segment inclusion/exclusion (legacy — new integrations use TMP)
See Targeting for details.

Format Workflow

Why Format Specification Matters

When creating a media buy, format specification enables:
  1. Placeholder Creation - Publisher creates placeholders in ad server with correct specs
  2. Validation - System validates products support requested formats
  3. Clear Expectations - Both parties know exactly what’s needed
  4. Progress Tracking - Track which assets are missing vs. required
  5. Technical Setup - Ad server configured before creatives arrive

Complete Workflow

Format Validation

Publishers MUST validate:
  • All formats are supported by the product
  • Format specifications match list_creative_formats output
  • Creative requirements can be fulfilled within timeline
Invalid legacy named-format example:
Invalid 3.1+ format-option example:

Flight date validation

For new media buys, the top-level start_time MUST be either "asap" or a date-time that is not in the past. A past concrete start_time MUST return an INVALID_REQUEST error. When a package specifies start_time or end_time, sellers SHOULD validate that:
  • Both dates fall within the media buy’s date range
  • start_time is before end_time
Out-of-range or inverted dates SHOULD return an INVALID_REQUEST error:

Asynchronous Operations

This task can complete instantly or take days depending on complexity and approval requirements. The response includes a status field that tells you what happened and what to do next. Note: For the complete status list see Task Lifecycle.

Immediate Success (completed)

The task completed synchronously. No async handling needed.Request:
test=false
Response:
The top-level status is the envelope task-status (TaskStatus) — completed on synchronous success. The body-level media_buy_status carries the buy’s lifecycle state (pending_creatives, pending_start, active, or paused). A 3.0-style response would have collided these two enums at the same root key; in 3.1 they are distinct fields. Sellers MAY continue to emit a deprecated top-level status: MediaBuyStatus during the 3.1 deprecation window for back-compat with 3.0 buyers, but 3.1 buyers MUST prefer media_buy_status. See Media-buy status field (3.1 migration) below.

Long-Running (submitted)

The task is queued for manual approval. Configure a webhook to receive updates.Request with webhook:
test=false
Initial response:
Webhook POST when approved:

Error (failed)

Response:
For complete async handling patterns, see Async Operations.

Usage Notes

  • Total budget is distributed across packages based on individual budget values
  • Creative assets must be uploaded before deadline for campaign activation
  • Impression-time targeting (audience, frequency, suitability) is handled by TMP
  • Pending states (working, submitted) are normal, not errors
  • Orchestrators MUST handle pending states as part of normal workflow
  • Inline creatives: The creatives array creates or supplies package creatives inline. If the seller advertises creative.has_creative_library: true, inline creatives enter the library; use sync_creatives to update existing library creatives and creative_assignments to assign existing library creatives. If the seller advertises inline_creative_management: true without a creative library, use packages[].creatives on create_media_buy and update_media_buy; do not call sync_creatives.
  • Inline creative lifecycle: Library-backed inline creatives enter the library with the same lifecycle as sync_creatives uploads. Inline-only sellers may keep the creative package-scoped and do not advertise later reuse by creative_id. Creative review is independent of the buy outcome; sellers MUST NOT skip review solely because the buy did not activate. Retention of unassigned library creatives is seller-defined in 3.0. See Inline creatives on the package.

Content Standards

When a media buy includes content standards (via the governance.content_standards field on get_products responses or the media buy request), the buyer is requesting brand suitability enforcement during delivery.
Content standards are created by calling create_content_standards on a verification agent (e.g., IAS, DoubleVerify). Standards MUST be calibrated with each seller before use in production to ensure the seller’s local evaluation model aligns with the verification agent’s interpretation. See the Content Standards overview for the full setup workflow: create → calibrate → activate → validate.

Policy Compliance

Brand and products are validated during creation. Policy violations return errors:
Publishers should ensure:
  • Brand/products align with selected packages
  • Creatives match declared brand/products
  • Campaign complies with all advertising policies

Next Steps

After creating a media buy:
  1. Supply creatives: Use sync_creatives for library-backed sellers, or packages[].creatives on update_media_buy for inline-only sellers
  2. Monitor Status: Use get_media_buy_delivery
  3. Optimize: Use provide_performance_feedback
  4. Update: Use update_media_buy to modify campaign

Media-buy status field (3.1 migration)

3.1 splits two enums that 3.0 collided at the same root key — envelope status (TaskStatus) at the top of every response, and body media_buy_status (MediaBuyStatus, new in 3.1) carrying the buy’s lifecycle state alongside. The legacy top-level status: MediaBuyStatus form is deprecated: true in 3.1 and removed in 3.2 (#4906); nested status on get_media_buys, get_media_buy_delivery, and core/media-buy.json follow in 4.0 (#4905). 3.1 buyers MUST prefer media_buy_status when present. 3.1 compliance storyboards assert path: "media_buy_status" — a 3.1 seller emitting only the legacy status is schema-valid but fails certification; the storyboard is the binding conformance check. Full migration: Migration › media_buy_status.

Learn More