> ## Documentation Index
> Fetch the complete documentation index at: https://agenticadvertisingorg-fix-release-bump-classification.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# get_media_buy_delivery

> get_media_buy_delivery task — retrieve impressions, spend, pacing, and dimensional breakdowns for active AdCP campaigns. Supports custom date ranges and metric filtering.

Retrieve comprehensive delivery metrics and performance data for media buy reporting.

**Response Time**: \~60 seconds (reporting query)

## Scope

`get_media_buy_delivery` works on any `media_buy_id` returned by [`get_media_buys`](/dist/docs/3.0.19/media-buy/task-reference/get_media_buys), regardless of how the underlying campaign was created. Sales agents MUST NOT refuse delivery reporting — or narrow its coverage — on the basis that the buy originated outside AdCP. If delivery data for a buy is genuinely unavailable (e.g., the ad server has not yet reported a flight), the seller returns the buy in `media_buy_deliveries` with zero or partial metrics; the seller does not omit it and does not return `MEDIA_BUY_NOT_FOUND` for an account-owned buy.

**Request Schema**: [`/schemas/3.0.19/media-buy/get-media-buy-delivery-request.json`](https://adcontextprotocol.org/schemas/3.0.19/media-buy/get-media-buy-delivery-request.json)
**Response Schema**: [`/schemas/3.0.19/media-buy/get-media-buy-delivery-response.json`](https://adcontextprotocol.org/schemas/3.0.19/media-buy/get-media-buy-delivery-response.json)

## Request Parameters

| Parameter              | Type                                                                                         | Required | Description                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                     |
| ---------------------- | -------------------------------------------------------------------------------------------- | -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `account`              | [account-ref](/dist/docs/3.0.19/building/by-layer/L2/accounts-and-agents#account-references) | No       | Account reference. Pass `{ "account_id": "..." }` or `{ "brand": {...}, "operator": "..." }` if the seller supports implicit resolution. Only returns media buys belonging to this account. When omitted, returns data across all accessible accounts.                                                                                                                                                                                                                                                                          |
| `media_buy_ids`        | string\[]                                                                                    | No\*     | Array of media buy IDs to retrieve                                                                                                                                                                                                                                                                                                                                                                                                                                                                                              |
| `status_filter`        | string \| string\[]                                                                          | No       | Status filter: `"pending_creatives"`, `"pending_start"`, `"active"`, `"paused"`, `"completed"`. Defaults to `["active"]` when omitted.                                                                                                                                                                                                                                                                                                                                                                                          |
| `start_date`           | string                                                                                       | No       | Report start date (YYYY-MM-DD), inclusive. Omit for campaign lifetime data. Only accepted when product supports `date_range`.                                                                                                                                                                                                                                                                                                                                                                                                   |
| `end_date`             | string                                                                                       | No       | Report end date (YYYY-MM-DD), **exclusive**. Omit for campaign lifetime data. Only accepted when product supports `date_range`.                                                                                                                                                                                                                                                                                                                                                                                                 |
| `reporting_dimensions` | object                                                                                       | No       | Request dimensional breakdowns within `by_package`. Include a key as an empty object (e.g., `"device_type": {}`) to activate with defaults. Keys: `geo`, `device_type`, `device_platform`, `audience`, `placement`. Each accepts optional `limit` (defaults to 25 for geo, audience, placement) and `sort_by` (sort-metric enum, default: `spend`). Geo requires `geo_level` (one per request) and `system` for metro/postal levels. Unsupported dimensions are silently omitted; malformed requests return a validation error. |

> **Date Range Behavior**: The date range is **start-inclusive, end-exclusive**. For example, `start_date: "2026-01-01"` and `end_date: "2026-01-02"` returns delivery data for January 1st only (from `2026-01-01 00:00:00` up to, but not including, `2026-01-02 00:00:00`). To get a full week of data (Jan 1-7), use `end_date: "2026-01-08"`.

**Date Range Examples**:

| start\_date  | end\_date    | Data Returned                    |
| ------------ | ------------ | -------------------------------- |
| `2026-01-01` | `2026-01-02` | January 1st only (1 day)         |
| `2026-01-01` | `2026-01-08` | January 1st through 7th (7 days) |
| `2026-01-01` | `2026-02-01` | Full month of January (31 days)  |
| `2026-01-15` | `2026-01-16` | January 15th only (1 day)        |

\*`media_buy_ids` filters results to specific media buys. If neither provided, returns all media buys in current session context.

## Response

Returns delivery report with aggregated totals and per-media-buy breakdowns:

| Field                  | Description                                                                                                                                                                                                                                          |
| ---------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `reporting_period`     | Date range for report (start/end timestamps)                                                                                                                                                                                                         |
| `currency`             | ISO 4217 currency code (USD, EUR, GBP, etc.)                                                                                                                                                                                                         |
| `attribution_window`   | Attribution methodology: `post_click` and `post_view` (duration objects), and `model` (last\_touch, first\_touch, linear, time\_decay, data\_driven)                                                                                                 |
| `aggregated_totals`    | Combined metrics across all media buys (impressions, spend, clicks, views, completed\_views, conversions, conversion\_value, roas, new\_to\_brand\_rate, cost\_per\_acquisition, completion\_rate, reach, reach\_unit, frequency, media\_buy\_count) |
| `media_buy_deliveries` | Array of delivery data per media buy                                                                                                                                                                                                                 |

### Media Buy Delivery Object

| Field             | Description                                                                                                                                              |
| ----------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `media_buy_id`    | Media buy identifier                                                                                                                                     |
| `status`          | Current status (`pending_creatives`, `pending_start`, `active`, `paused`, `completed`). In webhook context, may also be `reporting_delayed` or `failed`. |
| `totals`          | Aggregate metrics (impressions, spend, clicks, ctr, conversions, conversion\_value, roas, new\_to\_brand\_rate)                                          |
| `by_package`      | Package-level breakdowns with delivery\_status, paused state, and pacing\_index                                                                          |
| `daily_breakdown` | Day-by-day delivery (date, impressions, spend, conversions, conversion\_value, roas, new\_to\_brand\_rate)                                               |

See [schema](https://adcontextprotocol.org/schemas/3.0.19/media-buy/get-media-buy-delivery-response.json) for complete field list.

### Billing-grade vs best-effort numbers

Unless the seller explicitly declares otherwise, `get_media_buy_delivery` returns **best-effort** numbers: real-time or near-real-time telemetry, subject to revision as counts settle, **not** an invoicing source of truth. Callers that use these numbers for client reporting or pacing decisions are safe; callers that use them for reconciliation, accruals, or finance close are not.

Sellers **MAY** declare a finalization window in their capabilities (e.g., `delivery_reporting.finalization_window_hours`) and, once that window has elapsed for a reporting period, treat the numbers returned for that period as authoritative for billing — stable across subsequent calls, suitable for invoice reconciliation, and liable as the source of truth in a dispute. Callers **MUST NOT** assume finalization in the absence of such a declaration.

When a buyer's independent measurement disagrees with these numbers, reconciliation happens out-of-band through the commercial relationship between counterparties, backed by the audit trail on both sides. AdCP 3.0 does not specify a structured dispute task.

## Common Scenarios

### Single Media Buy

<CodeGroup>
  ```javascript JavaScript test=false theme={null}
  import { testAgent } from '@adcp/client/testing';
  import { GetMediaBuyDeliveryResponseSchema } from '@adcp/client';

  // Get single media buy delivery report
  const result = await testAgent.getMediaBuyDelivery({
    media_buy_ids: ['mb_12345'],
    start_date: '2024-02-01',
    end_date: '2024-02-07'
  });

  if (!result.success) {
    throw new Error(`Request failed: ${result.error}`);
  }

  const validated = GetMediaBuyDeliveryResponseSchema.parse(result.data);

  // Check for errors (discriminated union response)
  if ('errors' in validated && validated.errors) {
    throw new Error(`Query failed: ${JSON.stringify(validated.errors)}`);
  }

  console.log(`Delivered ${validated.aggregated_totals.impressions.toLocaleString()} impressions`);
  console.log(`Spend: $${validated.aggregated_totals.spend.toFixed(2)}`);
  if (validated.media_buy_deliveries.length > 0) {
    console.log(`CTR: ${(validated.media_buy_deliveries[0].totals.ctr * 100).toFixed(2)}%`);
  }
  ```

  ```python Python theme={null}
  import asyncio
  from adcp.testing import test_agent
  from adcp.types import GetMediaBuyDeliveryRequest

  async def main():
      # Get single media buy delivery report
      result = await test_agent.get_media_buy_delivery(
          GetMediaBuyDeliveryRequest(
              media_buy_ids=['mb_12345'],
              start_date='2024-02-01',
              end_date='2024-02-07'
          )
      )

      # Check for errors (discriminated union response)
      if hasattr(result, 'errors') and result.errors:
          raise Exception(f"Query failed: {result.errors}")

      print(f"Delivered {result.aggregated_totals.impressions:,} impressions")
      print(f"Spend: ${result.aggregated_totals.spend:.2f}")
      if result.media_buy_deliveries:
          print(f"CTR: {result.media_buy_deliveries[0].totals.ctr * 100:.2f}%")

  asyncio.run(main())
  ```
</CodeGroup>

### Multiple Media Buys

<CodeGroup>
  ```javascript JavaScript test=false theme={null}
  import { testAgent } from '@adcp/client/testing';
  import { GetMediaBuyDeliveryResponseSchema } from '@adcp/client';

  // Get all active media buys from context
  const result = await testAgent.getMediaBuyDelivery({
    status_filter: 'active',
    start_date: '2024-02-01',
    end_date: '2024-02-07'
  });

  if (!result.success) {
    throw new Error(`Request failed: ${result.error}`);
  }

  const validated = GetMediaBuyDeliveryResponseSchema.parse(result.data);

  if ('errors' in validated && validated.errors) {
    throw new Error(`Query failed: ${JSON.stringify(validated.errors)}`);
  }

  console.log(`${validated.aggregated_totals.media_buy_count} active campaigns`);
  console.log(`Total impressions: ${validated.aggregated_totals.impressions.toLocaleString()}`);
  console.log(`Total spend: $${validated.aggregated_totals.spend.toFixed(2)}`);

  // Review each campaign
  validated.media_buy_deliveries.forEach(delivery => {
    console.log(`${delivery.media_buy_id}: ${delivery.totals.impressions.toLocaleString()} impressions, CTR ${(delivery.totals.ctr * 100).toFixed(2)}%`);
  });
  ```

  ```python Python test=false theme={null}
  import asyncio
  from adcp.testing import test_agent
  from adcp.types import GetMediaBuyDeliveryRequest

  async def main():
      # Get all active media buys from context
      result = await test_agent.get_media_buy_delivery(
          GetMediaBuyDeliveryRequest(
              status_filter='active',
              start_date='2024-02-01',
              end_date='2024-02-07'
          )
      )

      if hasattr(result, 'errors') and result.errors:
          raise Exception(f"Query failed: {result.errors}")

      print(f"{result.aggregated_totals.media_buy_count} active campaigns")
      print(f"Total impressions: {result.aggregated_totals.impressions:,}")
      print(f"Total spend: ${result.aggregated_totals.spend:.2f}")

      # Review each campaign
      for delivery in result.media_buy_deliveries:
          print(f"{delivery.media_buy_id}: {delivery.totals.impressions:,} impressions, CTR {delivery.totals.ctr * 100:.2f}%")

  asyncio.run(main())
  ```
</CodeGroup>

### Date Range Reporting

<CodeGroup>
  ```javascript JavaScript test=false theme={null}
  import { testAgent } from '@adcp/client/testing';
  import { GetMediaBuyDeliveryResponseSchema } from '@adcp/client';

  // Get month-to-date performance
  const now = new Date();
  const monthStart = new Date(now.getFullYear(), now.getMonth(), 1);
  const dateFormat = date => date.toISOString().split('T')[0];

  const result = await testAgent.getMediaBuyDelivery({
    media_buy_ids: ['mb_12345'],
    start_date: dateFormat(monthStart),
    end_date: dateFormat(now)
  });

  if (!result.success) {
    throw new Error(`Request failed: ${result.error}`);
  }

  const validated = GetMediaBuyDeliveryResponseSchema.parse(result.data);

  if ('errors' in validated && validated.errors) {
    throw new Error(`Query failed: ${JSON.stringify(validated.errors)}`);
  }

  if (validated.media_buy_deliveries.length > 0) {
    // Analyze daily breakdown
    const dailyBreakdown = validated.media_buy_deliveries[0].daily_breakdown;
    if (dailyBreakdown && dailyBreakdown.length > 0) {
      console.log(`Daily average: ${Math.round(validated.aggregated_totals.impressions / dailyBreakdown.length).toLocaleString()} impressions`);

      // Find peak day
      const peakDay = dailyBreakdown.reduce((max, day) =>
        day.impressions > max.impressions ? day : max
      );
      console.log(`Peak day: ${peakDay.date} with ${peakDay.impressions.toLocaleString()} impressions`);
    }
  }
  ```

  ```python Python test=false theme={null}
  import asyncio
  from adcp.testing import test_agent
  from adcp.types import GetMediaBuyDeliveryRequest
  from datetime import date

  async def main():
      # Get month-to-date performance
      today = date.today()
      month_start = date(today.year, today.month, 1)

      result = await test_agent.get_media_buy_delivery(
          GetMediaBuyDeliveryRequest(
              media_buy_ids=['mb_12345'],
              start_date=str(month_start),
              end_date=str(today)
          )
      )

      if hasattr(result, 'errors') and result.errors:
          raise Exception(f"Query failed: {result.errors}")

      if result.media_buy_deliveries:
          # Analyze daily breakdown
          daily_breakdown = result.media_buy_deliveries[0].daily_breakdown
          if daily_breakdown:
              daily_avg = result.aggregated_totals.impressions // len(daily_breakdown)
              print(f"Daily average: {daily_avg:,} impressions")

              # Find peak day
              peak_day = max(daily_breakdown, key=lambda d: d.impressions)
              print(f"Peak day: {peak_day.date} with {peak_day.impressions:,} impressions")

  asyncio.run(main())
  ```
</CodeGroup>

### Multi-Status Query

<CodeGroup>
  ```javascript JavaScript theme={null}
  import { testAgent } from '@adcp/client/testing';
  import { GetMediaBuyDeliveryResponseSchema } from '@adcp/client';

  // Get both active and paused campaigns
  const result = await testAgent.getMediaBuyDelivery({
    status_filter: ['active', 'paused'],
    start_date: '2024-02-01',
    end_date: '2024-02-07'
  });

  if (!result.success) {
    throw new Error(`Request failed: ${result.error}`);
  }

  const validated = GetMediaBuyDeliveryResponseSchema.parse(result.data);

  if ('errors' in validated && validated.errors) {
    throw new Error(`Query failed: ${JSON.stringify(validated.errors)}`);
  }

  // Group by status
  const byStatus = validated.media_buy_deliveries.reduce((acc, delivery) => {
    if (!acc[delivery.status]) acc[delivery.status] = [];
    acc[delivery.status].push(delivery);
    return acc;
  }, {});

  console.log(`Active campaigns: ${byStatus.active?.length || 0}`);
  console.log(`Paused campaigns: ${byStatus.paused?.length || 0}`);

  // Identify underperforming campaigns
  byStatus.paused?.forEach(delivery => {
    if (delivery.by_package && delivery.by_package.length > 0) {
      const avgPacing = delivery.by_package.reduce((sum, pkg) => sum + pkg.pacing_index, 0) / delivery.by_package.length;
      console.log(`${delivery.media_buy_id}: paused with ${(avgPacing * 100).toFixed(0)}% pacing`);
    }
  });
  ```

  ```python Python theme={null}
  import asyncio
  from adcp.testing import test_agent
  from adcp.types import GetMediaBuyDeliveryRequest
  from collections import defaultdict

  async def main():
      # Get both active and paused campaigns
      result = await test_agent.get_media_buy_delivery(
          GetMediaBuyDeliveryRequest(
              status_filter=['active', 'paused'],
              start_date='2024-02-01',
              end_date='2024-02-07'
          )
      )

      if hasattr(result, 'errors') and result.errors:
          raise Exception(f"Query failed: {result.errors}")

      # Group by status
      by_status = defaultdict(list)
      for delivery in result.media_buy_deliveries:
          by_status[delivery.status].append(delivery)

      print(f"Active campaigns: {len(by_status['active'])}")
      print(f"Paused campaigns: {len(by_status['paused'])}")

      # Identify underperforming campaigns
      for delivery in by_status['paused']:
          if delivery.by_package:
              avg_pacing = sum(pkg.pacing_index for pkg in delivery.by_package) / len(delivery.by_package)
              print(f"{delivery.media_buy_id}: paused with {avg_pacing * 100:.0f}% pacing")

  asyncio.run(main())
  ```
</CodeGroup>

### Buyer Reference Query

<CodeGroup>
  ```javascript JavaScript theme={null}
  import { testAgent } from '@adcp/client/testing';
  import { GetMediaBuyDeliveryResponseSchema } from '@adcp/client';

  // Query by buyer reference instead of media buy ID
  const result = await testAgent.getMediaBuyDelivery({
    media_buy_ids: ['acme_q1_campaign_2024', 'acme_q1_retargeting_2024']
  });

  if (!result.success) {
    throw new Error(`Request failed: ${result.error}`);
  }

  const validated = GetMediaBuyDeliveryResponseSchema.parse(result.data);

  if ('errors' in validated && validated.errors) {
    throw new Error(`Query failed: ${JSON.stringify(validated.errors)}`);
  }

  // Lifetime delivery data (no date range specified)
  console.log(`Total lifetime impressions: ${validated.aggregated_totals.impressions.toLocaleString()}`);
  console.log(`Total lifetime spend: $${validated.aggregated_totals.spend.toFixed(2)}`);

  // Compare campaigns
  validated.media_buy_deliveries.forEach(delivery => {
    if (delivery.totals.impressions > 0) {
      const cpm = (delivery.totals.spend / delivery.totals.impressions) * 1000;
      console.log(`${delivery.media_buy_id}: CPM $${cpm.toFixed(2)}, CTR ${(delivery.totals.ctr * 100).toFixed(2)}%`);
    }
  });
  ```

  ```python Python theme={null}
  import asyncio
  from adcp.testing import test_agent
  from adcp.types import GetMediaBuyDeliveryRequest

  async def main():
      # Query by buyer reference instead of media buy ID
      result = await test_agent.get_media_buy_delivery(
          GetMediaBuyDeliveryRequest(
              media_buy_ids=['acme_q1_campaign_2024', 'acme_q1_retargeting_2024']
          )
      )

      if hasattr(result, 'errors') and result.errors:
          raise Exception(f"Query failed: {result.errors}")

      # Lifetime delivery data (no date range specified)
      print(f"Total lifetime impressions: {result.aggregated_totals.impressions:,}")
      print(f"Total lifetime spend: ${result.aggregated_totals.spend:.2f}")

      # Compare campaigns
      for delivery in result.media_buy_deliveries:
          if delivery.totals.impressions > 0:
              cpm = (delivery.totals.spend / delivery.totals.impressions) * 1000
              print(f"{delivery.media_buy_id}: CPM ${cpm:.2f}, CTR {delivery.totals.ctr * 100:.2f}%")

  asyncio.run(main())
  ```
</CodeGroup>

### Account-Scoped Query

<CodeGroup>
  ```javascript JavaScript test=false theme={null}
  import { testAgent } from '@adcp/client/testing';
  import { GetMediaBuyDeliveryResponseSchema } from '@adcp/client';

  // Get delivery for a specific advertiser account
  const result = await testAgent.getMediaBuyDelivery({
    account: { account_id: 'acc_acme_pinnacle' },
    status_filter: 'active',
    start_date: '2024-02-01',
    end_date: '2024-02-07'
  });

  if (!result.success) {
    throw new Error(`Request failed: ${result.error}`);
  }

  const validated = GetMediaBuyDeliveryResponseSchema.parse(result.data);

  if ('errors' in validated && validated.errors) {
    throw new Error(`Query failed: ${JSON.stringify(validated.errors)}`);
  }

  console.log(`${validated.aggregated_totals.media_buy_count} campaigns for account`);
  console.log(`Total spend: $${validated.aggregated_totals.spend.toFixed(2)}`);
  ```

  ```python Python test=false theme={null}
  import asyncio
  from adcp.testing import test_agent
  from adcp.types import GetMediaBuyDeliveryRequest

  async def main():
      # Get delivery for a specific advertiser account
      result = await test_agent.get_media_buy_delivery(
          GetMediaBuyDeliveryRequest(
              account={'account_id': 'acc_acme_pinnacle'},
              status_filter='active',
              start_date='2024-02-01',
              end_date='2024-02-07'
          )
      )

      if hasattr(result, 'errors') and result.errors:
          raise Exception(f"Query failed: {result.errors}")

      print(f"{result.aggregated_totals.media_buy_count} campaigns for account")
      print(f"Total spend: ${result.aggregated_totals.spend:.2f}")

  asyncio.run(main())
  ```
</CodeGroup>

## Metrics Definitions

| Metric                   | Definition                                                                                                                    |
| ------------------------ | ----------------------------------------------------------------------------------------------------------------------------- |
| **Impressions**          | Number of times ads were displayed                                                                                            |
| **Spend**                | Amount spent in specified currency                                                                                            |
| **Clicks**               | Number of ad clicks (if available)                                                                                            |
| **CTR**                  | Click-through rate (clicks/impressions)                                                                                       |
| **Views**                | Content engagements at the billable view threshold — video views, audio/podcast stream starts, or format-specific view events |
| **Completed Views**      | Audio/video completions (at threshold or 100%)                                                                                |
| **Completion Rate**      | Completion rate (completed\_views/impressions)                                                                                |
| **Conversions**          | Attributed conversions (purchases, new listeners, app installs, etc.)                                                         |
| **Conversion Value**     | Total monetary value of attributed conversions                                                                                |
| **ROAS**                 | Return on ad spend (conversion\_value / spend)                                                                                |
| **New-to-Brand Rate**    | Fraction of conversions from first-time brand buyers (0-1)                                                                    |
| **Cost per Acquisition** | Cost per conversion (spend / conversions)                                                                                     |
| **Reach**                | Unique users reached (see `reach_unit` for measurement unit: individuals, households, devices, accounts, cookies)             |
| **Reach Unit**           | Unit of measurement for reach — required when reach is present                                                                |
| **Frequency**            | Average ad exposures per reach unit                                                                                           |
| **Follows**              | New followers, subscribes, or page likes attributed to delivery                                                               |
| **Pacing Index**         | Actual vs. expected delivery rate (1.0 = on track, \<1.0 = behind, >1.0 = ahead)                                              |
| **CPM**                  | Cost per thousand impressions (spend/impressions \* 1000)                                                                     |

## Query Behavior

### Context-Based Queries

* If no `media_buy_ids` provided, returns all media buys from current session context
* Context established by previous operations (e.g., `create_media_buy`)

### Status Filtering

* Defaults to `["active"]` if not specified
* Can be single string (`"active"`) or array (`["active", "paused"]`)
* Valid filter values are media-buy lifecycle statuses: `pending_creatives`, `pending_start`, `active`, `paused`, `completed`
* `reporting_delayed` and `failed` are delivery/reporting statuses returned in webhook contexts, not request filter values
* Some legacy integrations may emit `pending`; treat it as equivalent to `pending_start`

### Date Ranges

* If dates not specified, returns campaign lifetime delivery data
* Both `start_date` and `end_date` must be provided together — partial date ranges are invalid
* Date format: `YYYY-MM-DD`
* **Start-inclusive, end-exclusive**: `start_date` is included, `end_date` is excluded. For example, `start_date: "2026-01-01"` and `end_date: "2026-01-02"` returns data for January 1st only.
* Products declare date range support in `reporting_capabilities.date_range_support`
* Products with `date_range_support: "lifetime_only"` reject requests that include `start_date`/`end_date` with a `DATE_RANGE_NOT_SUPPORTED` error
* Products with `date_range_support: "date_range"` accept date parameters and filter delivery data accordingly
* Daily breakdown may be truncated for long date ranges to reduce response size

### Metric Availability

* **Universal**: Impressions, spend (available on all platforms)
* **Format-dependent**: Clicks, completed\_views, completion\_rate (depends on inventory type and platform capabilities)
* **Audience**: Reach, frequency (available on platforms with deduplicated measurement)
* **Commerce attribution**: Conversions, conversion\_value, roas, new\_to\_brand\_rate (available on commerce media and streaming platforms)
* **Engagement**: Follows, saves, engagements, profile\_visits (available on social and streaming platforms)
* **Attribution window**: `attribution_window` describes the lookback windows and model used for conversion attribution (e.g., 14-day click, 1-day view, last\_touch)
* **Package-level**: All metrics broken down by package with pacing\_index

## Data Freshness

* Reporting data typically has 2-4 hour delay
* Real-time impression counts not available
* Use for periodic reporting and optimization decisions, not live monitoring

**Phased-maturation channels**: Data freshness differs for channels where billing-grade data is produced in phases rather than arriving final on day one — broadcast TV (Live → C3 → C7 DVR accumulation, final C7 \~15–22 days after broadcast), DOOH (tentative plays → post-IVT/fraud-check final), digital with IVT filtering (raw → post-GIVT → post-SIVT), and podcast (7-day → 30-day downloads). Products with `reporting_capabilities.measurement_windows` declare these timelines. Buyers reconcile against the `measurement_window` specified in `billing_measurement` on the agreed terms. See [Accountability](/dist/docs/3.0.19/media-buy/advanced-topics/accountability) for measurement terms and [Optimization and reporting](/dist/docs/3.0.19/media-buy/media-buys/optimization-reporting) for the full lifecycle.

## Error Handling

| Error Code                 | Description                              | Resolution                                                                                          |
| -------------------------- | ---------------------------------------- | --------------------------------------------------------------------------------------------------- |
| `AUTH_REQUIRED`            | Authentication needed                    | Provide credentials                                                                                 |
| `MEDIA_BUY_NOT_FOUND`      | Media buy doesn't exist                  | Verify media\_buy\_id                                                                               |
| `INVALID_DATE_RANGE`       | Invalid start/end dates                  | Use YYYY-MM-DD format, ensure start \< end                                                          |
| `DATE_RANGE_NOT_SUPPORTED` | Product only supports lifetime reporting | Omit `start_date` and `end_date`. Check `reporting_capabilities.date_range_support` on the product. |
| `CONTEXT_REQUIRED`         | No media buys in context                 | Provide media\_buy\_ids explicitly                                                                  |
| `INVALID_STATUS_FILTER`    | Invalid status value                     | Use valid status: pending\_creatives, pending\_start, active, paused, completed                     |

## Package-Level Metrics

The `by_package` array provides per-package delivery details with these key fields:

**Buyer Control**:

* **`paused`**: Whether the package is currently paused by the buyer (true/false)

**System State**:

* **`delivery_status`**: System-reported operational state:
  * `delivering` - Package is actively delivering impressions
  * `completed` - Package finished successfully
  * `budget_exhausted` - Package ran out of budget
  * `flight_ended` - Package reached its end date
  * `goal_met` - Package achieved its impression/conversion goal

**Performance**:

* **`pacing_index`**: Delivery pace (1.0 = on track, below 1.0 = behind, above 1.0 = ahead)
* **`rate`**: Effective pricing rate (e.g., CPM)
* **`pricing_model`**: How the package is billed (cpm, cpcv, cpp, etc.)

**Key Distinction**: `paused` reflects buyer control, while `delivery_status` reflects system reality. A package can be not paused but have `delivery_status: "budget_exhausted"`.

## Creative-Level Metrics

When the seller supports creative-level reporting (`supports_creative_breakdown` in reporting capabilities), each package includes a `by_creative` array with per-creative delivery metrics.

Each creative entry includes:

* **`creative_id`**: Creative identifier matching the creative assignment
* **`weight`**: Delivery weight for this creative during the reporting period (0-100)
* All standard delivery metrics (impressions, spend, clicks, ctr, etc.)

```json theme={null}
{
  "by_package": [
    {
      "package_id": "pkg_001",
      "spend": 5000,
      "impressions": 100000,
      "pricing_model": "cpm",
      "rate": 50,
      "currency": "USD",
      "delivery_status": "delivering",
      "by_creative": [
        {
          "creative_id": "hero_video_30s",
          "weight": 60,
          "impressions": 60000,
          "spend": 3000,
          "clicks": 3000,
          "ctr": 0.05,
          "completion_rate": 0.72
        },
        {
          "creative_id": "hero_video_15s",
          "weight": 40,
          "impressions": 40000,
          "spend": 2000,
          "clicks": 1200,
          "ctr": 0.03,
          "completion_rate": 0.85
        }
      ]
    }
  ]
}
```

For deeper creative analytics including variant-level delivery data (asset combination optimization, generative creative), use [`get_creative_delivery`](/dist/docs/3.0.19/creative/task-reference/get_creative_delivery). This is a Creative Protocol task — call it on any agent that implements the Creative Protocol, which may be the same sales agent if it declares `"creative"` in `supported_protocols`. See [Creative capabilities on sales agents](/dist/docs/3.0.19/creative/sales-agent-creative-capabilities).

## Catalog-item reporting

For catalog-driven packages (packages with a `catalog` field), the seller can return per-catalog-item delivery in the `by_catalog_item` array within each package.

Each entry identifies the catalog item and includes standard delivery metrics:

| Field             | Description                                                                                |
| ----------------- | ------------------------------------------------------------------------------------------ |
| `content_id`      | The item identifier (SKU, GTIN, job ID, etc.)                                              |
| `content_id_type` | Identifier type (`sku`, `gtin`, `job_id`, etc.) matching the catalog's `content_id_type`   |
| Standard metrics  | `impressions`, `spend`, `clicks`, `ctr`, `conversions`, `roas`, and other delivery metrics |

This is optional. Sellers that support item-level reporting populate `by_catalog_item`; sellers that do not simply omit it.

```json theme={null}
{
  "by_package": [
    {
      "package_id": "pkg_001",
      "spend": 5000,
      "impressions": 100000,
      "pricing_model": "cpc",
      "rate": 1.20,
      "currency": "USD",
      "delivery_status": "delivering",
      "by_catalog_item": [
        {
          "content_id": "SKU-12345",
          "content_id_type": "sku",
          "impressions": 45000,
          "spend": 2250,
          "clicks": 1800,
          "ctr": 0.04,
          "conversions": 90,
          "roas": 4.2
        },
        {
          "content_id": "SKU-67890",
          "content_id_type": "sku",
          "impressions": 55000,
          "spend": 2750,
          "clicks": 2200,
          "ctr": 0.04,
          "conversions": 110,
          "roas": 3.8
        }
      ]
    }
  ]
}
```

## Dimension Breakdowns

When you include `reporting_dimensions` in the request, the response includes dimensional breakdown arrays within each `by_package` entry. Each breakdown entry inherits all fields from `delivery-metrics` plus dimension-specific identifiers.

### Requesting breakdowns

```json test=false theme={null}
{
  "media_buy_ids": ["mb_123"],
  "reporting_dimensions": {
    "geo": { "geo_level": "metro", "system": "nielsen_dma", "limit": 10 },
    "device_type": {},
    "placement": { "limit": 5, "sort_by": "roas" }
  }
}
```

Each dimension accepts optional `limit` (max rows; defaults to 25 for geo, audience, and placement) and `sort_by` (any value from the `sort-metric` enum, e.g., `spend`, `impressions`, `clicks`, `roas` — defaults to `spend` descending; falls back to `spend` if the seller does not report the requested metric). Geo requires `geo_level` (`country`, `region`, `metro`, `postal_area`) and `system` for metro/postal levels. Each request uses a single geo\_level — for multiple granularities (e.g., country and region), make separate requests. Unsupported dimensions are silently omitted from the response, but malformed requests (e.g., geo without `geo_level`) return a validation error. Breakdowns are per-dimension only — cross-dimensional intersections (e.g., device\_type × geo) are not supported.

### Available dimensions

| Dimension       | Breakdown field      | Required fields                                          | Capability flag                      |
| --------------- | -------------------- | -------------------------------------------------------- | ------------------------------------ |
| Geography       | `by_geo`             | `geo_level`, `geo_code`, `impressions`, `spend`          | `supports_geo_breakdown`             |
| Device type     | `by_device_type`     | `device_type`, `impressions`, `spend`                    | `supports_device_type_breakdown`     |
| Device platform | `by_device_platform` | `device_platform`, `impressions`, `spend`                | `supports_device_platform_breakdown` |
| Audience        | `by_audience`        | `audience_id`, `audience_source`, `impressions`, `spend` | `supports_audience_breakdown`        |
| Placement       | `by_placement`       | `placement_id`, `impressions`, `spend`                   | `supports_placement_breakdown`       |

Check `reporting_capabilities` on the product to discover which dimensions are available. Product-level capabilities are authoritative since different products from the same seller may support different breakdowns.

### Truncation

Each breakdown array has a sibling boolean flag (e.g., `by_geo_truncated`). When `true`, additional rows exist beyond the returned set. When `false`, the list is complete. Sellers MUST return the truncated flag whenever the corresponding breakdown array is present. Rows are sorted by the requested `sort_by` metric descending.

### Audience sources

The `audience_source` field indicates where the audience segment originated:

| Source        | Description                                     | Targetable?                                     |
| ------------- | ----------------------------------------------- | ----------------------------------------------- |
| `synced`      | Buyer's first-party data via `sync_audiences`   | Yes — use `audience_include`/`audience_exclude` |
| `platform`    | Seller's native segments (interest, behavioral) | No — informational                              |
| `third_party` | External data provider segments                 | No — informational                              |
| `lookalike`   | Platform-generated expansion from a seed        | No — informational                              |
| `retargeting` | Prior engagement via seller's pixel/tag         | No — informational                              |
| `unknown`     | Unclassified or unrecognized audience source    | No — informational                              |

## Best Practices

**1. Check Date Range Support**
Before requesting date-filtered delivery, check `reporting_capabilities.date_range_support` on the product. Products with `lifetime_only` support reject date range requests — omit `start_date` and `end_date` to get campaign lifetime data instead.

**2. Use Date Ranges for Analysis**
For products that support date ranges, specify dates for period-over-period comparisons and trend analysis.

**3. Monitor Pacing Index**
Aim for 0.95-1.05 pacing index. Values outside this range indicate delivery issues.

**4. Check Daily Breakdown**
Identify delivery patterns and weekend/weekday performance differences.

**5. Compare Package Performance**
Use `by_package` breakdowns to identify best-performing inventory. Check both `paused` state and `delivery_status` to understand why packages aren't delivering.

**6. Track Status Changes**
Use multi-status queries to understand why campaigns were paused or completed.

## Post-Delivery Governance Validation

Delivery reporting is not the final step. When campaign governance is active, delivery data feeds into governance validation to detect unauthorized supply paths, geo drift, and pacing violations.

The governance feedback loop:

1. Pull delivery data via `get_media_buy_delivery`
2. Report outcomes to the governance agent via [`report_plan_outcome`](/dist/docs/3.0.19/governance/campaign/tasks/report_plan_outcome)
3. The governance agent compares actual delivery against planned parameters (drift detection)
4. Validate property delivery via [`validate_property_delivery`](/dist/docs/3.0.19/governance/property/tasks/validate_property_delivery) to catch unauthorized supply paths

| Governance task                                                                                               | Purpose                                                                                           |
| ------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------- |
| [`report_plan_outcome`](/dist/docs/3.0.19/governance/campaign/tasks/report_plan_outcome)                      | Feed delivery data to the governance agent for budget tracking and drift detection                |
| [`validate_property_delivery`](/dist/docs/3.0.19/governance/property/tasks/validate_property_delivery)        | Validate delivery records against property lists — catches ads running on unauthorized properties |
| [`validate_content_delivery`](/dist/docs/3.0.19/governance/content-standards/tasks/validate_content_delivery) | Validate content artifacts against brand suitability standards                                    |
| [`get_plan_audit_logs`](/dist/docs/3.0.19/governance/campaign/tasks/get_plan_audit_logs)                      | View the full plan state and audit trail                                                          |

Without this feedback loop, delivery data is reported but never validated. Budget overruns, pacing divergence, geo drift, and unauthorized supply paths go undetected.

## Next Steps

After retrieving delivery data:

1. **Optimize Campaigns**: Use [`update_media_buy`](/dist/docs/3.0.19/media-buy/task-reference/update_media_buy) to adjust budgets, pacing, or targeting
2. **Provide Feedback**: Use [`provide_performance_feedback`](/dist/docs/3.0.19/media-buy/task-reference/provide_performance_feedback) to share results with seller
3. **Update Creatives**: Use [`sync_creatives`](/dist/docs/3.0.19/creative/task-reference/sync_creatives) to refresh underperforming assets
4. **Create Follow-Up Campaigns**: Use [`create_media_buy`](/dist/docs/3.0.19/media-buy/task-reference/create_media_buy) based on insights

## Learn More

* [Media Buy Lifecycle](/dist/docs/3.0.19/media-buy/media-buys/) - Complete campaign workflow
* [Async Operations](/dist/docs/3.0.19/building/by-layer/L3/async-operations) - Async patterns and status handling
* [Performance Optimization](/dist/docs/3.0.19/media-buy/media-buys/optimization-reporting) - Using delivery data for optimization
