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_credentialsat synthesis and seller-evaluated issuer-boundrights_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/rankon leaves; not a gate.
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:-
Account-scoped discovery. Options are discovered, not guessed.
list_transformersis account-scoped, brief-filterable, and paginated, with anexpand_paramsmode 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. -
Per-account pricing. Capabilities carry
pricing_options(reusingvendor-pricing-option.json) resolved per account, echoed per leaf in the result, and reconciled viareport_usage. An output that matches no pricing option and has no unscoped default surfacesUNPRICEABLE_OUTPUT. -
Result envelope with a stable leaf anchor.
build_creativereturns each produced leaf with its ownbuild_variant_id— a namespace distinct from apreview_id(preview), a servedvariant_id(delivery), and the call-levelbuild_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, thatbuild_variant_idnormally becomes the durablecreative_id;get_creative_deliverythen joins outcomes back to the produced leaf throughcreative_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 thebuild_creativetask 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’svoice_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_credentialsare provider-enforced at synthesis. The rights agent coordinates with the provider to issue a scoped credential; the provider validatesrights_keyat generation time and is the gatekeeper. The credential is required on the acquired branch ofacquire_rights.rights_constraint.attestation_refs[]carries issuer-bound rights credentials through the creative lifecycle. The serving seller evaluates them under its ownadcp.attestationsallowlist, binds the exact constraint digest and rights action, and is the only party that produces a trusted evaluation. (approval_statusremains a manifest-time snapshot.)rights_constraint.verification_urlis 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-assetrights[]travels with the creative as a presentation. Missing or non-verified references remain informational and cannot authorize serving.
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, likeconfig.
- Signal-driven creative fan-out (#5240, RFC). A buyer fans out over
signal_conditions: SignalTargeting[]onbuild_creative, producing one creative group per condition, each tagged with thesignal_conditionit is FOR. Advisory at the AdCP layer; trafficking-compatibility (a sun creative MUST NOT serve into a rain-targeted package) is enforced sales-side viaSIGNAL_TARGETING_INCOMPATIBLE. #5240 reuses the existing signals-domainSignalTargeting/signal-ref.json— no new creative-contextsignal_refis minted — so the creative’s condition and the sales-side package targeting share onesignal_refidentity.
-
evaluator/evaluator_id(#5241, experimental). A creative evaluator/oracle the buyer attaches so the agent can explore and rank alternatives on thebest_of_naxis, surfacingrecommended/rankon leaves. Advisory — a preference signal, not a seller-enforced gate. Only the feature vocabulary and result envelope are discovered on-wire: evaluator feature discovery reusesget_adcp_capabilities.governance.creative_features, and evaluator results use the samecreative-feature-result[]vocabulary asget_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, andextMUST NOT contain API keys, bearer tokens, client secrets,Authorizationvalues, JWKs, JWKS documents, or JWKS URIs; credential- or trust-material payload fields should be rejected asCREDENTIAL_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_urlthat the producing agent is allowed to call, as an account-arrangedevaluator_idalias for a seller-supported evaluator agent/adapter, or as inlineexemplarsthat 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.
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.