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

# get_products

Discover available advertising products based on campaign requirements using natural language briefs or structured filters.

**Authentication**: Optional (returns limited results without credentials)

**Response Time**: \~60 seconds (AI inference with back-end systems)

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

## Quick Start

Discover products with a natural language brief:

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

  const result = await testAgent.getProducts({
    brief: 'Premium athletic footwear with innovative cushioning',
    brand_manifest: {
      name: 'Nike',
      url: 'https://nike.com'
    }
  });

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

  // Validate response against schema
  const validated = GetProductsResponseSchema.parse(result.data);
  console.log(`Found ${validated.products.length} products`);

  // Access validated product fields
  for (const product of validated.products) {
    console.log(`- ${product.name} (${product.delivery_type})`);
    console.log(`  Formats: ${product.format_ids.map(f => f.id).join(', ')}`);
  }
  ```

  ```python Python theme={null}
  import asyncio
  from adcp import test_agent

  async def discover_products():
      result = await test_agent.simple.get_products(
          brief='Premium athletic footwear with innovative cushioning',
          brand_manifest={
              'name': 'Nike',
              'url': 'https://nike.com'
          }
      )
      print(f"Found {len(result.products)} products")

  asyncio.run(discover_products())
  ```

  ```bash CLI theme={null}
  uvx adcp \
    https://test-agent.adcontextprotocol.org/mcp \
    get_products \
    '{"brief":"Premium athletic footwear with innovative cushioning","brand_manifest":{"name":"Nike","url":"https://nike.com"}}' \
    --auth 1v8tAhASaUYYp4odoQ1PnMpdqNaMiTrCRqYo9OJp6IQ
  ```
</CodeGroup>

### Using Structured Filters

You can also use structured filters instead of (or in addition to) a brief:

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

  const result = await testAgent.getProducts({
    brand_manifest: {
      name: 'Nike',
      url: 'https://nike.com'
    },
    filters: {
      format_types: ['video'],
      delivery_type: 'guaranteed',
      standard_formats_only: true
    }
  });

  if (result.success && result.data) {
    console.log(`Found ${result.data.products.length} guaranteed video products`);
  }
  ```

  ```python Python theme={null}
  import asyncio
  from adcp import test_agent

  async def discover_with_filters():
      result = await test_agent.simple.get_products(
          brand_manifest={
              'name': 'Nike',
              'url': 'https://nike.com'
          },
          filters={
              'format_types': ['video'],
              'delivery_type': 'guaranteed',
              'standard_formats_only': True
          }
      )
      print(f"Found {len(result.products)} guaranteed video products")

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

## Request Parameters

| Parameter        | Type                    | Required | Description                                                                                              |
| ---------------- | ----------------------- | -------- | -------------------------------------------------------------------------------------------------------- |
| `brief`          | string                  | No       | Natural language description of campaign requirements                                                    |
| `brand_manifest` | BrandManifest \| string | No       | Brand information (inline object or URL). See [Brand Manifest](/dist/docs/2.5.3/creative/brand-manifest) |
| `filters`        | Filters                 | No       | Structured filters (see below)                                                                           |

### Filters Object

| Parameter               | Type        | Description                                                                                     |
| ----------------------- | ----------- | ----------------------------------------------------------------------------------------------- |
| `delivery_type`         | string      | Filter by `"guaranteed"` or `"non_guaranteed"`                                                  |
| `is_fixed_price`        | boolean     | Filter for fixed price vs auction products                                                      |
| `format_types`          | string\[]   | Filter by format types (e.g., `["video", "display"]`)                                           |
| `format_ids`            | FormatID\[] | Filter by specific format IDs                                                                   |
| `standard_formats_only` | boolean     | Only return products accepting IAB standard formats                                             |
| `min_exposures`         | integer     | Minimum exposures needed for measurement validity                                               |
| `start_date`            | string      | Campaign start date in ISO 8601 format (YYYY-MM-DD) for availability checks                     |
| `end_date`              | string      | Campaign end date in ISO 8601 format (YYYY-MM-DD) for availability checks                       |
| `budget_range`          | object      | Budget range to filter appropriate products (see Budget Range Object below)                     |
| `countries`             | string\[]   | Filter by target countries using ISO 3166-1 alpha-2 codes (e.g., `["US", "CA", "GB"]`)          |
| `channels`              | string\[]   | Filter by advertising channels (e.g., `["display", "video", "dooh", "ctv", "audio", "native"]`) |

### Budget Range Object

| Parameter  | Type   | Required | Description                                              |
| ---------- | ------ | -------- | -------------------------------------------------------- |
| `currency` | string | Yes      | ISO 4217 currency code (e.g., `"USD"`, `"EUR"`, `"GBP"`) |
| `min`      | number | No\*     | Minimum budget amount                                    |
| `max`      | number | No\*     | Maximum budget amount                                    |

\*At least one of `min` or `max` must be specified.

## Response

Returns an array of `products`, each containing:

| Field                  | Type                 | Description                                                                                           |
| ---------------------- | -------------------- | ----------------------------------------------------------------------------------------------------- |
| `product_id`           | string               | Unique product identifier                                                                             |
| `name`                 | string               | Human-readable product name                                                                           |
| `description`          | string               | Detailed product description                                                                          |
| `publisher_properties` | PublisherProperty\[] | Array of publisher entries, each with `publisher_domain` and either `property_ids` or `property_tags` |
| `format_ids`           | FormatID\[]          | Supported creative format IDs                                                                         |
| `delivery_type`        | string               | `"guaranteed"` or `"non_guaranteed"`                                                                  |
| `delivery_measurement` | DeliveryMeasurement  | How delivery is measured (impressions, views, etc.)                                                   |
| `pricing_options`      | PricingOption\[]     | Available pricing models (CPM, CPCV, etc.)                                                            |
| `brief_relevance`      | string               | Why this product matches the brief (when brief provided)                                              |

**See schema for complete field list**: [`get-products-response.json`](https://adcontextprotocol.org/schemas/v2/media-buy/get-products-response.json)

## Common Scenarios

### Standard Catalog Discovery

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

  // No brief = standard catalog products for maximum reach
  const result = await testAgent.getProducts({
    brand_manifest: {
      name: 'Nike',
      url: 'https://nike.com'
    },
    filters: {
      delivery_type: 'non_guaranteed'
    }
  });

  if (result.success && result.data) {
    console.log(`Found ${result.data.products.length} standard catalog products`);
  }
  ```

  ```python Python theme={null}
  import asyncio
  from adcp import test_agent

  async def discover_standard_catalog():
      # No brief = standard catalog products for maximum reach
      result = await test_agent.simple.get_products(
          brand_manifest={
              'name': 'Nike',
              'url': 'https://nike.com'
          },
          filters={
              'delivery_type': 'non_guaranteed'
          }
      )
      print(f"Found {len(result.products)} standard catalog products")

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

### Multi-Format Discovery

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

  // Find products supporting both video and display
  const result = await testAgent.getProducts({
    brief: 'Brand awareness campaign with video and display',
    brand_manifest: {
      name: 'Nike',
      url: 'https://nike.com'
    },
    filters: {
      format_types: ['video', 'display']
    }
  });

  if (result.success && result.data) {
    console.log(`Found ${result.data.products.length} products supporting video and display`);
  }
  ```

  ```python Python theme={null}
  import asyncio
  from adcp import test_agent

  async def discover_multi_format():
      # Find products supporting both video and display
      result = await test_agent.simple.get_products(
          brief='Brand awareness campaign with video and display',
          brand_manifest={
              'name': 'Nike',
              'url': 'https://nike.com'
          },
          filters={
              'format_types': ['video', 'display']
          }
      )
      print(f"Found {len(result.products)} products supporting video and display")

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

### Budget and Date Filtering

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

  // Find products within budget and date range for specific countries and channels
  const result = await testAgent.getProducts({
    brief: 'Q2 campaign for athletic footwear in North America',
    brand_manifest: {
      name: 'Nike',
      url: 'https://nike.com'
    },
    filters: {
      start_date: '2025-04-01',
      end_date: '2025-06-30',
      budget_range: {
        min: 50000,
        max: 100000,
        currency: 'USD'
      },
      countries: ['US', 'CA'],
      channels: ['display', 'video', 'ctv'],
      delivery_type: 'guaranteed'
    }
  });

  if (result.success && result.data) {
    console.log(`Found ${result.data.products.length} products for Q2 within budget`);
  }
  ```

  ```python Python theme={null}
  import asyncio
  from adcp import test_agent

  async def discover_with_budget_and_dates():
      # Find products within budget and date range for specific countries and channels
      result = await test_agent.simple.get_products(
          brief='Q2 campaign for athletic footwear in North America',
          brand_manifest={
              'name': 'Nike',
              'url': 'https://nike.com'
          },
          filters={
              'start_date': '2025-04-01',
              'end_date': '2025-06-30',
              'budget_range': {
                  'min': 50000,
                  'max': 100000,
                  'currency': 'USD'
              },
              'countries': ['US', 'CA'],
              'channels': ['display', 'video', 'ctv'],
              'delivery_type': 'guaranteed'
          }
      )
      print(f"Found {len(result.products)} products for Q2 within budget")

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

### Property Tag Resolution

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

  // Get products with property tags
  const result = await testAgent.getProducts({
    brief: 'Sports content',
    brand_manifest: {
      name: 'Nike',
      url: 'https://nike.com'
    }
  });

  if (result.success && result.data) {
    // Products with property_tags in publisher_properties need resolution via list_authorized_properties
    const productsWithTags = result.data.products.filter(p =>
      p.publisher_properties?.some(pub => pub.property_tags && pub.property_tags.length > 0)
    );
    console.log(`${productsWithTags.length} products use property tags (large networks)`);
  }
  ```

  ```python Python theme={null}
  import asyncio
  from adcp import test_agent

  async def discover_property_tags():
      # Get products with property tags
      result = await test_agent.simple.get_products(
          brief='Sports content',
          brand_manifest={
              'name': 'Nike',
              'url': 'https://nike.com'
          }
      )

      # Products with property_tags in publisher_properties need resolution via list_authorized_properties
      products_with_tags = [p for p in result.products
          if any(pub.get('property_tags') for pub in p.get('publisher_properties', []))]
      print(f"{len(products_with_tags)} products use property tags (large networks)")

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

### Guaranteed Delivery Products

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

  // Find guaranteed delivery products for measurement
  const result = await testAgent.getProducts({
    brief: 'Guaranteed delivery for lift study',
    brand_manifest: {
      name: 'Nike',
      url: 'https://nike.com'
    },
    filters: {
      delivery_type: 'guaranteed',
      min_exposures: 100000
    }
  });

  if (result.success && result.data) {
    console.log(`Found ${result.data.products.length} guaranteed products with 100k+ exposures`);
  }
  ```

  ```python Python theme={null}
  import asyncio
  from adcp import test_agent

  async def discover_guaranteed():
      # Find guaranteed delivery products for measurement
      result = await test_agent.simple.get_products(
          brief='Guaranteed delivery for lift study',
          brand_manifest={
              'name': 'Nike',
              'url': 'https://nike.com'
          },
          filters={
              'delivery_type': 'guaranteed',
              'min_exposures': 100000
          }
      )
      print(f"Found {len(result.products)} guaranteed products with 100k+ exposures")

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

### Standard Formats Only

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

  // Find products that only accept IAB standard formats
  const result = await testAgent.getProducts({
    brand_manifest: {
      name: 'Nike',
      url: 'https://nike.com'
    },
    filters: {
      standard_formats_only: true
    }
  });

  if (result.success && result.data) {
    console.log(`Found ${result.data.products.length} products with standard formats only`);
  }
  ```

  ```python Python theme={null}
  import asyncio
  from adcp import test_agent

  async def discover_standard_formats():
      # Find products that only accept IAB standard formats
      result = await test_agent.simple.get_products(
          brand_manifest={
              'name': 'Nike',
              'url': 'https://nike.com'
          },
          filters={
              'standard_formats_only': True
          }
      )
      print(f"Found {len(result.products)} products with standard formats only")

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

## Error Handling

| Error Code         | Description                            | Resolution                              |
| ------------------ | -------------------------------------- | --------------------------------------- |
| `AUTH_REQUIRED`    | Authentication needed for full catalog | Provide credentials via auth header     |
| `INVALID_REQUEST`  | Brief too long or malformed filters    | Check request parameters                |
| `POLICY_VIOLATION` | Category blocked for advertiser        | See policy response message for details |

### Authentication Comparison

See the difference between authenticated and unauthenticated access:

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

  // WITH authentication - full catalog with pricing
  const fullCatalog = await testAgent.getProducts({
    brief: 'Premium CTV inventory for brand awareness',
    brand_manifest: {
      name: 'Nike',
      url: 'https://nike.com'
    }
  });

  if (!fullCatalog.success) {
    throw new Error(`Failed to get products: ${fullCatalog.error}`);
  }

  console.log(`With auth: ${fullCatalog.data.products.length} products`);
  console.log(`First product pricing: ${fullCatalog.data.products[0].pricing_options.length} options`);

  // WITHOUT authentication - limited public catalog
  const publicCatalog = await testAgentNoAuth.getProducts({
    brief: 'Premium CTV inventory for brand awareness',
    brand_manifest: {
      name: 'Nike',
      url: 'https://nike.com'
    }
  });

  if (!publicCatalog.success) {
    throw new Error(`Failed to get products: ${publicCatalog.error}`);
  }

  console.log(`Without auth: ${publicCatalog.data.products.length} products`);
  console.log(`First product pricing: ${publicCatalog.data.products[0].pricing_options?.length || 0} options`);
  ```

  ```python Python theme={null}
  import asyncio
  from adcp import test_agent, test_agent_no_auth

  async def compare_auth():
      # WITH authentication - full catalog with pricing
      full_catalog = await test_agent.simple.get_products(
          brief='Premium CTV inventory for brand awareness',
          brand_manifest={
              'name': 'Nike',
              'url': 'https://nike.com'
          }
      )

      print(f"With auth: {len(full_catalog['products'])} products")
      print(f"First product pricing: {len(full_catalog['products'][0]['pricing_options'])} options")

      # WITHOUT authentication - limited public catalog
      public_catalog = await test_agent_no_auth.simple.get_products(
          brief='Premium CTV inventory for brand awareness',
          brand_manifest={
              'name': 'Nike',
              'url': 'https://nike.com'
          }
      )

      print(f"Without auth: {len(public_catalog['products'])} products")
      print(f"First product pricing: {len(public_catalog['products'][0].get('pricing_options', []))} options")

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

**Key Differences:**

* **Product Count**: Authenticated access returns more products, including private/custom offerings
* **Pricing Information**: Only authenticated requests receive detailed pricing options (CPM, CPCV, etc.)
* **Targeting Details**: Custom targeting capabilities may be restricted to authenticated users
* **Rate Limits**: Unauthenticated requests have lower rate limits

## Authentication Behavior

* **Without credentials**: Returns limited catalog (standard catalog products), no pricing, no custom offerings
* **With credentials**: Returns complete catalog with pricing and custom products

See [Authentication Guide](/dist/docs/2.5.3/reference/authentication) for details.

## Asynchronous Operations

Most product searches complete immediately, but some scenarios require asynchronous processing. When this happens, you'll receive a status other than `completed` and can track progress through webhooks or polling.

### When Search Runs Asynchronously

Product search may require async processing in these situations:

* **Complex searches**: Searching across multiple inventory sources or custom curation
* **Needs clarification**: Your brief is vague and the system needs more information
* **Custom products**: Bespoke product packages that require human review

### Async Status Flow

<Tabs>
  <Tab title="MCP">
    #### Immediate Completion (Most Common)

    ```json theme={null}
    POST /api/mcp/call_tool

    {
      "name": "get_products",
      "arguments": {
        "brief": "CTV inventory for sports audience",
        "brand_manifest": { "name": "Nike", "url": "https://nike.com" }
      }
    }

    Response (200 OK):
    {
      "status": "completed",
      "message": "Found 3 products matching your requirements",
      "data": {
        "products": [...]
      }
    }
    ```

    #### Needs Clarification

    When the brief is unclear, the system asks for more details:

    ```json theme={null}
    Response (200 OK):
    {
      "status": "input-required",
      "message": "I need a bit more information. What's your budget range and campaign duration?",
      "task_id": "task_789",
      "context_id": "ctx_123",
      "data": {
        "reason": "CLARIFICATION_NEEDED",
        "partial_results": [],
        "suggestions": ["$50K-$100K", "1 month", "Q1 2024"]
      }
    }
    ```

    Continue the conversation with the same `context_id`:

    ```json theme={null}
    POST /api/mcp/continue

    {
      "context_id": "ctx_123",
      "message": "Budget is $75K for a 3-week campaign in March"
    }

    Response (200 OK):
    {
      "status": "completed",
      "message": "Perfect! Found 5 products within your budget",
      "data": {
        "products": [...]
      }
    }
    ```

    #### Complex Search (With Webhook)

    For searches requiring deep inventory analysis, configure a webhook:

    ```json theme={null}
    POST /api/mcp/call_tool

    {
      "name": "get_products",
      "arguments": {
        "brief": "Premium inventory across all formats for luxury automotive brand",
        "brand_manifest": { "name": "Porsche", "url": "https://porsche.com" },
        "pushNotificationConfig": {
          "url": "https://buyer.com/webhooks/adcp/get_products",
          "authentication": {
            "schemes": ["Bearer"],
            "credentials": "secret_token_32_chars"
          }
        }
      }
    }

    Response (200 OK):
    {
      "status": "working",
      "message": "Searching premium inventory across display, video, and audio",
      "task_id": "task_456",
      "context_id": "ctx_123",
      "data": {
        "percentage": 10,
        "current_step": "searching_inventory"
      }
    }

    // Later, webhook POST to https://buyer.com/webhooks/adcp/get_products
    {
      "task_id": "task_456",
      "task_type": "get_products",
      "status": "completed",
      "timestamp": "2025-01-22T10:30:00Z",
      "message": "Found 12 premium products across all formats",
      "result": {
        "products": [...]
      }
    }
    ```
  </Tab>

  <Tab title="A2A">
    #### Immediate Completion (Most Common)

    ```json theme={null}
    POST /api/a2a

    {
      "message": {
        "role": "user",
        "parts": [{
          "kind": "data",
          "data": {
            "skill": "get_products",
            "parameters": {
              "brief": "CTV inventory for sports audience",
              "brand_manifest": { "name": "Nike", "url": "https://nike.com" }
            }
          }
        }]
      }
    }

    Response (200 OK):
    {
      "id": "task_123",
      "contextId": "ctx_456",
      "artifact": {
        "kind": "data",
        "data": {
          "products": [...]
        }
      },
      "status": {
        "state": "completed",
        "message": {
          "role": "agent",
          "parts": [{ "text": "Found 3 products matching your requirements" }]
        }
      }
    }
    ```

    #### Needs Clarification

    Real-time updates via SSE when clarification is needed:

    ```json theme={null}
    // Initial response
    {
      "id": "task_789",
      "contextId": "ctx_123",
      "status": {
        "state": "input-required",
        "message": {
          "role": "agent",
          "parts": [
            { "text": "I need a bit more information. What's your budget range and campaign duration?" },
            {
              "data": {
                "reason": "CLARIFICATION_NEEDED",
                "suggestions": ["$50K-$100K", "1 month", "Q1 2024"]
              }
            }
          ]
        }
      }
    }

    // Send follow-up
    POST /api/a2a

    {
      "contextId": "ctx_123",
      "message": {
        "role": "user",
        "parts": [{ "text": "Budget is $75K for a 3-week campaign in March" }]
      }
    }

    // SSE update: task completed
    {
      "id": "task_789",
      "contextId": "ctx_123",
      "artifact": {
        "kind": "data",
        "data": { "products": [...] }
      },
      "status": {
        "state": "completed",
        "message": {
          "role": "agent",
          "parts": [{ "text": "Perfect! Found 5 products within your budget" }]
        }
      }
    }
    ```

    #### Complex Search (With Webhook)

    Configure push notifications for long searches:

    ```json theme={null}
    POST /api/a2a

    {
      "message": {
        "role": "user",
        "parts": [{
          "kind": "data",
          "data": {
            "skill": "get_products",
            "parameters": {
              "brief": "Premium inventory across all formats for luxury automotive brand",
              "brand_manifest": { "name": "Porsche", "url": "https://porsche.com" }
            }
          }
        }]
      },
      "pushNotificationConfig": {
        "url": "https://buyer.com/webhooks/a2a/get_products",
        "authentication": {
          "schemes": ["bearer"],
          "credentials": "secret_token_32_chars"
        }
      }
    }

    Response (200 OK):
    {
      "id": "task_456",
      "contextId": "ctx_789",
      "status": {
        "state": "working",
        "message": {
          "role": "agent",
          "parts": [
            { "text": "Searching premium inventory across display, video, and audio" },
            {
              "data": {
                "percentage": 10,
                "current_step": "searching_inventory"
              }
            }
          ]
        }
      }
    }

    // Later, webhook POST to https://buyer.com/webhooks/a2a/get_products
    {
      "id": "task_456",
      "contextId": "ctx_789",
      "artifact": {
        "kind": "data",
        "data": {
          "products": [...]
        }
      },
      "status": {
        "state": "completed",
        "message": {
          "role": "agent",
          "parts": [
            { "text": "Found 12 premium products across all formats" },
            {
              "data": {
                "products": [...]
              }
            }
          ]
        },
        "timestamp": "2025-01-22T10:30:00Z"
      }
    }
    ```
  </Tab>
</Tabs>

### Status Overview

| Status           | When It Happens                   | What You Do                          |
| ---------------- | --------------------------------- | ------------------------------------ |
| `completed`      | Search finished successfully      | Process the product results          |
| `input-required` | Need clarification on the brief   | Answer the question and continue     |
| `working`        | Searching across multiple sources | Wait for webhook or poll for updates |
| `submitted`      | Custom curation queued            | Wait for webhook notification        |
| `failed`         | Search couldn't complete          | Check error message, adjust brief    |

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

**Most searches complete immediately.** Async processing is only needed for complex scenarios or when the system needs your input.

## Next Steps

After discovering products:

1. **Review Options**: Compare products, pricing, and targeting capabilities
2. **Create Media Buy**: Use [`create_media_buy`](/dist/docs/2.5.3/media-buy/task-reference/create_media_buy) to execute campaign
3. **Prepare Creatives**: Use [`list_creative_formats`](/dist/docs/2.5.3/media-buy/task-reference/list_creative_formats) to see format requirements
4. **Upload Assets**: Use [`sync_creatives`](/dist/docs/2.5.3/media-buy/task-reference/sync_creatives) to provide creative assets

## Learn More

* [Product Discovery Guide](/dist/docs/2.5.3/media-buy/product-discovery/) - Understanding briefs and products
* [Pricing Models](/dist/docs/2.5.3/media-buy/advanced-topics/pricing-models) - CPM, CPCV, CPP explained
* [Brief Expectations](/dist/docs/2.5.3/media-buy/product-discovery/brief-expectations) - How to write effective briefs
* [Media Products](/dist/docs/2.5.3/media-buy/product-discovery/media-products) - Product structure and fields
