preview_creative. Supports three modes:
- Generation: Create a manifest from a brief or seed assets (
message+creative_manifest) - Transformation: Adapt an existing manifest to a different format (
creative_manifest+target_format_id) - Library retrieval: Resolve a
creative_idfrom the agent’s library into a manifest with ad-serving assets
build_creative takes a creative manifest as input and produces a creative manifest as output. For library retrieval, provide a creative_id (from list_creatives) and the agent resolves it from its library.
For information about legacy format IDs and how to reference formats, see Creative Formats - Referencing Formats. On the 3.1 canonical path, creative agents advertise buildable outputs through get_adcp_capabilities.creative.supported_formats[]; targetable entries SHOULD include a stable capability_id, and buyers pass that value as target_format_id.id (or target_format_ids[N].id) when calling build_creative.
Request parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
message | string | No | Natural language instructions for the creative agent. For generation, this provides creative direction. For transformation, this guides how to adapt the creative. For refinement, this describes the desired changes. |
creative_manifest | object | No | Creative manifest to transform or generate from (see Creative Manifest). For pure generation, this should include the target format_id and any required input assets. For transformation, this is the complete creative to adapt. When creative_id is provided, the agent resolves the creative from its library and this field is ignored. |
creative_id | string | No | Reference to a creative in the agent’s library. The creative agent resolves this to a manifest from its library. Use this instead of creative_manifest when retrieving an existing creative for tag generation or format adaptation. |
concept_id | string | No | Creative concept containing the creative. Used to disambiguate when the same creative_id exists in multiple concepts. |
media_buy_id | string | No | Buyer’s media buy reference for tag generation context. When the creative agent is also the ad server (e.g., CM360), this provides the trafficking context needed to generate placement-specific tags. Omit when the platform generates tags at the creative level (Flashtalking, Celtra). This is the buyer’s reference — the seller-assigned identifier from create_media_buy. |
package_id | string | No | Buyer’s package or line item reference within the media buy. Used with media_buy_id when the creative agent needs line-item-level context. Omit to get a tag not scoped to a specific package — the ad server may return the same tag regardless. |
target_format_id | object | Conditional | Single format ID to generate. Object with agent_url and id fields. For 3.1 canonical creative-agent routing, id is the advertised creative.supported_formats[].capability_id; legacy named-format IDs remain accepted during the migration window. Mutually exclusive with target_format_ids — provide exactly one. |
target_format_ids | array | Conditional | Array of format IDs to generate in a single call. Each element is an object with agent_url and id fields. For 3.1 canonical creative-agent routing, each id is an advertised creative.supported_formats[].capability_id; legacy named-format IDs remain accepted during the migration window. Mutually exclusive with target_format_id — provide exactly one. Returns one manifest per format. |
brand | object | No | Brand reference with domain field. Resolves brand identity via /.well-known/brand.json. Provides brand-level context (colors, logos, tone). |
quality | string | No | Quality tier: "draft" (fast, lower-fidelity for iteration) or "production" (full quality for final delivery). If omitted, the creative agent uses its own default. |
item_limit | integer | No | Maximum number of catalog items to use within one creative. Caps generation cost for catalog-driven formats (e.g. a 6-card carousel built from a 1,000-product catalog). Distinct from max_creatives, which fans out across items. |
transformer_id | string | No | Select one transformer (discovered via list_transformers) to perform the build. The requested target format(s) MUST be a subset of that transformer’s output_format_ids. The transformer’s per_unit rate is the pricing source for the build. |
config | object | No | Typed configuration bag keyed to the selected transformer’s params[].field (e.g. { "voice": "isaac", "speaking_rate": 1.1 }). The creative agent MUST reject unknown keys and out-of-range values with field-attributed errors (strict validation) — vendor-specific knobs that are not declared params go in ext. Only meaningful with transformer_id. |
max_creatives | integer | No | Catalog fan-out axis: produce up to N distinct creatives, one per catalog item (a sample — e.g. 5 of 150). Distinct from item_limit, which caps items used within a single creative. Mutually exclusive with refine_from_build_variant_id. Triggers the BuildCreativeVariantSuccess response shape. Supported only when the agent advertises creative.multiplicity.supports_catalog_fanout; values above max_creatives_limit are clamped (shortfall via items_returned < items_total), not rejected. |
signal_conditions | array | No | Signal fan-out axis: produce one distinct creative per signal condition, each kept and trafficked with its own targeting (a rain creative AND a sun creative). Each item is a SignalTargeting. Sibling to max_creatives; composes with it (catalog × conditions). Advisory at this layer (#5280) — trafficking-compatibility is enforced sales-side via SIGNAL_TARGETING_INCOMPATIBLE. Supported only when the agent advertises creative.multiplicity.supports_signal_fanout; counts above max_signal_conditions_limit are clamped. See Signal fan-out. |
selection_strategy | string | No | How the agent samples when max_creatives < eligible items: audience_relevance (user-side, ranks by the same signal_ref pointers), contextual_fit (content-side, same mechanism with a context signal), performance (historical delivery), proximity, inventory_priority (seller-side), or random (default). Ordering surfaces on rank/recommended. Supported set in creative.multiplicity.selection_strategies[]. |
max_variants | integer | No | Number of alternative renders to produce per creative (best-of-N). Default 1. You pay for every produced variant; keeping one or more is a separate trafficking step. Supported only when the agent advertises creative.multiplicity.supports_variants; values above max_variants_limit are clamped. |
variant_axis | object | No | Describes the dimension along which variants differ. Object with dimension (voice | theme | best_of_n | transformer_config | custom), optional values[] (explicit values to enumerate along the axis), optional field (the config param to sweep — required when dimension is transformer_config), and optional label. |
keep_mode | string | No | Advisory hint to the agent on how many variants you intend to keep: "keep_all", "keep_one", or "keep_some". Default "keep_all". Advisory only — you are billed for all produced variants regardless. The response echoes keep_mode_applied so you have confirmation the hint was received (audit trail for billing disputes). |
evaluator | object | No | Experimental (status; feature id creative.evaluator). Advisory evaluator (Evaluator Spec) driving a gate-then-rank pipeline over the agent’s best-of-N: one source form (exemplars / evaluator_id / agent_url), an optional hard feature_requirement[] gate (drop fails — internal pruning of recommended leaves, never a block on an already-produced billable leaf), an explicit rank_by ordering ([{feature_id, direction: maximize|minimize}]), and an allowlisted feature_agent pointer. External agents (feature_agent.agent_url / agent_url) MUST be in the seller’s creative_policy.accepted_verifiers[] — off-list → EVALUATOR_AGENT_NOT_ACCEPTED. Requires creative.supports_evaluator; otherwise ignored. Populates the per-leaf variants[].eval block. See variants[].eval. |
refine_from_build_variant_id | string | No | Refine a prior produced variant: re-build from its build_variant_id applying the NL instruction in message plus any config delta, returning new lineage-linked variants (never a mutation). transformer_id and target format(s) are inherited from the parent. Composes with max_variants/variant_axis; mutually exclusive with max_creatives. Requires creative.supports_refinement — otherwise UNSUPPORTED_FEATURE; an unknown/no-longer-retained ref is REFERENCE_NOT_FOUND (error.field = refine_from_build_variant_id). See Refinement. |
mode | string | No | "execute" (default) produces and bills. "estimate" is a dry run — produces and bills nothing, returns a BuildCreativeEstimate cost band (cost_low/cost_high) computed against this request’s inputs. Requires creative.supports_spend_controls. See Spend controls. |
max_spend | object | No | Hard per-call spend ceiling { amount, currency }. The agent produces leaves until the next would exceed amount, then stops and returns the partial result with budget_status: "capped". Requires creative.supports_spend_controls. Caps one call — bound refinement loops buyer-side. See Spend controls. |
include_preview | boolean | No | When true, requests preview renders alongside the manifest. Agents that support this return a preview object in the response. Agents that don’t simply omit it. |
preview_inputs | array | No | Input sets for preview generation when include_preview is true. Each entry has name (required), optional macros, and optional context_description. If omitted, the agent generates a single default preview. Only supported with target_format_id (single-format) — ignored for multi-format requests. |
preview_quality | string | No | Render quality for inline previews: "draft" or "production". Independent of the build quality — you can build at draft and preview at production, or vice versa. Only used when include_preview is true. |
preview_output_format | string | No | Output format for preview renders: "url" (default) or "html". Only used when include_preview is true. |
macro_values | object | No | Macro values to pre-substitute into the output manifest’s assets. Keys are universal macro names (e.g., CLICK_URL, CACHEBUSTER); values are the literal substitution strings. The creative agent translates universal macros to its platform’s native syntax. Macros not provided here remain as {MACRO} placeholders for the sales agent to resolve at serve time. |
account | AccountRef | No | Account reference for pricing and billing. When present, the creative agent applies account-specific pricing from the rate card, records the build against the account, and can enforce quotas. Required by creative agents that charge for their services. |
Pricing response fields
When the creative agent charges andaccount is provided, the response includes pricing fields:
| Field | Type | Description |
|---|---|---|
pricing_option_id | string | Which rate card pricing option was applied |
vendor_cost | number | Cost incurred for this build. May be 0 for CPM-priced creatives where cost accrues at serve time. |
currency | string | ISO 4217 currency code |
consumption | object | Structured consumption details — tokens, images_generated, renders, duration_seconds. See creative-consumption.json. Informational for cost verification; vendor_cost is the billing source of truth. |
status: "working" with context_id polling), pricing fields appear on the final completed response only.
Important: Required input assets should be included in the creative_manifest.assets object, not as separate task parameters. The format definition specifies what assets it requires. Catalog context for dynamic creatives should be provided via the creative_manifest.assets map.
Generation controls
For generative formats, two optional parameters control the generation process:-
quality: Controls generation fidelity. Use"draft"for rapid iteration (reviewing layouts, copy, composition) and"production"for final renders. Draft outputs may use lower-resolution images, simplified effects, or placeholder elements. To produce a production version of a draft you like, pass the draft’s output manifest back ascreative_manifestwithquality: "production". Note:preview_creativealso acceptsqualityto control render fidelity independently — see Previewing generative creative. -
item_limit: For catalog-driven formats, caps how many catalog items are used during generation. A catalog might contain 1,000 products but you only need 4 hero images. The creative agent selects top items based on relevance or catalog ordering. Whenitem_limitexceeds the format’smax_items(from catalog requirements), the creative agent should use the lesser of the two. If omitted, the creative agent decides based on catalog size and format requirements.
Use cases
Pure generation (creating from scratch)
For pure generation, provide a minimal source manifest with the required input assets defined by the format:Transformation (adapting existing creative)
For transformation, provide the complete source manifest:Format resizing
Transform an existing creative to a different size:Library retrieval
Retrieve a creative from the agent’s library and resolve it into a manifest with ad-serving assets. Use this when you know thecreative_id from list_creatives and want the creative agent to produce a delivery-ready manifest with tags (HTML, JavaScript, or VAST):
CLICK_URL macro was substituted with the provided value; CACHEBUSTER remains as a placeholder for the sales agent to resolve at serve time.
Cross-agent workflow: When creative generation and media buying are handled by different agents, use
build_creative on the creative agent to produce a manifest with tags, then sync_creatives on the sales agent to upload it. When the sales agent implements both protocols, this happens on a single endpoint — see Creative capabilities on sales agents.Multi-format generation
Generate creatives for multiple formats in a single call usingtarget_format_ids. The agent produces one manifest per format from the same source assets and brief:
creative_manifests (array) instead of creative_manifest (singular). Each manifest is a complete creative manifest with its own format_id, ready for sync_creatives or preview_creative:
FORMAT_NOT_SUPPORTED), the entire request fails with an error response. The response array order corresponds to the target_format_ids request order. Match manifests to requested formats by array position or by comparing the format_id on each manifest.
Multi-format workflow
After a multi-format build, preview all results usingpreview_creative batch mode. Each element of creative_manifests in the build response becomes a creative_manifest in the batch preview request:
build_creative again with target_format_id (singular) and pass back that format’s manifest. You don’t need to rebuild all formats — just iterate on the one that needs work.
Multi-format requests with
include_preview: true generate one default preview per format. Custom preview_inputs are only supported with single-format requests. For multi-format builds where you need context-specific previews (device variants, different contexts), use a separate preview_creative batch call after building.Transformers & variants
Select a transformer (discovered vialist_transformers) with transformer_id, supply a typed config keyed to its params, and ask for alternatives with max_variants. The agent returns the variant response: creatives[], each holding a variants[] array. Read recommended / rank to surface the agent’s best-of-N pick; traffic the variant(s) you want by their build_variant_id.
Resolutions and quality tiers go on target_format_ids (or quality), not on variant_axis — variants are alternatives for the same format.
per_unit × 3); keep_mode is advisory. Keeping is a separate trafficking step on the chosen build_variant_id — the kept variant then lazily earns a creative_id that flows to report_usage.
Paid build with pricing
When the creative agent charges andaccount is provided, the response includes pricing fields. The agent selects the applicable pricing option server-side based on the account’s rate card and the work performed — the buyer does not pass pricing_option_id in the request.
Per-unit pricing (transformation agent):
pricing_option_id corresponds to one of the options from list_creatives. The buyer passes it in report_usage for reconciliation.
CPM pricing (ad server) — vendor_cost is 0 at build time because cost accrues when impressions are served:
Response format
Single-format response
When the request usestarget_format_id, the response contains a single creative manifest:
Multi-format response
When the request usestarget_format_ids, the response contains an array of creative manifests:
Variant response
When the request usesmax_creatives, max_variants > 1, variant_axis, or refine_from_build_variant_id, the agent returns the BuildCreativeVariantSuccess shape — the third success shape (oneOf member 3 of 6) alongside the single- and multi-format responses, which are unchanged and still used when you build one creative with one variant.
- creatives[]: One entry per built creative group. With
max_creatives, there is one entry per sampled catalog item (catalog_item_refidentifies which item); without catalog fan-out there is a single entry. Treat this as the produced group set; choose among alternatives inside each group’svariants[]. - creatives[].build_creative_id: Identifies a built creative within this response.
- creatives[].catalog_item_ref: Present on catalog fan-out — an object identifying the source catalog item via
item_id(plus optionalcatalog_type). - creatives[].signal_condition: Present on signal fan-out — the SignalTargeting condition this creative group is FOR (e.g. weather=rain). Shares
signal_refidentity with sales-side package targeting so the sales agent can match and reject incompatible assignments. - creatives[].errors[]: Present only on a failed catalog item — catalog fan-out is non-atomic, so a failed item is returned as a
creatives[]entry carryingerrors[]and novariants[], without failing the batch. - creatives[].variants[]: The choose-among alternatives produced for this creative group. Length is at most
max_variants. Each variant carries its own completecreative_manifest. - variants[].build_variant_id: Identifies a single variant — the leaf-level lineage anchor. This is its own namespace — never reuse a
preview_id(apreview_creativerender) or a servedvariant_id(a delivery-time identifier) here. You traffic a chosen build by passing itsbuild_variant_id. - variants[].parent_build_variant_id: Present only on a refined variant (Refinement) — the
build_variant_idof the source it was refined from. Absent for first-generation builds. - variants[].variant_axis_value: The value of the
variant_axisdimension this variant represents (e.g. a voice, a theme). - variants[].recommended / variants[].rank: Best-of-N signals —
recommendedflags the agent’s top pick;rankorders the variants. These plusvariant_axisandkeep_modeare how best-of-N is expressed. - variants[].eval: Present only when the request supplied an advisory
evaluatorand the agent advertisescreative.supports_evaluator. The rank-side of theget_creative_featuresfeature oracle.eval.features[]iscreative-feature-result[]— the same shapeget_creative_features.results[]returns (e.g. acreative_quality_scorenumber, anon_briefcategorical, a calibratedpredicted_performance); the wrapper is open, each feature item is closed. The agent runs a gate-then-rank pipeline over its best-of-N: it evaluates each leaf, drops leaves failing the hardevaluator.feature_requirement[]gate from its recommended survivors, then orders survivors byevaluator.rank_by([{feature_id, direction}]) — which is whatrecommended/rankreflect. The gate is internal pruning of which leaves the agent recommends from its own exploration, not an AdCP-layer block: what is produced and billed is governed bymax_variants/max_creatives/max_spend, so this block appears only on returned (billed) leaves. The exemplars form calibrates onepredicted_performancefeature in [0,1]; a pass/warn/fail verdict is a categorical string feature value gated viafeature_requirement.allowed_values—eval.features[]is a feature measurement, never a stored verdict. When the evaluator names an external agent, it must be on the seller’screative_policy.accepted_verifiers[](off-list →EVALUATOR_AGENT_NOT_ACCEPTED);eval.calls_used/eval.seconds_usedreport external judge usage whenagent_urlwas used. - variants[] pricing receipt: Each variant carries a per-leaf receipt (
pricing_option_id,vendor_cost,currency,consumption) for the work that produced it. - items_total / items_returned: For catalog fan-out, the total eligible catalog items and how many creatives were returned (e.g. “5 of 150”).
- leaves_total / leaves_returned: Leaf-granular counts — total leaves the request would produce vs. how many were actually produced/billed. When
budget_statusiscapped,leaves_returned<leaves_totalis the shortfall (works even for variant-only fan-out with no catalog). - vendor_cost / currency: Aggregate cost across all produced variants in the response.
- keep_mode_applied: Echoes the
keep_modethe agent applied (present when the request set it).keep_modeis advisory and doesn’t change what’s produced or billed, so this is your confirmation the hint was received — the audit trail for a “I asked for keep_one but was billed for N” dispute. - selection_strategy_applied: Echoes the
selection_strategythe agent applied (whenmax_creativessampling occurred). The ranking itself shows inrank/recommendedon the leaves. - budget_status:
complete(default; absent == complete) orcapped— amax_spendceiling stopped production early (a successful partial build, not a failure). See Spend controls. - errors[]: Advisory (non-terminal) entries on an otherwise-successful build — e.g. a
BUDGET_CAP_REACHEDnotice whenbudget_statusiscapped.
Atomicity differs by axis. Variant production per format is atomic — if one variant for a format fails, that format’s build fails. Catalog fan-out (
max_creatives, per item) is non-atomic: individual creatives[] entries may succeed while others fail. A failed item is returned as a creatives[] entry carrying errors[] (and no variants[]); the batch still succeeds.Build-time variants are not delivery variants. The build_variant_id here is a pre-delivery handle for an alternative you produced. It is a different namespace from the served variant_id in get_creative_delivery, which identifies a creative execution that was delivered. A build-time variant becomes a delivery variant only once you keep and traffic it.Resolutions and quality tiers are not variants. Multiple sizes or quality levels belong on the format axis — pass them as target_format_ids (or quality), not as variant_axis values. Variants are alternatives for the same format (different voice, theme, or best-of-N take).Refinement
Conversational refinement re-builds a prior variant with free-form direction — “make it warmer”, “tighten the CTA”. The typedconfig surface is closed by design, so free-form intent rides the open surface that already exists: the message field (whose description is already “For refinement, this describes the desired changes”). Refinement is therefore not a new task — it’s build_creative with one extra input:
- Pass
refine_from_build_variant_id(a prior leaf’sbuild_variant_id) plus your instruction inmessageand anyconfigdelta. - The agent re-builds from that leaf and returns new variants, each with
parent_build_variant_idset to the source. A refinement is never a mutation — the parent leaf is unchanged, and the new leaf earns its ownbuild_variant_id(and, on trafficking, its owncreative_id). transformer_idand the target format(s) are inherited from the parent; you don’t repeat them. Passing atransformer_idor target format that differs from the parent’s is anINVALID_REQUEST.configis applied as a delta over the parent’s config.- Composes with
max_variants/variant_axis(e.g. “three warmer takes” → three refined leaves), but not withmax_creatives/ catalog fan-out — you refine one produced creative, not a catalog. - Requires the agent to advertise
creative.supports_refinement: true(it retains produced leaves for an agent-defined window). Agents that retain nothing returnUNSUPPORTED_FEATURE; refine a buyer-held manifest instead via the transform path (creative_manifest+message). An unknown or no-longer-retained ref returnsREFERENCE_NOT_FOUNDwitherror.fieldset torefine_from_build_variant_id.
BuildCreativeSuccess carries an optional build_variant_id (present when the agent supports refinement) that you pass as refine_from_build_variant_id. Multi-format builds that need per-output refinable leaves should request the variant shape (max_variants), since the bare creative_manifests[] array carries no leaf ids.
AI-derivative attribution rides the manifest’s existing provenance; parent_build_variant_id carries only the lineage edge (refinements chain into a tree).
test=false
Spend controls
Fan-out and refinement can produce many independently-billed leaves (max_creatives × max_variants), and per_unit pricing gives a rate but not the unit count in advance (a 6-second voiceover and a 60-second one cost 10× at the same rate). Two opt-in controls, both gated by creative.supports_spend_controls:
- Estimate first (
mode: "estimate"). A dry run: the agent produces and bills nothing and returns aBuildCreativeEstimatewith acost_low/cost_highband (andbasis:fixed= exact,estimated_units= generative projection,cpm_deferred= cost accrues at serve). The band is the load-bearing piece — the seller derives it from your actual inputs, so you don’t have to guess unit counts. - Cap the call (
max_spend: { amount, currency }). A hard stop: the agent produces leaves until the next would push aggregatevendor_costoveramount, then returns the partialBuildCreativeVariantSuccesswithbudget_status: "capped"and an advisoryBUDGET_CAP_REACHEDinerrors[]— every returned leaf is real and billed, nothing produced is discarded. The leaf-granular shortfall isleaves_returned<leaves_total(notitems_returned/items_total, which count catalog items and don’t capture a variant-only or mid-item cap); theBUDGET_CAP_REACHEDadvisory is the authoritative cap signal. If even the first leaf would exceed the cap, the call fails with a terminalBUDGET_CAP_REACHED.currencymust match the rate card (no FX) or the request is rejectedINVALID_REQUEST(error.field: max_spend.currency).max_spendbounds only build-timevendor_cost— CPM-priced builds (basis: cpm_deferred) are 0 at build time and accrue at serve, so the cap never engages; bound a CPM fan-out withmax_creativesinstead.
cost_high, then execute with max_spend = cost_high × a safety margin (CPM builds excepted — their cost_high is 0 at build time). max_spend caps a single call; to bound an autonomous refinement loop, track aggregate vendor_cost across calls and stop issuing them (a buyer responsibility in this revision — a protocol-level session budget is deferred to the working group).
Estimate response
Amode: "estimate" request returns the BuildCreativeEstimate shape (oneOf member 4 of 6) — produced and billed nothing, just a projected cost band:
test=false
- estimate.leaves_total =
items_to_produce×variants_per_item— the number of billable leavesmode: "execute"would produce. - estimate.cost_low / cost_high / cost_expected: the projected aggregate cost band. The seller derives it from your actual inputs.
- estimate.basis:
fixed(per-format flat —cost_low == cost_high, exact),estimated_units(generativeper_unit; the band reflects unit-count uncertainty), orcpm_deferred(CPM — build-time cost 0, accrues at serve, so the band is 0). - estimate.per_leaf (optional): per-leaf breakdown.
- Estimates are advisory / non-binding in this revision (binding quotes are deferred to the working group).
Field descriptions
- creative_manifest: (single-format) The complete creative manifest ready for use with
sync_creativesorpreview_creative - creative_manifests: (multi-format) Array of complete creative manifests, one per requested format. Each contains its own
format_id. - format_id: The target format (matches the requested format)
- assets: Map of asset keys to asset content — includes creative content (images, text, URLs), catalogs, briefs, and anything else the format requires
- expires_at: Optional ISO 8601 timestamp when generated asset URLs in the manifest expire. Set to the earliest expiration across all generated assets. Re-build the creative after this time to get fresh URLs. Not present when the manifest contains no expiring URLs (e.g., pure text generation or assembly-only transforms).
- preview: Optional. Present when
include_previewwas true in the request and the agent supports inline preview. Contains the same content fields as apreview_creativesingle response (previews,interactive_url,expires_at) minus theresponse_typediscriminator, so clients can reuse the same preview rendering logic. For single-format responses, each entry inpreviews[]corresponds to an input set frompreview_inputs. For multi-format responses, each entry includes aformat_idand corresponds to one requested format (one default preview per format;preview_inputsis ignored). - preview_error: Optional. Standard error object (
code,message,recovery) present wheninclude_previewwas true but preview generation failed. Therecoveryfield indicates whether the failure istransient(retry later),correctable, orterminal. Distinguishes “agent doesn’t support inline preview” (field absent, no error) from “preview generation failed” (field present with structured error).
Compliance errors
If the manifest includes a brief asset withcompliance requirements that the creative agent cannot satisfy, the agent MUST return an error — not a partial success. Unsatisfied disclosures are a hard failure.
required_disclosures can be satisfied in the target format before generating the creative. If any disclosure cannot be placed as specified, the entire request fails. This ensures regulated creatives are never served without required legal text.
Response timing
How the creative agent responds depends on how long the operation will take:| Expected duration | Status | Caller experience |
|---|---|---|
| Under 30 seconds | completed | Result returned directly — synchronous |
| Over 30 seconds, server actively processing | working | Out-of-band status updates while the server continues processing. Caller holds the connection — still synchronous from their perspective |
| Blocked on external dependency (human review, approval) | submitted | Truly async — caller should configure a webhook via push_notification_config and move on |
working is a progress signal, not a polling trigger
When the server expects to take more than 30 seconds but is actively processing, it sends working as an out-of-band MCP status update. This keeps the client informed (“I’m on it”) without requiring the caller to switch to a polling or webhook pattern. The connection stays open and the result arrives when it’s ready.
When to go async
submitted means the operation is blocked on something outside the server’s control:
- Human creative review — brand guidelines require approval before returning
- External approval workflows — third-party compliance or legal review
push_notification_config to receive the result. See Async Operations and Push Notifications.
Human-in-the-loop
The agent may returnstatus: "input-required" when it needs human input — for example, when brand guidelines require creative approval or when the agent needs clarification on creative direction:
APPROVAL_REQUIRED— Creative needs human approval before finalizingCREATIVE_DIRECTION_NEEDED— Agent needs clarification on creative brief or directionASSET_SELECTION_NEEDED— Agent needs the caller to choose between asset options
Workflow integration
Typical generation workflow
- Build: Use
build_creativeto generate/transform the manifest - Preview: Use
preview_creativeto see how it renders (see preview_creative) - Sync: Use
sync_creativesto traffic the finalized creative
include_preview: true on the build request. If the agent supports it, the response includes a preview object alongside the manifest — same content fields as preview_creative, no extra round trip. If the agent doesn’t support inline preview, the field is simply absent and you fall back to a separate preview_creative call. Always check for the presence of preview rather than assuming it will be there when requested.
Use preview_quality to control render fidelity independently from build quality. For example, build at quality: "draft" (fast concept generation) but preview at preview_quality: "production" (full-fidelity render to show stakeholders the layout). If preview_quality is omitted, the agent uses its own default.
Examples
Example 1: Pure generation (generative format)
Generate a creative from scratch using a generative format:Example 2: Format transformation
Transform an existing 728x90 leaderboard to a 300x250 banner:Example 3: Transformation with specific instructions
Adapt a creative for mobile with specific design changes:Example 4: Generation with creative brief
Generate a creative using structured campaign context viabrand and a brief asset on the manifest:
Example 5: Generation with compliance requirements
Generate a financial services creative with regulatory disclosures and prohibited claims:jurisdictions) applies globally. The prohibited_claims array tells the creative agent which claims to avoid in generated copy.
Example 6: Commerce media with brief and product catalog
Generate a sponsored product carousel with campaign context, compliance disclosures, and a synced product catalog:assets map. The format declares both a brief and catalog asset type — the buying agent discovers this via list_creative_formats and syncs the required catalog before submitting.
Example 7: Build with inline preview
Build a creative and get preview renders in the same response:preview object contains the same content fields as a preview_creative single response (previews, interactive_url, expires_at). If the agent does not support inline preview, this field is absent — the buyer agent falls back to a separate preview_creative call. If preview generation fails, the response includes preview_error with a standard error object (code, message, recovery) instead.
Example 8: Draft generation with item limit
Generate a draft-quality creative from a large catalog, capping the number of items:item_limit: 4 ensures only 4 hero images are generated. quality: "draft" produces fast, lower-fidelity output for review.
Response:
expires_at field signals when the generated CDN URLs expire. Re-build after this time to get fresh URLs. Once the direction is approved, re-submit the output manifest with quality: "production" for final renders.
Key concepts
Brand vs creative brief
| Brand | Creative Brief | |
|---|---|---|
| Scope | Brand identity | Campaign context |
| Lifespan | Stable across campaigns | Specific to a campaign or flight |
| Contains | Colors, logos, fonts, tone | Audience, territory, messaging, compliance, reference assets |
| Legal | Brand-level disclaimers (always-on) | Campaign-specific regulatory disclosures (regional, product-based) |
| Source | Brand registry / /.well-known/brand.json | Agency or brand team |
| Lives on | Resolved via domain lookup | The manifest’s assets map (assets.brief) |
brand provides stable brand identity (colors, logos, tone) resolved via the domain’s /.well-known/brand.json. The brief is an asset on the manifest (assets.brief), so it travels with the creative through regeneration, resizing, and auditing. The message field provides per-request natural language instructions.
Precedence: The brand parameter is the authoritative source for creative rendering context (colors, logos, tone).
Layering: The brief asset on the manifest provides structured direction; message on the request provides per-request natural language overrides. When both provide conflicting direction, message takes precedence as the most specific instruction.
Transformation model
build_creative follows a manifest-in, manifest-out model:
- Input: Creative manifest (can be minimal or complete — everything lives in assets)
- Process: Transform/generate based on
messageand manifest content - Output: Target creative manifest ready for preview or sync (brief carries forward)
Pure generation vs transformation
- Pure Generation: Provide minimal
creative_manifestwith just the format_id, catalog assets (if the format renders catalog items), and any required seed assets. The creative agent generates output assets from scratch usingmessageas guidance. - Transformation: Provide complete
creative_manifestwith all existing assets. The creative agent adapts existing assets to the target format, optionally following guidance inmessage.
Integration with other tasks
- build_creative → Generates manifest (optionally with inline preview via
include_preview) - preview_creative → Renders the manifest separately (see preview_creative)
- sync_creatives → Traffics the finalized manifest
include_preview: true to combine build and preview into one call. If the agent doesn’t support it, the response simply omits the preview field — fall back to a separate preview_creative call. Either way, the preview content fields (previews, interactive_url, expires_at) are the same.
This separation allows you to:
- Build once, preview multiple times with different contexts
- Iterate on build without re-syncing
- Preview before committing to traffic
Iterative refinement
build_creative supports multi-turn iteration without a mode flag. The presence and combination of fields determines the operation:
- Generation:
message+ minimalcreative_manifest(empty or seed assets) +target_format_id - Transformation: full
creative_manifest+message+target_format_id - Library retrieval:
creative_id+target_format_id+ optionalmacro_values - Refinement: previous output as
creative_manifest+messagewith changes
creative_manifest back as input with a new message. Alternatively, update the brief asset (assets.brief) to change the creative direction — the brief is the buyer-owned source of truth for what the creative should be.
Error codes
| Code | Description |
|---|---|
FORMAT_NOT_SUPPORTED | The target_format_id (or target_format_ids[N] in a multi-format request) is not supported by this creative agent. For canonical creative-agent routing, retry with an advertised creative.supported_formats[].capability_id; legacy named-format IDs remain valid when the agent still advertises them. |
INVALID_MANIFEST | The creative_manifest is malformed or missing required assets for the target format |
CREATIVE_NOT_FOUND | The creative_id does not exist in the agent’s library (or in the specified concept_id) |
COMPLIANCE_UNSATISFIED | A required disclosure from the brief cannot be rendered in the target format (e.g., format does not support the required disclosure position) |