> ## 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.

# create_media_buy

Create a media buy from selected packages. Handles validation, approval if needed, and campaign creation.

**Response Time**: Instant to days (returns `completed`, `working` \< 120s, or `submitted` for hours/days)

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

## Quick Start

Create a simple media buy with two packages:

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

  // Calculate dates dynamically - start tomorrow, end in 90 days
  const tomorrow = new Date();
  tomorrow.setDate(tomorrow.getDate() + 1);
  tomorrow.setHours(0, 0, 0, 0);
  const endDate = new Date(tomorrow);
  endDate.setDate(endDate.getDate() + 90);

  const result = await testAgent.createMediaBuy({
    buyer_ref: 'summer_campaign_' + Date.now(),
    brand_manifest: {
      name: 'Nike',
      url: 'https://nike.com'
    },
    packages: [
      {
        buyer_ref: 'display_package_1',
        product_id: 'prod_d979b543',
        pricing_option_id: 'cpm_usd_auction',
        format_ids: [
          {
            agent_url: 'https://creative.adcontextprotocol.org',
            id: 'display_300x250_image'
          }
        ],
        budget: 5000,
        bid_price: 5.00
      },
      {
        buyer_ref: 'display_package_2',
        product_id: 'prod_e8fd6012',
        pricing_option_id: 'cpm_usd_auction',
        format_ids: [
          {
            agent_url: 'https://creative.adcontextprotocol.org',
            id: 'display_300x250_html'
          }
        ],
        budget: 5000,
        bid_price: 4.50
      }
    ],
    start_time: tomorrow.toISOString(),
    end_time: endDate.toISOString()
  });

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

  // Validate response against schema
  const validated = CreateMediaBuyResponseSchema.parse(result.data);

  // Check for errors (discriminated union response)
  if ('errors' in validated && validated.errors) {
    throw new Error(`Failed to create media buy: ${JSON.stringify(validated.errors)}`);
  }

  if ('media_buy_id' in validated) {
    console.log(`Created media buy ${validated.media_buy_id}`);
    console.log(`Upload creatives by: ${validated.creative_deadline}`);
    console.log(`Packages created: ${validated.packages.length}`);
  }
  ```

  ```python Python test=false theme={null}
  import asyncio
  import time
  from datetime import datetime, timedelta, timezone
  from adcp import test_agent

  async def create_campaign():
      # Calculate dates dynamically - start tomorrow, end in 90 days
      tomorrow = datetime.now(timezone.utc).replace(hour=0, minute=0, second=0, microsecond=0) + timedelta(days=1)
      end_date = tomorrow + timedelta(days=90)

      result = await test_agent.simple.create_media_buy(
          buyer_ref=f'summer_campaign_{int(time.time() * 1000)}',
          brand_manifest={
              'name': 'Nike',
              'url': 'https://nike.com'
          },
          packages=[
              {
                  'buyer_ref': 'ctv_package',
                  'product_id': 'prod_d979b543',
                  'pricing_option_id': 'cpm_usd_auction',
                  'format_ids': [
                      {
                          'agent_url': 'https://creative.adcontextprotocol.org',
                          'id': 'display_300x250_image'
                      }
                  ],
                  'budget': 5000,
                  'bid_price': 5.00
              },
              {
                  'buyer_ref': 'audio_package',
                  'product_id': 'prod_e8fd6012',
                  'pricing_option_id': 'cpm_usd_auction',
                  'format_ids': [
                      {
                          'agent_url': 'https://creative.adcontextprotocol.org',
                          'id': 'display_300x250_html'
                      }
                  ],
                  'budget': 5000,
                  'bid_price': 4.50
              }
          ],
          start_time=tomorrow.isoformat().replace('+00:00', 'Z'),
          end_time=end_date.isoformat().replace('+00:00', 'Z')
      )

      # Check for errors (discriminated union response)
      if hasattr(result, 'errors') and result.errors:
          raise Exception(f"Failed to create media buy: {result.errors}")

      print(f"Created media buy {result.media_buy_id}")
      print(f"Upload creatives by: {result.creative_deadline}")
      print(f"Packages created: {len(result.packages)}")

  asyncio.run(create_campaign())
  ```

  ```bash CLI test=false theme={null}
  npx adcp \
    https://test-agent.adcontextprotocol.org/mcp \
    create_media_buy \
    '{"buyer_ref":"summer_campaign_2025","brand_manifest":{"name":"Nike","url":"https://nike.com"},"packages":[{"buyer_ref":"display_package_1","product_id":"prod_d979b543","pricing_option_id":"cpm_usd_auction","format_ids":[{"agent_url":"https://creative.adcontextprotocol.org","id":"display_300x250_image"}],"budget":30000,"bid_price":5.00},{"buyer_ref":"display_package_2","product_id":"prod_e8fd6012","pricing_option_id":"cpm_usd_auction","format_ids":[{"agent_url":"https://creative.adcontextprotocol.org","id":"display_300x250_html"}],"budget":20000,"bid_price":4.50}],"start_time":"2025-06-01T00:00:00Z","end_time":"2025-08-31T23:59:59Z"}' \
    --auth 1v8tAhASaUYYp4odoQ1PnMpdqNaMiTrCRqYo9OJp6IQ
  ```
</CodeGroup>

## Request Parameters

| Parameter           | Type             | Required | Description                                                                                                                     |
| ------------------- | ---------------- | -------- | ------------------------------------------------------------------------------------------------------------------------------- |
| `buyer_ref`         | string           | Yes      | Your reference identifier for this media buy                                                                                    |
| `packages`          | Package\[]       | Yes      | Array of package configurations (see below)                                                                                     |
| `brand_manifest`    | BrandManifestRef | Yes      | Brand identity - minimal (name/URL) acceptable for sales agents. See [Brand Manifest](/dist/docs/2.5.3/creative/brand-manifest) |
| `start_time`        | string           | Yes      | `"asap"` or ISO 8601 date-time                                                                                                  |
| `end_time`          | string           | Yes      | ISO 8601 date-time (UTC unless timezone specified)                                                                              |
| `po_number`         | string           | No       | Purchase order number                                                                                                           |
| `reporting_webhook` | ReportingWebhook | No       | Automated reporting delivery configuration                                                                                      |

### Package Object

| Parameter           | Type             | Required | Description                                                                                           |
| ------------------- | ---------------- | -------- | ----------------------------------------------------------------------------------------------------- |
| `buyer_ref`         | string           | Yes      | Your reference for this package                                                                       |
| `product_id`        | string           | Yes      | Product ID from `get_products`                                                                        |
| `pricing_option_id` | string           | Yes      | Pricing option ID from product's `pricing_options` array                                              |
| `format_ids`        | FormatID\[]      | Yes      | Format IDs that will be used - must be supported by product                                           |
| `budget`            | number           | Yes      | Budget in currency specified by pricing option                                                        |
| `impressions`       | number           | No       | Impression goal for this package                                                                      |
| `paused`            | boolean          | No       | Create package in paused state (default: `false`)                                                     |
| `pacing`            | string           | No       | `"even"` (default), `"asap"`, or `"front_loaded"`                                                     |
| `bid_price`         | number           | No       | Bid price for auction pricing (required when `is_fixed` is false)                                     |
| `targeting_overlay` | TargetingOverlay | No       | Additional targeting criteria (see [Targeting](/dist/docs/2.5.3/media-buy/advanced-topics/targeting)) |
| `creative_ids`      | string\[]        | No       | Existing library creative IDs to assign                                                               |
| `creatives`         | CreativeAsset\[] | No       | Full creative objects to upload and assign                                                            |

## Response

### Success Response

| Field               | Description                                     |
| ------------------- | ----------------------------------------------- |
| `media_buy_id`      | Publisher's unique identifier                   |
| `buyer_ref`         | Your reference identifier                       |
| `creative_deadline` | ISO 8601 timestamp for creative upload deadline |
| `packages`          | Array of created packages with complete state   |

### Error Response

| Field    | Description                               |
| -------- | ----------------------------------------- |
| `errors` | Array of error objects explaining failure |

**Note**: Responses use discriminated unions - you get either success fields OR errors, never both. Always check for `errors` before accessing success fields.

## Common Scenarios

### Campaign with Targeting

Add geographic restrictions and frequency capping:

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

  // Calculate end date dynamically - 90 days from now
  const endDate = new Date();
  endDate.setDate(endDate.getDate() + 90);

  const result = await testAgent.createMediaBuy({
    buyer_ref: 'regional_campaign_' + Date.now(),
    brand_manifest: {
      name: 'Regional Retailer',
      url: 'https://example-retailer.com'
    },
    packages: [{
      buyer_ref: 'ctv_regional',
      product_id: 'prod_d979b543',
      pricing_option_id: 'cpm_usd_auction',
      format_ids: [{
        agent_url: 'https://creative.adcontextprotocol.org',
        id: 'display_300x250_image'
      }],
      budget: 5000,
      bid_price: 5.00,
      targeting_overlay: {
        geo_country_any_of: ['US'],
        geo_region_any_of: ['CA', 'NY'],
        frequency_cap: {
          suppress_minutes: 60
        }
      }
    }],
    start_time: 'asap',
    end_time: endDate.toISOString()
  });

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

  const validated = CreateMediaBuyResponseSchema.parse(result.data);
  if ('errors' in validated && validated.errors) {
    throw new Error(`Creation failed: ${JSON.stringify(validated.errors)}`);
  }

  if ('media_buy_id' in validated) {
    console.log(`Campaign ${validated.media_buy_id} created with targeting`);
  }
  ```

  ```python Python theme={null}
  import asyncio
  import time
  from datetime import datetime, timedelta, timezone
  from adcp import test_agent

  async def create_targeted_campaign():
      # Calculate end date dynamically - 90 days from now
      end_date = datetime.now(timezone.utc) + timedelta(days=90)

      result = await test_agent.simple.create_media_buy(
          buyer_ref=f'regional_campaign_{int(time.time() * 1000)}',
          brand_manifest={
              'name': 'Regional Retailer',
              'url': 'https://example-retailer.com'
          },
          packages=[{
              'buyer_ref': 'ctv_regional',
              'product_id': 'prod_d979b543',
              'pricing_option_id': 'cpm_usd_auction',
              'format_ids': [{
                  'agent_url': 'https://creative.adcontextprotocol.org',
                  'id': 'display_300x250_image'
              }],
              'budget': 5000,
              'bid_price': 5.00,
              'targeting_overlay': {
                  'geo_country_any_of': ['US'],
                  'geo_region_any_of': ['CA', 'NY'],
                  'frequency_cap': {
                      'suppress_minutes': 60
                  }
              }
          }],
          start_time='asap',
          end_time=end_date.isoformat().replace('+00:00', 'Z')
      )

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

      print(f"Campaign {result.media_buy_id} created with targeting")

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

### Campaign with Inline Creatives

Upload creatives at the same time as creating the campaign:

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

  // Calculate end date dynamically - 90 days from now
  const endDate = new Date();
  endDate.setDate(endDate.getDate() + 90);

  const result = await testAgent.createMediaBuy({
    buyer_ref: 'campaign_with_creatives_' + Date.now(),
    brand_manifest: {
      name: 'Nike',
      url: 'https://nike.com'
    },
    packages: [{
      buyer_ref: 'ctv_package',
      product_id: 'prod_d979b543',
      pricing_option_id: 'cpm_usd_auction',
      format_ids: [{
        agent_url: 'https://creative.adcontextprotocol.org',
        id: 'display_300x250_image'
      }],
      budget: 5000,
      bid_price: 5.00,
      creatives: [{
        creative_id: 'hero_video_30s',
        name: 'Hero Video',
        format_id: {
          agent_url: 'https://creative.adcontextprotocol.org',
          id: 'display_300x250_image'
        },
        assets: {
          image: {
            url: 'https://cdn.example.com/hero-banner.jpg',
            width: 300,
            height: 250
          }
        }
      }]
    }],
    start_time: 'asap',
    end_time: endDate.toISOString()
  });

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

  const validated = CreateMediaBuyResponseSchema.parse(result.data);
  if ('errors' in validated && validated.errors) {
    throw new Error(`Creation failed: ${JSON.stringify(validated.errors)}`);
  }

  if ('packages' in validated) {
    console.log(`Campaign created with ${validated.packages[0].creative_assignments.length} creatives`);
  }
  ```

  ```python Python test=false theme={null}
  import asyncio
  import time
  from datetime import datetime, timedelta, timezone
  from adcp import test_agent

  async def create_with_creatives():
      # Calculate end date dynamically - 90 days from now
      end_date = datetime.now(timezone.utc) + timedelta(days=90)

      result = await test_agent.simple.create_media_buy(
          buyer_ref=f'campaign_with_creatives_{int(time.time() * 1000)}',
          brand_manifest={
              'name': 'Nike',
              'url': 'https://nike.com'
          },
          packages=[{
              'buyer_ref': 'ctv_package',
              'product_id': 'prod_d979b543',
              'pricing_option_id': 'cpm_usd_auction',
              'format_ids': [{
                  'agent_url': 'https://creative.adcontextprotocol.org',
                  'id': 'display_300x250_image'
              }],
              'budget': 5000,
              'bid_price': 5.00,
              'creatives': [{
                  'creative_id': 'hero_video_30s',
                  'name': 'Hero Video',
                  'format_id': {
                      'agent_url': 'https://creative.adcontextprotocol.org',
                      'id': 'display_300x250_image'
                  },
                  'assets': {
                      'image': {
                          'url': 'https://cdn.example.com/hero-banner.jpg',
                          'width': 300,
                          'height': 250
                      }
                  }
              }]
          }],
          start_time='asap',
          end_time=end_date.isoformat().replace('+00:00', 'Z')
      )

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

      print(f"Campaign created with {len(result.packages[0].creative_assignments)} creatives")

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

### Campaign with Reporting Webhook

Receive automated reporting notifications:

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

  // Calculate end date dynamically - 90 days from now
  const endDate = new Date();
  endDate.setDate(endDate.getDate() + 90);

  const result = await testAgent.createMediaBuy({
    buyer_ref: 'campaign_with_reporting_' + Date.now(),
    brand_manifest: {
      name: 'Nike',
      url: 'https://nike.com'
    },
    packages: [{
      buyer_ref: 'ctv_package',
      product_id: 'prod_d979b543',
      pricing_option_id: 'cpm_usd_auction',
      format_ids: [{
        agent_url: 'https://creative.adcontextprotocol.org',
        id: 'display_300x250_image'
      }],
      budget: 5000,
      bid_price: 5.00
    }],
    start_time: 'asap',
    end_time: endDate.toISOString(),
    reporting_webhook: {
      url: 'https://buyer.example.com/webhooks/reporting',
      authentication: {
        schemes: ['Bearer'],
        credentials: 'secret_token_xyz_minimum_32_chars'
      },
      reporting_frequency: 'daily',
      requested_metrics: ['impressions', 'spend', 'video_completions']
    }
  });

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

  const validated = CreateMediaBuyResponseSchema.parse(result.data);
  if ('errors' in validated && validated.errors) {
    throw new Error(`Creation failed: ${JSON.stringify(validated.errors)}`);
  }

  if ('media_buy_id' in validated) {
    console.log(`Campaign created - daily reports will be sent to webhook`);
  }
  ```

  ```python Python theme={null}
  import asyncio
  import time
  from datetime import datetime, timedelta, timezone
  from adcp import test_agent

  async def create_with_reporting():
      # Calculate end date dynamically - 90 days from now
      end_date = datetime.now(timezone.utc) + timedelta(days=90)

      result = await test_agent.simple.create_media_buy(
          buyer_ref=f'campaign_with_reporting_{int(time.time() * 1000)}',
          brand_manifest={
              'name': 'Nike',
              'url': 'https://nike.com'
          },
          packages=[{
              'buyer_ref': 'ctv_package',
              'product_id': 'prod_d979b543',
              'pricing_option_id': 'cpm_usd_auction',
              'format_ids': [{
                  'agent_url': 'https://creative.adcontextprotocol.org',
                  'id': 'display_300x250_image'
              }],
              'budget': 5000,
              'bid_price': 5.00
          }],
          start_time='asap',
          end_time=end_date.isoformat().replace('+00:00', 'Z'),
          reporting_webhook={
              'url': 'https://buyer.example.com/webhooks/reporting',
              'authentication': {
                  'schemes': ['Bearer'],
                  'credentials': 'secret_token_xyz_minimum_32_chars'
              },
              'reporting_frequency': 'daily',
              'requested_metrics': ['impressions', 'spend', 'video_completions']
          }
      )

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

      print('Campaign created - daily reports will be sent to webhook')

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

## Error Handling

Common errors and resolutions:

| Error Code               | Description                     | Resolution                                  |
| ------------------------ | ------------------------------- | ------------------------------------------- |
| `PRODUCT_NOT_FOUND`      | Invalid product\_id             | Verify product exists via `get_products`    |
| `FORMAT_INCOMPATIBLE`    | Format not supported by product | Check product's `format_ids` field          |
| `BUDGET_INSUFFICIENT`    | Budget below product minimum    | Increase budget or choose different product |
| `TARGETING_TOO_NARROW`   | Targeting yields zero inventory | Broaden geographic or audience criteria     |
| `POLICY_VIOLATION`       | Brand/product violates policy   | Review publisher's content policies         |
| `INVALID_PRICING_OPTION` | pricing\_option\_id not found   | Use ID from product's `pricing_options`     |

Example error response:

```json theme={null}
{
  "errors": [{
    "code": "FORMAT_INCOMPATIBLE",
    "message": "Product 'prod_d979b543' does not support format 'display_728x90'",
    "field": "packages[0].format_ids",
    "suggestion": "Use display_300x250_image, display_300x250_html, or display_300x250_generative formats"
  }]
}
```

## Key Concepts

### Format Specification

Format IDs are **required** for each package because:

* Publishers create placeholder creatives in ad servers
* Both parties know exactly what creative assets are needed
* Validation ensures products support requested formats
* Progress tracking shows which assets are missing

See [Format Workflow](#format-workflow) below for complete details.

### Brand Manifest

The `brand_manifest` field identifies the advertiser for policy compliance and business purposes.

**Minimal manifests are acceptable** for sales agents:

```json theme={null}
{
  "brand_manifest": {
    "name": "ACME Corporation",
    "url": "https://acmecorp.com"
  }
}
```

Full manifests with colors, fonts, and product catalogs are only needed for creative generation. See [Brand Manifest](/dist/docs/2.5.3/creative/brand-manifest).

### 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](/dist/docs/2.5.3/media-buy/advanced-topics/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

See [Targeting](/dist/docs/2.5.3/media-buy/advanced-topics/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

```
1. list_creative_formats → Get available format specifications
2. get_products → Find products (returns format_ids they support)
3. Validate compatibility → Ensure products support desired formats
4. create_media_buy → Specify formats (REQUIRED)
   └── Publisher creates placeholders
   └── Clear creative requirements established
