> ## Documentation Index
> Fetch the complete documentation index at: https://docs.apostra.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Create products from ad-server inventory

> Turn synced ad-server inventory into validated product drafts in Inventory Components or through your storefront agent

Once your ad server (Google Ad Manager, FreeWheel, SpringServe, or AdsWizz) is connected and its inventory has synced, you turn that inventory into **products** buyers can discover and buy. Open **Inventory Components** to do the whole job directly, or describe an exact product to your storefront agent and let it use the same typed product tools for you.

## Three things called "product"

Worth separating before you start, because they behave differently and only one of them is yours to author:

|                                | What it is                                                                                                                                                                                                                                                                        | Who authors it          |
| ------------------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------- |
| **Wholesale product** (`wh:…`) | What this page is about. You author it from your ad-server inventory. `active` ones are directly discoverable by buyers, and on a ready [Storefront-built product path](/v2/storefront/products/product-composition) they also become inputs the Merchandising Agent builds from. | **You**                 |
| **Composed product** (`cf_…`)  | Built to a specific brief at discovery time from your wholesale products and your rules. Buyers cannot tell it from a hand-authored one.                                                                                                                                          | The Merchandising Agent |
| **Passthrough product**        | A third-party sales agent's own buyer-facing products, returned as-is. Not composition inputs.                                                                                                                                                                                    | Your third-party agent  |

A **component** is none of these — it is the raw ad-server material (ad units, placements, targeting) you select *from* when authoring. You never author a component.

If your source is a third-party sales agent rather than a managed one, its products live in that agent and you author them there; Apostra reads them.

## How a product gets created

Both paths follow the same server contract, so you see the exact request before anything is saved:

