Skip to main content
build_creative accepts inputs the buyer attaches to a build: a selected build capability, render configuration, and — over time — pointers to context the buyer wants the production to honor. This page defines the contract those inputs share so each new pointer inherits it instead of relitigating governance. The one distinction that matters is whether an input is an enforced capability input the agent validates and gates on, or an advisory context pointer that informs production but does not hard-block it at the AdCP layer. The boundary is deliberate and matches the rest of the protocol: capabilities are declared, not gated, and the default is exposure, not coercion. An input gates only when it is a typed contract the agent owns end to end — a render configuration that drives a paid render. Everything else steers.

Two classes of buyer-attached input

Enforced capability input — transformer_id + config

A transformer_id selects an account-scoped transformer (discovered via list_transformers) to perform the build. One transformer per call; target_capability_id / target_capability_ids MUST be a subset of the transformer’s output_capability_ids. Render configuration goes in config. config is a typed bag keyed by each param’s field from the transformer’s params[]. It gates, and it gates correctly: per build_creative, the creative agent MUST reject unknown keys and out-of-range values with field-attributed errors rather than silently ignoring them — config drives a paid render. Vendor-specific knobs that are not declared params go in ext, not here. The schema leaves the object open because legal keys are dynamic per transformer, so strict validation is a normative agent obligation. This is the only buyer-attached input that hard-blocks a build at the AdCP layer, and it is the right one to: config is a contract the creative agent owns, priced per account, and a mis-keyed value would charge for the wrong render. The agent declares creative.supports_transformers to expose this surface, and transformer and build_variant are registered x-entity types.

Advisory context pointers — signal_ref, evaluator, rights / provenance