5. sync_creatives → Upload actual files matching formats
6. Campaign activation → Replace placeholders with real creatives
```

### 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 format example:

```json theme={null}
{
  "errors": [{
    "code": "FORMAT_INCOMPATIBLE",
    "message": "Product 'ctv_sports_premium' does not support format 'audio_standard_30s'",
    "field": "packages[0].format_ids",
    "supported_formats": [
      { "agent_url": "https://creative.adcontextprotocol.org", "id": "video_standard_30s" },
      { "agent_url": "https://creative.adcontextprotocol.org", "id": "video_standard_15s" }
    ]
  }]
}
```

## 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.

| Status           | Meaning                   | Your Action                         |
| ---------------- | ------------------------- | ----------------------------------- |
| `completed`      | Done immediately          | Process the result                  |
| `working`        | Processing (\~2 min)      | Poll frequently or wait for webhook |
| `submitted`      | Long-running (hours/days) | Use webhooks or poll infrequently   |
| `input-required` | Needs your input          | Read message, respond with info     |
| `failed`         | Error occurred            | Handle the error                    |

**Note:** For the complete status list see [Core Concepts - Task Status System](/dist/docs/2.5.3/protocols/task-management#task-status-system).

<Tabs>
  <Tab title="MCP">
    ### Immediate Success (`completed`)

    The task completed synchronously. No async handling needed.

    **Request:**

    ```javascript theme={null}
    const response = await session.call('create_media_buy', {
      buyer_ref: 'summer_campaign_2025',
      brand_manifest: { name: 'Nike', url: 'https://nike.com' },
      packages: [
        {
          buyer_ref: 'ctv_package',
          product_id: 'prod_ctv_sports',
          pricing_option_id: 'cpm_fixed',
          budget: 50000
        }
      ]
    });
    ```

    **Response:**

    ```json theme={null}
    {
      "status": "completed",
      "media_buy_id": "mb_12345",
      "buyer_ref": "summer_campaign_2025",
      "creative_deadline": "2025-06-15T23:59:59Z",
      "packages": [
        {
          "package_id": "pkg_001",
          "buyer_ref": "ctv_package",
          "product_id": "prod_ctv_sports"
        }
      ]
    }
    ```

    ### Long-Running (`submitted`)

    The task is queued for manual approval. Configure a webhook to receive updates.

    **Request with webhook:**

    ```javascript theme={null}
    const response = await session.call('create_media_buy',
      {
        buyer_ref: 'enterprise_campaign',
        brand_manifest: { name: 'Nike', url: 'https://nike.com' },
        packages: [
          {
            buyer_ref: 'premium_package',
            product_id: 'prod_premium_ctv',
            pricing_option_id: 'cpm_fixed',
            budget: 500000  // Large budget triggers approval
          }
        ]
      },
      {
        pushNotificationConfig: {
          url: 'https://your-app.com/webhooks/adcp',
          authentication: {
            schemes: ['bearer'],
            credentials: 'your_webhook_secret'
          }
        }
      }
    );
    ```

    **Initial response:**

    ```json theme={null}
    {
      "status": "submitted",
      "task_id": "task_abc123",
      "message": "Budget exceeds auto-approval limit. Sales review required (2-4 hours)."
    }
    ```

    **Webhook POST when approved:**

    ```json theme={null}
    {
      "task_id": "task_abc123",
      "task_type": "create_media_buy",
      "status": "completed",
      "timestamp": "2025-01-22T14:30:00Z",
      "message": "Media buy approved and created",
      "result": {
        "media_buy_id": "mb_67890",
        "buyer_ref": "enterprise_campaign",
        "creative_deadline": "2025-06-20T23:59:59Z",
        "packages": [
          {
            "package_id": "pkg_002",
            "buyer_ref": "premium_package"
          }
        ]
      }
    }
    ```

    ### Error (`failed`)

    **Response:**

    ```json theme={null}
    {
      "status": "failed",
      "errors": [
        {
          "code": "INSUFFICIENT_INVENTORY",
          "message": "Requested targeting yields no available impressions",
          "field": "packages[0].targeting",
          "suggestion": "Expand geographic targeting or increase CPM bid"
        }
      ]
    }
    ```
  </Tab>

  <Tab title="A2A">
    ### Immediate Success (`completed`)

    **Request:**

    ```javascript theme={null}
    const response = await a2a.send({
      message: {
        parts: [{
          kind: 'data',
          data: {
            skill: 'create_media_buy',
            parameters: {
              buyer_ref: 'summer_campaign_2025',
              brand_manifest: { name: 'Nike', url: 'https://nike.com' },
              packages: [
                {
                  buyer_ref: 'ctv_package',
                  product_id: 'prod_ctv_sports',
                  pricing_option_id: 'cpm_fixed',
                  budget: 50000
                }
              ]
            }
          }
        }]
      }
    });
    ```

    **Response:**

    ```json theme={null}
    {
      "status": "completed",
      "taskId": "task_123",
      "contextId": "ctx_456",
      "artifacts": [{
        "parts": [
          { "text": "Media buy created successfully" },
          {
            "data": {
              "media_buy_id": "mb_12345",
              "buyer_ref": "summer_campaign_2025",
              "creative_deadline": "2025-06-15T23:59:59Z",
              "packages": [
                {
                  "package_id": "pkg_001",
                  "buyer_ref": "ctv_package"
                }
              ]
            }
          }
        ]
      }]
    }
    ```

    ### Processing (`working`)

    Task is actively processing. Use SSE streaming or poll for updates.

    **Initial response:**

    ```json theme={null}
    {
      "status": "working",
      "taskId": "task_789",
      "contextId": "ctx_456"
    }
    ```

    **SSE status update:**

    ```json theme={null}
    {
      "taskId": "task_789",
      "status": {
        "state": "working",
        "message": {
          "parts": [
            { "text": "Validating inventory availability..." },
            {
              "data": {
                "percentage": 50,
                "current_step": "inventory_check"
              }
            }
          ]
        }
      }
    }
    ```

    ### Long-Running (`submitted`)

    **Request with push notification:**

    ```javascript theme={null}
    const response = await a2a.send({
      message: {
        parts: [{
          kind: 'data',
          data: {
            skill: 'create_media_buy',
            parameters: {
              buyer_ref: 'enterprise_campaign',
              packages: [{ budget: 500000 }]  // Triggers approval
            }
          }
        }]
      },
      pushNotificationConfig: {
        url: 'https://your-app.com/webhooks/a2a',
        authentication: {
          schemes: ['bearer'],
          credentials: 'your_webhook_secret'
        }
      }
    });
    ```

    **Initial response:**

    ```json theme={null}
    {
      "status": "submitted",
      "taskId": "task_abc",
      "contextId": "ctx_456"
    }
    ```

    **Webhook POST (Task) when completed:**

    ```json theme={null}
    {
      "id": "task_abc",
      "contextId": "ctx_456",
      "status": {
        "state": "completed",
        "message": {
          "parts": [
            { "text": "Media buy approved and created" },
            {
              "data": {
                "media_buy_id": "mb_67890",
                "buyer_ref": "enterprise_campaign",
                "packages": [{ "package_id": "pkg_002" }]
              }
            }
          ]
        },
        "timestamp": "2025-01-22T14:30:00Z"
      }
    }
    ```

    ### Input Required (`input-required`)

    Task is paused waiting for clarification or approval.

    **Response:**

    ```json theme={null}
    {
      "status": "input-required",
      "taskId": "task_def",
      "contextId": "ctx_456",
      "artifacts": [{
        "parts": [
          { "text": "The requested budget exceeds your pre-approved limit. Please confirm you want to proceed with $500K spend." },
          {
            "data": {
              "reason": "APPROVAL_REQUIRED",
              "errors": [
                {
                  "code": "BUDGET_EXCEEDS_LIMIT",
                  "message": "Requested budget exceeds pre-approved limit",
                  "field": "total_budget"
                }
              ]
            }
          }
        ]
      }]
    }
    ```

    **Follow-up to approve:**

    ```javascript theme={null}
    await a2a.send({
      contextId: 'ctx_456',  // Continue the conversation
      message: {
        parts: [{ kind: 'text', text: 'Yes, I confirm the $500K budget' }]
      }
    });
    ```

    ### Error (`failed`)

    **Response:**

    ```json theme={null}
    {
      "status": "failed",
      "taskId": "task_xyz",
      "artifacts": [{
        "parts": [
          { "text": "Failed to create media buy" },
          {
            "data": {
              "errors": [
                {
                  "code": "INSUFFICIENT_INVENTORY",
                  "message": "Requested targeting yields no available impressions",
                  "suggestion": "Expand geographic targeting"
                }
              ]
            }
          }
        ]
      }]
    }
    ```
  </Tab>
</Tabs>

For complete async handling patterns, see [Task Management](/dist/docs/2.5.3/protocols/task-management).

## Usage Notes

* Total budget is distributed across packages based on individual `budget` values
* Both media buys and packages have `buyer_ref` fields for tracking
* Creative assets must be uploaded before deadline for campaign activation
* AXE segments enable advanced audience targeting
* Pending states (`working`, `submitted`) are normal, not errors
* Orchestrators MUST handle pending states as part of normal workflow

## Policy Compliance

Brand and products are validated during creation. Policy violations return errors:

```json theme={null}
{
  "errors": [{
    "code": "POLICY_VIOLATION",
    "message": "Brand or product category not permitted on this publisher",
    "field": "brand_manifest",
    "suggestion": "Contact publisher for category approval process"
  }]
}
```

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. **Upload Creatives**: Use [`sync_creatives`](/dist/docs/2.5.3/media-buy/task-reference/sync_creatives) before deadline
2. **Monitor Status**: Use [`get_media_buy_delivery`](/dist/docs/2.5.3/media-buy/task-reference/get_media_buy_delivery)
3. **Optimize**: Use [`provide_performance_feedback`](/dist/docs/2.5.3/media-buy/task-reference/provide_performance_feedback)
4. **Update**: Use [`update_media_buy`](/dist/docs/2.5.3/media-buy/task-reference/update_media_buy) to modify campaign

## Learn More

* [Media Buy Lifecycle](/dist/docs/2.5.3/media-buy/media-buys/) - Complete campaign workflow
* [get\_products](/dist/docs/2.5.3/media-buy/task-reference/get_products) - Discover inventory
* [Targeting](/dist/docs/2.5.3/media-buy/advanced-topics/targeting) - Targeting strategies
* [Pricing Models](/dist/docs/2.5.3/media-buy/advanced-topics/pricing-models) - Currency and pricing
