Skip to main content
A wholesale product is what you author from synced ad-server inventory so buyers can discover and buy it. In V3 you create and manage one with save_wholesale_product and read it with search and get. The field-level rules for prices, formats, channels and audience declarations are in Create products from ad-server inventory. This page is the V3 workflow.

Which sources hold products you can author

You author products only on a source Apostra manages for you, which means an ad-server-backed source. Pass its sourceId, as returned by search({ "kind": "inventory_source" }), on every call. A source that does not hold products you author refuses the write with refused: "not_our_system_of_record" and says why: A source whose ad server is disconnected is refused with source_disconnected. Reconnect it first. A source still being set up upstream is refused with source_not_provisioned. Read it with get and include: ["diagnostics"], then retry.

Create a product

A create has no id. It needs name, inventory and channels. When you send pricingOptions you also send deliveryType.
  • channels are AdCP media channels. The tool refuses audio and video, an empty list, and more distinct channels than a product can hold.
  • inventory is the source’s own selector shape. V3 has no tool that searches selectors. Reuse the inventory object that get returns for an existing product on the same source, or the values you already hold.
  • status is draft, active or archived. A draft is hidden from buyers. The result states the status the source gave the product. Save status: "active" when the product is ready.
  • A create is validated against the source before anything is written. A blocking finding stops the save and the result carries saved: false, refused: "validation_failed" and the findings as errors, each with a code, a message and a field when the source named one. Advisory findings do not block the save and come back as warnings.

Check a create without saving it

Add dryRun: true to a create to validate it and write nothing. A valid product returns saved: false, dryRun: true and valid: true. A change cannot be dry-run, because a change carries only the fields you named and the source validates complete products.

Change a product

Pass the product id and only the fields you want to change. Every field you omit keeps its stored value.
  • pricingOptions are replaced whole. Send every price you want to keep.
  • If you change prices without a deliveryType, the tool reads the product’s stored delivery type and uses it.
  • A change with id and no other field is refused as nothing to change.
  • A change cannot empty channels.
  • The fields includedAgeSignal and audienceEvidence follow one rule: omit to keep, a value to replace, null to clear.

Take a product off the market, or delete it

status: "archived" stops buyers from seeing a product and is reversible. Save status: "active" to bring the same product back. delete: true removes the product from the source for good. The tool enforces three conditions before it deletes:
  1. The product is draft or archived. An active product is refused with refused: "product_not_off_market" and nextAction: "archive_first".
  2. You pass confirmName, the product’s exact stored name. Read the product with get, show the operator its name, and send that name back. A wrong name is refused with name_confirmation_mismatch, and the stored name is not echoed to you.
  3. The call carries no other field. A delete cannot also edit, and it cannot be dry-run.
Deleting a product that no longer exists reports action: "unchanged" with code: "NOT_FOUND" instead of failing. Deleting does not touch the ad-server inventory the product packaged. To sell that inventory again, create a new product, which gets a new id.

Read the result

A successful save returns saved: true with these fields: A status of active means the product is eligible. It does not prove buyers can see it. Buyers read the storefront catalogue, which refreshes after the save. Check buyer visibility with get once it has.

Find and inspect products

List a source’s products with search:
filter.productStatus is draft, active or archived. Each result has an origin: ad_server for a product you author, and modular_source for one a modular source offers. Read one product with get. It needs the sourceId:
The read returns what was saved, including inventory, channels, formatOptions, pricingOptions, deliveryType and prebidIntegrationActive. It also returns:
  • buyerVisibility, which is visible, or hidden with the check that failed, such as a paused storefront, a catalogue that has not warmed, unresolved pricing, or no price in a storefront currency;
  • inferredChannels, a guess made from the formats, shown only when you have declared none. It is never stored; and
  • composerCompleteness.missing, the facts the proposal composer still needs. The composer can pitch an active product only when it has a channel, a canonical format and a priced option with a currency and delivery type.

Limits

  • The tool needs a Seller Account.
  • V3 has no tool for bulk product creation, for the wholesale avails percentile-CPM feed, or for searching ad-server selectors. Create products one at a time with save_wholesale_product.