Skip to main content
AdCP separates four questions that are often collapsed into one rejection code:
  1. What was observed? A creative feature such as an automatic redirect, credential-harvesting form, or excessive tracker count.
  2. Which rule did that observation violate? A versioned policy in the shared policy registry.
  3. Who detected it? The creative governance agent and methodology used for the evaluation.
  4. Where is the creative in its lifecycle? Initial review failure, later policy revocation, or content drift.
Keeping these axes separate gives buyers stable, actionable identifiers without putting every scanner signature, platform rule, or vendor outcome into a protocol enum.

The policy-backed feature convention

A policy-backed creative feature uses registry:{policy_id}. Its value is a binary compliance result:
  • true — the creative complies with the resolved policy.
  • false — the creative violates the resolved policy.
The governance agent may also return its own observation features. For example, auto_redirect: true describes the detected behavior, while registry:creative_security_auto_redirect: false describes the policy result. Buyers that only need an interoperable pass/fail decision can request the registry-backed feature. Buyers that need richer diagnostics can also request the agent-defined features or follow its detail_url.
The first identifier is stable across governance agents because it resolves through the policy registry. The second is agent-defined and may evolve with the agent’s methodology. A shared ID standardizes the question being answered; it does not force every agent to use the same scanner or prevent sellers from applying published, seller-specific limits where a policy explicitly allows them.

Responsibilities

End-to-end workflow

1. Discover seller requirements

Sellers publish policy IDs on products. Buyers that require predictable enforcement can filter during discovery:
A matching product includes the same IDs in enforced_policies.

2. Preflight the creative

The buyer calls a creative governance agent that advertises the corresponding registry-backed features:
The buyer can correct the automatic redirect before submitting the creative to the seller.

3. Attribute a seller rejection

If the seller independently detects the same violation, it uses the existing CREATIVE_REJECTED error and cites the registry policy ID:
The policy ID is the durable code; the pinned URL identifies the exact registry version used for this decision. When an error-array surface reports several failures, sellers emit one error entry per policy rather than inventing a combined code. This preserves one stable resolution and remediation path per entry.

4. Keep lifecycle reasons orthogonal

The policy ID explains which rule failed. Creative lifecycle webhooks separately explain when and why the status changed:
  • review_failure — the policy failed during initial review.
  • policy_revocation — an approved creative later failed because the seller’s policy changed or an earlier violation was discovered.
  • content_drift — the creative or destination changed after approval.
A scanner or verification company is detection provenance, not a rejection reason. The same automatic redirect must resolve to creative_security_auto_redirect regardless of which trusted governance agent detected it.

Initial registry policies

The first policy-backed creative rejection vocabulary focuses on runtime behavior rather than file-format constraints: The policies concerning risky origins, permitted UX, resource use, approved collectors, and tracker limits are intentionally parameterized by the enforcing seller. For those policies, the seller or its governance agent must publish the applied list, permission, or limit through its methodology documentation and include the observed value in the detailed report or rejection reason. The shared policy ID remains stable while the declared operating limit can differ by product. These policies deliberately do not include:
  • Advertiser, campaign, or account deny-lists. Those are seller relationship or transaction constraints, not creative observations. A destination-domain policy may still reject a creative when changing the destination is a valid remediation.
  • Verification-vendor blocks. The vendor is who detected a violation, not what the violation was.
  • Regulated-category catch-alls. Alcohol, gambling, political, pharmaceutical, weapons, and similar rules resolve through their category-specific registry policies rather than one ambiguous sensitive_category code.
  • File-format validation. Dimensions, duration, file size, codec, and other mechanically declared format constraints remain on the creative-format and validation surfaces.

Why this does not pollute the protocol

The protocol defines one reusable mechanism: open feature IDs plus a registry-reference convention. The shared registry supplies optional vocabulary as versioned data. Governance agents decide how to measure compliance, sellers decide which policies they enforce, and buyers decide which policies they require or preflight. Adding a new threat signature therefore does not require an AdCP release. A governance agent can expose it immediately as an agent-defined feature. When the ecosystem needs a stable cross-agent contract, contributors publish a reviewed policy entry and agents opt into the corresponding registry: feature. The wire format remains unchanged.

Current readback limitation

The structured policy_id bridge is available on CREATIVE_REJECTED error details. Persistent creative and package approval readbacks still carry human-readable rejection_reason strings, and lifecycle webhooks carry reason_code plus reason_detail. Until those readback surfaces gain a reusable structured policy-reference field, buyers should retain the original rejection error with the transaction context needed to correlate it to the submitted creative. This limitation is tracked in GitHub issue #6652.