Advisory pointers carry buyer context the production SHOULD honor — an audience signal, an evaluator’s preference, a rights or provenance reference. They inform or steer; they MUST NOT hard-block production at the AdCP layer. Where enforcement exists for the thing a pointer names, it lives in the layer that owns it, not in build_creative:
  • Rights / provenance — enforced by the credential layer (generation_credentials at synthesis and seller-evaluated issuer-bound rights_constraint.attestation_refs[] at serving), not by the buyer’s pointer.
  • Signals (#5240) — where enforcement exists, it lives in trafficking-compatibility checks.
  • Evaluators (#5241) — explore-and-rank guidance, surfaced as recommended / rank on leaves; not a gate.
This mirrors the register the protocol already uses for advisory state: buyers MUST NOT gate downstream spend or package activation on an advisory value, the way sync_creatives status is “a UI hint and polling-scheduling signal — not a spend-authorization gate.” keep_mode is the same shape on the request side — advisory only, it does not change what is returned or billed.

Shared shape

Every buyer-attached input — enforced or advisory — inherits the same three-part shape. This is normative for transformers today and is the pattern future pointers reuse:
  1. Account-scoped discovery. Options are discovered, not guessed. list_transformers is account-scoped, brief-filterable, and paginated, with an expand_params mode that enumerates an account’s configured option values (for example, the voices provisioned for that account). There is no separate options endpoint — enumeration is a mode of the one discovery task. A future pointer’s catalog is discovered the same way.
  2. Per-account pricing. Capabilities carry pricing_options (reusing vendor-pricing-option.json) resolved per account, echoed per leaf in the result, and reconciled via report_usage. An output that matches no pricing option and has no unscoped default surfaces UNPRICEABLE_OUTPUT.
  3. Result envelope with a stable leaf anchor. build_creative returns each produced leaf with its own build_variant_id — a namespace distinct from a preview_id (preview), a served variant_id (delivery), and the call-level build_creative_id. Lineage, refinement parentage, and the build→delivery learning join all key on this leaf id, and each leaf carries its own pricing receipt. When a kept leaf is trafficked, that build_variant_id normally becomes the durable creative_id; get_creative_delivery then joins outcomes back to the produced leaf through creative_id. This is the anchor an evaluator’s scores or a signal’s targeting attach to when those pointers land. The response-shape contract and per-leaf field mechanics live in the build_creative task reference.

Rights are advisory at the pointer; enforcement is the credential

A rights or provenance reference attached to a build is an advisory / audit pointer. It does not authorize the build at the AdCP layer, and the creative agent is not obligated to validate a rights token against it. A transformer’s voice_synthesis_ref[].rights_id says this directly:
This is provenance metadata only, not a build_creative rights token.
In AdCP 3.2, rights enforcement lives in the credential layer — not at the buyer’s pointer:
  • generation_credentials are provider-enforced at synthesis. The rights agent coordinates with the provider to issue a scoped credential; the provider validates rights_key at generation time and is the gatekeeper. The credential is required on the acquired branch of acquire_rights.
  • rights_constraint.attestation_refs[] carries issuer-bound rights credentials through the creative lifecycle. The serving seller evaluates them under its own adcp.attestations allowlist, binds the exact constraint digest and rights action, and is the only party that produces a trusted evaluation. (approval_status remains a manifest-time snapshot.)
  • rights_constraint.verification_url is deprecated, untrusted informational text. A receiver MUST NOT fetch it for rights evaluation; HTTP 200/404 has no AdCP authorization or revocation meaning and cannot be converted into a credential locator.
  • creative-manifest / creative-asset rights[] travels with the creative as a presentation. Missing or non-verified references remain informational and cannot authorize serving.
Buyer-attached provenance follows the same seller-publishes / buyer-represents / seller-confirms split — the buyer declares, the seller verifies. A buyer’s verify_agent.agent_url MUST be a canonicalized match of one of the seller’s published creative_policy.accepted_verifiers[]; off-list URLs are rejected with PROVENANCE_VERIFIER_NOT_ACCEPTED. That rejection is the seller enforcing its own allowlist before any outbound call — not the buyer’s pointer gating the build. The buyer’s attached results are supplementary; a seller that requires verification runs its own detection rather than trusting them.
Settled position vs. #5261. A buyer-attached pointer is still not a creative-agent build authorization token. generation_credentials gate synthesis, while a serving seller independently evaluates the issuer-bound rights references that travel on the creative. The pointer stays advisory at build time; enforcement belongs to the credential evaluator at the consuming boundary. The structural join is voice_synthesis.rights_offering_id: it identifies the configuration-time offering returned by get_rights, while the buyer-specific grant remains the output of acquire_rights. This improves lineage without authorizing either build or serving.

Experimental advisory pointers

The following advisory pointers belong to this contract’s second class and remain experimental while interop hardens. They inherit the shared shape above: account-scoped discovery where applicable, per-account pricing where applicable, and the same result envelope. They do not inherit the enforced class’s build-time gate — that is reserved for typed contracts the creative agent owns, like config.
  • Signal-driven creative fan-out (#5240, RFC). A buyer fans out over signal_conditions: SignalTargeting[] on build_creative, producing one creative group per condition, each tagged with the signal_condition it is FOR. Advisory at the AdCP layer; trafficking-compatibility (a sun creative MUST NOT serve into a rain-targeted package) is enforced sales-side via SIGNAL_TARGETING_INCOMPATIBLE. #5240 reuses the existing signals-domain SignalTargeting / signal-ref.json — no new creative-context signal_ref is minted — so the creative’s condition and the sales-side package targeting share one signal_ref identity.
Do not mint a SECOND x-entity: signal creative schema. #5240’s resolution is to reuse the existing signals-domain signal-ref.json (x-entity: signal, scope discriminator) and signal-targeting.json for the creative signal_condition rather than create a parallel signal vocabulary — that shared identity is what lets the sales agent match a creative’s condition against package targeting. The signal pointer stays in the advisory class (no build-time gate); enforcement lives at the trafficking boundary.
  • evaluator / evaluator_id (#5241, experimental). A creative evaluator/oracle the buyer attaches so the agent can explore and rank alternatives on the best_of_n axis, surfacing recommended / rank on leaves. Advisory — a preference signal, not a seller-enforced gate. Only the feature vocabulary and result envelope are discovered on-wire: evaluator feature discovery reuses get_adcp_capabilities.governance.creative_features, and evaluator results use the same creative-feature-result[] vocabulary as get_creative_features. evaluator_id, where used in the experimental surface, is a pre-provisioned, account-arranged house preset, not an ID from the creative-feature catalog and not a marketplace/provider identity. The trust boundary is the same as other buyer-attached pointers: the payload names or calibrates the evaluator; it does not carry evaluator credentials or caller-supplied trust material. External evaluator calls authenticate on the producing agent’s transport connection to the evaluator, using request signing/JWKS, mTLS, or a pre-provisioned static credential. evaluator, context, and ext MUST NOT contain API keys, bearer tokens, client secrets, Authorization values, JWKs, JWKS documents, or JWKS URIs; credential- or trust-material payload fields should be rejected as CREDENTIAL_IN_ARGS.

Evaluator source model

evaluator has three separable layers:
  • Intent is what the buyer wants judged. It is expressed through feature_requirement[], rank_by, and the creative-feature vocabulary; these define the gate/rank semantics, not where the evaluator came from.
  • Source is what performs the evaluation. The clean source-resolution model is an agent-shaped evaluator endpoint or adapter. In the current experimental surface, that can appear directly as a buyer-supplied agent_url that the producing agent is allowed to call, as an account-arranged evaluator_id alias for a seller-supported evaluator agent/adapter, or as inline exemplars that calibrate a predicted-performance style feature.
  • Discovery / marketplace is how a buyer finds an evaluator provider. That layer is outside AdCP core unless a seller is advertising handles or adapters it can actually resolve.
The current source forms map to different buyer paths: That split covers the current motivating cases without making discovery a marketplace: an external brand-requirements API uses the agent_url / allowlisted-verifier path, generic brand.json alignment can be represented by an allowlisted agent or seller-supported account alias, and historical performance from good / bad artifacts uses exemplars. This keeps the protocol boundary centered on agent-shaped evaluator sources rather than a parallel id catalog. A future list_evaluators is best scoped to seller-supported evaluator agents/adapters, not commercial marketplace / provider discovery. evaluator_id only needs to remain a durable primitive if a concrete interop case cannot be represented by that agent-shaped reference. A fourth source form may be needed for conversion-outcome evaluators that are trained from delivery history rather than artifact exemplars. That remains an open design question for the list_evaluators / evaluator-discovery follow-up, and this clarification does not freeze it.