1. **Pick inventory.** Choose the ad-server objects to package, such as ad units or placements from your synced inventory. If the package uses GAM key-values for targeting, create signals from that ad-server targeting rather than putting raw key-values in the inventory selector bundle.
2. **Draft.** In Inventory Components, select reviewed components, enter a product name and optional description, and choose the delivery options buyers can use. Each option shows practical details such as media type, dimensions, and video length. Choose the publisher-property coverage this product declares from the options your ad server lists: everything sold under one publisher, specific properties, or specific tags. For a representation network, the publisher shown is the network while its represented sites are the individual properties. When exactly one option is available, the form preselects it; with several, choose the one that covers the product. The Inventory Selector task offers the same form after you pick exact ad-server rows. When you start from **Create product** in Property Roster, the publisher requirement is already attached and only compatible delivery options are shown. Neither widget sends the selection back into chat.
3. **Validate.** Choose **Review product**. This checks that the selected inventory can deliver every option before anything is saved and surfaces field-level issues (see [What validation surfaces](#what-validation-surfaces)).
4. **Confirm and create.** Choose **Create draft product** only after validation succeeds. That explicit click saves the exact reviewed request as `draft`; it is not visible to buyers until you activate it.

After creation, the task confirms the draft and points you to Inventory Components, where you can manage or activate it. If you created it inside Inventory Components, the Products tab refreshes automatically. In chat, the agent confirms the product landed by listing your products back to you.

### FreeWheel products need an Ad Unit or Ad Unit Package

Choose at least one **Ad Unit**, **Ad Unit Package**, or a combination of both
to identify the FreeWheel delivery opportunities for a product. Content scope,
such as a site, site group, series, or video group, is a separate optional
selection. Content scope alone cannot receive creatives.

Inventory Components follows the selection rule returned by the connected
FreeWheel source. It lists the direct ad units and packages that source makes
available, so a network can work with either inventory model without a
seller-specific setting. If neither type has eligible inventory, the form says
so and blocks review. A failed inventory request produces a separate retryable
error and also blocks review. Google Ad Manager, SpringServe, and other adapters
do not show or require this FreeWheel field.

## Edit an existing product

In **Inventory Components** → **Products**, choose **Edit** to load the complete product definition before changing it. The editor shows the channels and delivery type, every canonical format option with its parameters (including dimensions and duration), the inventory selectors and placements, targeting capabilities, video placement types, and every pricing option with its model, rate or floor, currency, and delivery type.

Choose **Save changes** to validate the complete product first. Any blocking problem names the field and how to correct it; nothing is saved until validation passes. The save then changes only the fields you edited, so a name or status update cannot clear pricing, coverage, formats, placements, or targeting that you left unchanged. Blank or `null` JSON does not mean "clear": correct it to a valid value or cancel to retain the original value. Delivery type can be changed only to a supported value; it cannot be cleared because the source PATCH contract has no clearing value. Product IDs, timestamps, source-owned permissions, and any other source-managed fields remain visible but are explicitly read-only in this screen.

Legacy FreeWheel products that do not meet the source's current selection rule
can still be renamed, described, activated, or archived. Changing their
inventory is a repair: retain the publisher properties separately and add a
current FreeWheel Ad Unit or Ad Unit Package under
`inventory.execution.selectors` before saving.

## Buyer-facing AdCP compatibility

Author products with canonical delivery options. Inventory-feed payloads use
`formatOptions[]`; the corresponding AdCP 3.1 buyer response uses
`format_options[]`, with a stable `format_option_id`, a `format_kind`, and any
format-specific `params`.

Storefront negotiates the response for the buyer's AdCP version:

* AdCP 3.1 clients receive the canonical `format_options[]` declarations.
* AdCP 3.0 clients receive the required legacy `format_ids[]` projection when
  the seller has published a valid mapping for the canonical option.
* If a canonical option cannot be projected safely, validation fails closed;
  Storefront does not invent a legacy format identity.

Custom Storefront response metadata now lives under
`ext.scope3.storefront`. Integrations that previously read
`extensions.scope3.storefront` must move to the `ext` path. Demo responses use
`ext.scope3.storefront.demo` and
`ext.scope3.storefront.demo_disclosure`; see [Demo Storefront](/v2/storefront/inventory-sources/demo-storefront).

## Make a product ready for proposals

The proposal composer can pitch an active product only when it has a channel,
a canonical URL-free format, and a priced option with a currency and delivery
type. `save_wholesale_product` accepts `channels` when you need to set that
fact yourself. Use the same AdCP channel codes the storefront uses, such as
`display`, `olv`, `ctv`, and `streaming_audio`.

For a managed source that returns no channel, Apostra infers a channel only
when its canonical creative format maps to exactly one composer-compatible
channel. Ambiguous formats, including common video and audio formats, remain
unclassified so you can state the intended `channels` yourself. Your non-empty
`channels` declaration always wins over that fallback.

For GAM, this means `video_vast`, `image`, and `html5` always need explicit
`channels`: each is compatible with several composer channels, so inferring one
would guess at the commercial placement. This fail-closed rule is intentional.

Pricing coverage alone is not a price the composer can quote. A positive fixed
price or platform-derived floor with its pricing-option ID, pricing model, ISO
currency, and `guaranteed` or `non_guaranteed` delivery type is quoteable. A
bare non-fixed `rate` without a fixed price or floor is not quoteable. The
product read reports any remaining request-independent
`composerCompleteness.missing` facts beside `pricingStatus`, so a
source-reported `priced` status cannot hide a product that still lacks a
quoteable option. A particular RFP also needs a price in its requested currency.

## If GAM shows only the network

A connected Google Ad Manager source should expose the selector types and
inventory rows that its sync can read, such as ad units, placements, and custom
targeting. Seeing only the GAM network, with no selectable inventory below it,
is not a completed product-setup state. It does not mean you must first invent
title or geography keys.

1. Confirm the source sync has completed and open its Health or diagnostics
   view.
2. Check that Apostra service account still has GAM inventory read access.
3. Inspect the source's advertised selector capabilities. A selector type can
   be absent because GAM does not expose it for that network or because the
   integration does not support it; an advertised type with no rows is a sync
   or product defect.
4. If the source is healthy but still exposes no inventory rows, contact
   Apostra with the source ID, last sync time, missing selector type, and a
   screenshot. Do not work around it by creating unsupported targeting keys.

Titles, sections, geography, and similar commercial groupings are not all
native GAM inventory levels. Once inventory is visible, package native
selectors directly and use existing GAM custom targeting or product metadata
for the additional dimensions your network actually maintains.

### What validation surfaces

Validation (and preview) returns two kinds of findings:

* **Blocking problems** that stop the product from being valid — for example a creative format your ad server doesn't recognize. Fix these before creating.
* **Advisory warnings** that never block creating the product, but flag a gap worth closing:
  * **A declared property wasn't found.** You named a specific property (by id or tag) that isn't in the registry or on the publisher's [`adagents.json`](/v2/concepts/identity-documents) — usually a typo. The check skips a publisher that exposes no property list yet (not-yet-crawled), so valid-but-unindexed inventory isn't flagged.
  * **Publisher hasn't authorized your agent.** A declared publisher's [`adagents.json`](/v2/concepts/identity-documents) doesn't list your storefront's sales agent. The product still authors fine; treat the warning as a publisher-owned authorization gap to fix before depending on that inventory. The check reads the publisher's live `adagents.json`, so a publisher that simply hasn't been crawled yet is not flagged.
  * **Publisher format needs attention.** The selected format may be missing or changed in the latest catalog, the catalog may be unavailable or stale, or its property scope may not cover the selected publisher properties. The product task adds the selected publisher format and property scope automatically so validation can flag these gaps.

Advisory warnings are informational and help you catch gaps early. A publisher does not have to have authorized you for a product to author, and the storefront's own coverage check never blocks you.

Declaring coverage is required for an ad-server-backed source: it rejects a product that names no publisher property. The product task asks you to pick from the coverage options listed by your ad server so the draft carries one. Authoring depends on what the option contains, not how the coverage was discovered or whether the publisher was verified. Findings are grouped by whether they stop you, so an advisory never reads as a blocker.

Every publisher listed by your ad server produces an `all` coverage option, even when no individual properties are listed yet. Specific property ids and tags appear only when your ad server supplies them. If the task offers no coverage options, the source has not supplied any publishers; refresh the source and check its publisher setup. A publisher's [`adagents.json`](/v2/concepts/identity-documents) status does not limit which listed coverage options you can use to author a product.

## Creating several products at once

When you have a set of products to add, for example a spreadsheet of ad units, you do not have to approve them one by one. The agent validates and previews each draft, then creates the whole set after **a single approval**.

* **Drop a spreadsheet into the chat.** Attach a CSV or spreadsheet of products and the agent maps the rows into drafts, validates them, and proposes the batch.
* **One approval for the batch.** You approve the full set once rather than per product.
* **It keeps going if one fails.** Bulk creation continues on error: if one product can't be created, the rest still are. At the end you get a clear per-product result showing which products were created and which failed, with the reason, so you can re-run just the ones that need attention.

You can also ask the agent to make the first pass for you. For example:

* "Set up my initial products for me."
* "Take a crack at my first cut."
* "Here is a list of sections and ad units; bulk create products from it."

The agent should inspect inventory selector capabilities, browse representative ad-server rows, map publisher/property/placement evidence into product drafts, validate the full set, and ask you to approve the batch before it creates anything.

## Updating several products at once

When you need to change a set of products, for example fixing the ones that failed during a batch create or adjusting pricing across a slate, you do not have to approve each edit one at a time. The agent applies all patches after **a single approval**.

* **Describe the changes in chat.** Tell the agent which products to update and what to change. You can paste a list or describe the edits; the agent maps them to the matching products and shows you what will change before asking for approval.
* **One approval for the batch.** You approve the full set of updates once rather than per product.
* **It keeps going if one fails.** Bulk updates continue on error: if one product can't be updated, the rest still are. At the end you get a clear per-product result showing which products were updated and which failed, with the reason, so you can re-run just the ones that need attention.

## Product status

Every product has a status:

| Status     | Meaning                                                                                               |
| ---------- | ----------------------------------------------------------------------------------------------------- |
| `draft`    | Not yet live, not visible to buyers.                                                                  |
| `active`   | Live and discoverable by buyers.                                                                      |
| `archived` | Taken off the market. Archive a product to stop offering it; make it `active` again to bring it back. |

Inventory Components and Inventory Selector create new products as `draft` so you can review them before activation. In chat, state whether you want a draft or an active product; the confirmation shows the exact status before the write.

## Retiring a product

Two endings, and only one of them can be walked back:

|             | What happens                                                                                                                          | Can you undo it?                                                    |
| ----------- | ------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------- |
| **Archive** | The product comes off the market. Buyers stop seeing it, and its name, inventory selection, and prices stay exactly as you left them. | Yes — make it `active` again and it is back, same product, same id. |
| **Delete**  | The product is removed from the source entirely.                                                                                      | No.                                                                 |

**Archive first.** Archiving is the normal way to stop offering something and is
enough for almost every case: a seasonal package, a product you are reworking,
inventory you are not selling this quarter. Delete only when you want the
product gone for good, and archive it first — deleting an `active` product takes
it out from under buyers who can discover and buy it right now, and there is no
undo. A `draft` was never offered to anyone, so it can go directly.

Because the step cannot be reversed, confirm the exact product before you ask
for it: name, not just id. Deleting the wrong product is not something a retry
fixes.

**Deleting a product does not touch your ad-server inventory.** The ad units,
placements, and targeting you packaged stay in your ad server exactly as they
were: you are removing the product you authored, not the material it was built
from. To sell that inventory again, author a new product from the same
components — it comes back with a new id, not the one you deleted.

## GAM key-value signal targeting

GAM key-value targeting is supported through signals, not as raw
product selector fields. For simple one-key mappings, browse the
`custom_targeting_key` and `custom_targeting_value` ad-server targeting types
and create a `custom_key_value` signal. For composite logic, create a
`gam_targeting_groups` signal: groups are OR'd
together, criteria inside a group are AND'd together, and multiple values in one
criterion are OR'd by GAM for that key.

Before answering whether a source supports key-value targeting, read the
source's signal capabilities. A GAM-backed ad server source can advertise
`mappingKinds[].mappingKind: "gam_targeting_groups"` and API targeting types such
as `custom_targeting_key` and `custom_targeting_value`. If those capabilities
are present, tell the operator that key-value targeting is supported through
signals, then validate and create the signal.

### Property and tag mappings

Some large networks map each publisher property or site in GAM with key-values
instead of breaking out placements or ad units per property. Sellers can now
author and preview those source-scoped mappings, including tag-based mappings,
through the [property and tag mapping task](/v2/storefront/inventory-sources/tasks/import-mapping).

This authoring slice records the seller's execution address. It does not replace
`publisher_properties`, grant publisher authorization, or claim that downstream
media-buy execution consumes the mapping yet.

Do not use GAM key-values as a substitute for `publisher_properties`, and do
not describe a mapping as proof of which properties a product sells. Use
key-values for source targeting where the source capabilities support it; use
ad units, placements, or declared publisher properties for the product's
inventory and property definition.

See [Ad-server signals](/v2/storefront/esa/signals) for the
`gam_targeting_groups` request shape and validation flow.

## Related

<CardGroup cols={2}>
  <Card title="Inventory sources overview" href="/v2/storefront/inventory-sources/overview" icon="plug">
    How sources sync inventory you can package
  </Card>

  <Card title="Ad-server access" href="/v2/storefront/inventory-sources/ad-server-access" icon="shield-check">
    What each ad server asks for, and why
  </Card>

  <Card title="Source diagnostics" href="/v2/storefront/inventory-sources/diagnostics" icon="stethoscope">
    Check sync health before packaging
  </Card>

  <Card title="Storefront onboarding" href="/v2/setup/storefront-onboarding" icon="store">
    End-to-end seller setup
  </Card>
</CardGroup>
