Skip to main content

Migrating to creative transformers (3.1)

AdCP 3.1 introduces transformers — the creative analog of a media-buy product: an agent-offered, account-scoped, selectable unit of build capability (a voice, model, style, or director) with a typed configuration surface and per-account pricing, discovered via list_transformers and selected with transformer_id on build_creative. Because a transformer carries its own input/output formats and its own pricing, three things that 3.0 hung on the format are now redundant and are deprecated:
  • Format.input_format_ids / Format.output_format_ids
  • Format.pricing_options
  • the input_format_ids / output_format_ids discovery filters on list_creative_formats
Nothing breaks if you do nothing in 3.1. All four are deprecated: true but still validate and still function through the 3.1–3.x line. Act before 4.0. The hazards below are about silent degradation over the window, not hard breaks.

What changed

Surface3.03.1Removed
Build-capability discoveryfilter list_creative_formats on input_format_ids / output_format_ids; read Format.input_format_ids / output_format_idsdiscover via list_transformers (each transformer declares its own I/O signature)4.0
Creative/transform pricingFormat.pricing_options (per format)transformer.pricing_options (per transformer; include_pricing + account on list_transformers)4.0
list_creative_formats input_format_ids / output_format_ids filterssupporteddeprecated: true — use list_transformers filters + brief4.0

Migrate

Format I/O signature → transformer

A transformer declares the formats it accepts and produces directly, so build capability is a property of the selectable unit, not a relationship hung on a format. Before (3.0) — a transform format declares what it consumes/produces:
test=false
{
  "format_id": { "agent_url": "https://creative.example", "id": "resize_to_meta" },
  "input_format_ids":  [{ "agent_url": "https://creative.example", "id": "display_master" }],
  "output_format_ids": [{ "agent_url": "https://creative.example", "id": "meta_reels_9x16" }]
}
After (3.1) — declare a transformer (discovered via list_transformers):
test=false
{
  "transformer_id": "resize_to_meta",
  "name": "Resize to Meta Reels",
  "input_format_ids":  [{ "agent_url": "https://creative.example", "id": "display_master" }],
  "output_format_ids": [{ "agent_url": "https://creative.example", "id": "meta_reels_9x16" }],
  "params": [],
  "pricing_options": [ { "pricing_option_id": "per_format", "model": "per_unit", "unit": "format", "unit_price": 0.10, "currency": "USD" } ]
}

Format pricing → transformer pricing

Format.pricing_options moves to transformer.pricing_options (same vendor-pricing-option shape; per_unit is typical). The applied option is echoed per-leaf on the build_creative response and reconciled via report_usage, unchanged.
Per-output pricing does not survive the move unchanged. Format.pricing_options could price each output format differently; transformer.pricing_options is one rate card for the whole transformer with no edge to a specific output_format_id. A multi-publisher template that priced outputs differently must split into one transformer per price point (e.g. one transformer per publisher), not a single transformer with many outputs.

list_creative_formats discovery filters → list_transformers

Stop filtering list_creative_formats on input_format_ids / output_format_ids to find “what can build X”. Use list_transformers — filter on its input_format_ids / output_format_ids, narrow with brief, and expand account-scoped option values with expand_params.

What breaks silently if you do nothing

These do not throw — which is exactly why they are the reason this guide exists.
  1. Discovery-read degradation (buyers). If your buyer/storyboard learns build capability only by reading Format.input_format_ids / output_format_ids or by filtering list_creative_formats on them, you keep working against a 3.1 seller but see progressively emptier results as sellers stop emitting the deprecated fields and move capability onto transformers. No error — just fewer and fewer options. The field outlives its data. Move discovery to list_transformers.
  2. Per-output pricing loss (multi-publisher template sellers). See the pricing note above — a template that priced outputs differently silently mis-states pricing after a naïve Format.pricing_optionstransformer.pricing_options lift. Split into per-price-point transformers.
  3. Fan-out / best-of-N spend under-counting (billing pipelines). With max_variants / max_creatives, every produced variant is billed, but only a trafficked leaf lazily earns a creative_id. Discarded best-of-N leaves are billed via the inline per-leaf vendor_cost on the build_creative response only — they never earn a creative_id and so never appear in report_usage. A pipeline that reconciles spend solely from report_usage (the 3.0 invariant “every billed unit reconciles via creative_id”) will under-count by every discarded variant. Ingest the inline per-leaf receipts as the authoritative record for untrafficked leaves.

SDK behavior and timeline

VersionDeprecated fields
3.1deprecated: true; still emitted and honored. SDKs MUST continue to read them.
3.1–3.xHonored throughout. New code SHOULD NOT emit them.
4.0+SDKs MAY reject. Removed.

See also