Skip to main content

Overview

A Media Buy represents one ADCP transaction with one sales agent. It is not a directly-creatable resource — the platform spawns media buys when a Campaign executes, creating one media buy per sales agent for each selected product. You read their status and tune them through the campaign update endpoint, never by creating or posting them directly.
Media buys are spawned at execution, not before. A DRAFT campaign has no media buys. After POST /campaigns/:id/execute, the campaign holds a mediaBuys[] array — one entry per sales agent.

Where a media buy sits in the hierarchy

A campaign fans out into media buys, each of which fans out into packages, each of which delivers:
Campaign
└── Media Buy        (one per sales agent)
    └── Package      (one per product per pacing period)
        └── Delivery (impressions, spend, clicks)
See Package for the per-product, per-pacing-period unit beneath each media buy.

Status

A media buy’s status is one of:
StatusMeaning
DRAFTCreated but not yet submitted
PENDING_APPROVALSubmitted; awaiting seller approval
INPUT_REQUIREDSeller needs additional information before approval can proceed
ACTIVELive and delivering
PAUSEDSpend halted; resumable
COMPLETEDFlight finished or fully delivered
CANCELEDStopped before completion
FAILEDSubmission or execution error
REJECTEDSeller declined the buy
ARCHIVEDSoft-deleted

Most-restrictive rule

For a multi-agent campaign, the surfaced status is the most restrictive across all agents. For example, if one media buy is ACTIVE and another is PENDING_APPROVAL, the campaign reports PENDING_APPROVAL. INPUT_REQUIRED signals that a seller is blocked waiting on more information.

How status flows

Status updates reach you two ways:
  • Webhooks from sales agents — preferred, near-real-time. No polling needed.
  • Polling via GET /api/v2/buyer/campaigns/:id/media-buy-status, which queries each agent directly and persists any changes.
curl https://api.interchange.io/api/v2/buyer/campaigns/cmp_987654321/media-buy-status \
  -H "Authorization: Bearer $SCOPE3_API_KEY"
Polling is most useful right after execution, while you wait on publisher approvals. Once webhooks are flowing, prefer them — see Get media buy status.

Optimization goals

Optimization goals are applied at the media-buy level — they propagate to every package in the media buy at execution time. Each goal is either event-based (optimize against tracked conversions) or metric-based (optimize against seller-native delivery metrics).
{
  "kind": "event",
  "event_sources": [
    { "event_source_id": "website_pixel", "event_type": "purchase", "value_field": "value" }
  ],
  "target": { "kind": "cost_per", "value": 25.0 }
}

Target kinds

Target kindMeaning
cost_perTarget CPA (events) or CPM-like rate (metrics)
per_ad_spendTarget ROAS — value per dollar spent (events only)
maximize_valueNo target — maximize total event value within budget
threshold_rateMaintain a minimum rate of the metric (metrics only)

Supported metrics

clicks, views, completed_views, viewed_seconds, attention_seconds, attention_score, engagements, follows, saves, profile_visits.

Reading and tuning media buys

Because media buys aren’t created directly, you act on them through PUT /api/v2/buyer/campaigns/:id using the mediaBuys[] array. Each entry targets one media buy by mediaBuyId and carries an action. When lowering a campaign’s budget.total, the campaign update automatically reduces live package budgets proportionally if the new media budget would otherwise be below current package allocations. Provide explicit mediaBuys[].packages[].budget values only when you want specific package-level amounts instead of proportional scaling.
ActionEffect
updateDefault — modify budget, pacing, optimization goals, or creatives
cancelCancel a running media buy
deleteArchive the media buy

Update budget and optimization goals

{
  "mediaBuys": [
    {
      "action": "update",
      "mediaBuyId": "mb_abc123",
      "packages": [
        { "packageId": "pkg_1", "budget": 15000, "pacing": "even" }
      ],
      "optimization_goals": [
        { "kind": "metric", "metric": "completed_views", "target": { "kind": "cost_per", "value": 0.08 } }
      ],
      "updated_reason": "Mid-flight optimization based on early performance"
    }
  ]
}
Always confirm optimization_goals with the buyer before changing them — silent goal changes break optimization continuity.

Cancel a single package

To cancel one package without touching the rest of the media buy, pass packageIds on the mediaBuys[] entry:
{
  "mediaBuys": [
    {
      "action": "cancel",
      "mediaBuyId": "mb_abc123",
      "packageIds": ["pkg_2"],
      "reason": "format not supported on this device mix"
    }
  ]
}
See Package for what each package represents.

Override creative attachment

By default, a campaign’s manifest-linked creatives auto-sync to every media buy on update, filtered to the formats accepted by each buy’s products. Pass creative_ids on a mediaBuys[] entry to override that per-buy:
{
  "mediaBuys": [
    {
      "action": "update",
      "mediaBuyId": "mb_abc123",
      "creative_ids": ["cr_video_15s", "cr_video_30s"]
    }
  ]
}
  • Omit creative_ids to use auto-sync (default).
  • "creative_ids": [] explicitly clears all creatives from the media buy.
  • Each ID must already be linked to the campaign and match a format accepted by the media buy’s products. Otherwise the update fails with a validation error — the field is not silently filtered.
  • creative_ids is only valid with action: "update". It is rejected with cancel or delete.

Cascade behavior

Actions on the parent campaign cascade down to its media buys and packages:
  • Campaign pause halts every media buy and package.
  • Campaign reactivate brings them back to ACTIVE (post-flight if dates allow).
  • Creative manifest update re-syncs to every media buy that uses the format.
  • Property list update propagates to packages without a full re-execute.
  • Frequency caps on the campaign or advertiser are enforced across all media buys.

Failures and debug

When a media buy fails to execute — a publisher rejection or an ADCP error — POST /api/v2/buyer/campaigns/:id/execute returns structured errors[]:
{
  "campaignId": "cmp_987654321",
  "previousStatus": "DRAFT",
  "newStatus": "ACTIVE",
  "success": false,
  "errors": [
    {
      "mediaBuyId": "mb_abc123",
      "salesAgentId": "agent_xyz",
      "message": "Sales agent returned 422: invalid format for product"
    }
  ]
}
Pass debug: true on execute to include the full ADCP request, response, and A2A debug logs in each error entry.

Campaign

The parent media plan that spawns media buys at execution

Package

One per product per pacing period, beneath each media buy

Get media buy status

Poll live ADCP status across sales agents

Update campaign

The endpoint that reads and tunes media buys