completed, or submitted for review that takes hours/days)
Request Schema: creative/sync-creatives-request.json
Response Schema: creative/sync-creatives-response.json
Quick start
Upload creative assets:creatives[].status (e.g., pending_review) on the synchronous success response. When the whole operation is queued (batch ingestion, governance review gating the sync), the response is a submitted envelope with top-level status: "submitted" and a task_id. See Async approval workflow.
Read-after-write visibility
Creatives accepted via a synchronoussync_creatives success response MUST be committed to the creative library before the response is returned. They MUST be immediately visible to subsequent list_creatives calls from the same account and authorized caller, including creatives whose review lifecycle status is processing or pending_review.
Implementations that acknowledge a creative on the synchronous success branch but buffer the library write until a later background commit are not conformant. If the whole sync operation cannot commit before returning, use the submitted task envelope instead; the visibility requirement then applies when the task completes with accepted creatives.
Request parameters
Every
creatives[] item in one request MUST have a unique creative_id.
Duplicate IDs make response correlation and write ordering ambiguous, so the
seller rejects the request rather than applying last-write-wins behavior.
Creative object
New 3.2 integrations use
format_kind with format_option_ref when routing depends on a product’s declared option. A compatibility implementation may accept the legacy branch from an older peer, but never mixes both shapes.
Before uploading, buyers MUST verify each creative manifest against the target product’s canonical format_options[]. The manifest MUST include every asset slot that the selected format option declares as required, keyed by that slot’s asset_group_id.
Creative revisions
Buyers may sendrevision_id to any 3.2 peer. When the agent advertises
creative.supports_revisions: true, buyers may rely on it to correlate one
immutable input state through sync, review, readback, and delivery. Without the
capability, the receiver may ignore the field and the buyer cannot rely on
revision guarantees. A supporting seller echoes it on accepted created, updated,
and unchanged items and omits it on failed and deleted items.
The identity is (creative_id, revision_id). Reusing that pair with identical
canonical revision content is safe even under a new idempotency_key. Reusing
it with changed content fails that creative item with
CREATIVE_REVISION_CONTENT_MISMATCH and leaves its prior state unchanged; other batch items may still process. Mint a new revision_id for intentional
content changes. Metadata-only changes to name or tags, and assignment
changes, do not require a new revision. The seller checks idempotency_key
conflicts first, then revision content.
Canonical revision content is RFC 8785 JCS of the effective buyer-authored
creative state after applying existing sync mutation semantics, then removing
exactly the top-level creative_id, revision_id, name, tags,
status, weight, placement_refs, and placement_ids fields. Sellers do not
materialize defaults or normalize values before this comparison. Nested fields
with those names remain content. Duplicate JSON member names are rejected.
An allowed omitted localization preserves the prior topology before
comparison. localization: null removes localization from the effective state
before comparison, so a later allowed omission represents that same
unlocalized state. URL identity is the submitted URL string (plus
any submitted digest), so use immutable or digest-bound asset references when
byte-level identity matters.
A different revision ID with content identical to the current canonical state
is accepted as updated, becomes current, and preserves the existing review
state. A seller atomically rebinds any in-flight review to that new
identical-content ID. A previously bound historical ID must still match its
retained fingerprint and, when its content differs from current, enters review
again if accepted. A different revision with changed content enters review. Sellers retain revision
fingerprint bindings for the creative’s lifetime (and any soft-purge tombstone
window); a hard purge starts a new creative incarnation. Revision IDs are not
ordering counters—buyers serialize writes, and stale review results for older
revisions cannot change the current revision or status.
When an existing unversioned creative first adopts revision identity, identical
effective content is accepted as updated, binds the supplied ID, and preserves
review state. If content also changes, the seller binds the ID only when the
ordinary update is accepted, and changed content enters review.
An omitted revision_id preserves current revision identity only for
content-equivalent updates. If a supporting seller accepts changed content from
a legacy unversioned caller, it clears current revision identity and does not
mint one; later readback, webhooks, and delivery omit the field while historical
bindings remain retained. Prior approval does not transfer, and an accepted
content-bearing unversioned update enters the ordinary review lifecycle.
With dry_run: true, the seller evaluates existing revision conflicts and may
echo the simulated revision, but it does not reserve an ID, change bindings or
tombstones, select a current revision, or alter review state.
When an item carries representation_selection, its creative_id and
revision_id must equal the selection lineage. The seller binds revision
identity to representation_selection.revision_content_digest, which commits
to the complete CreativeRepresentationSet,
not to the selected manifest bytes alone. The actor that emitted the selection
must first verify the digest against the complete set. A downstream seller that
receives only the selected output can enforce stable digest reuse, but cannot
claim it independently inspected representations it never received.
The seller separately verifies selected_output_digest with the same manifest
projection used by build_creative: remove top-level $schema,
representation_selection, creative_id, revision_id, name, tags,
status, weight, placement_refs, placement_ids, inputs, and
then include every other field. It tracks
(selected_representation_id, selected_output_digest) as the execution review
fingerprint. A changed selection or changed derived output is an
updated creative and follows ordinary re-review even when the source-set
revision_id and digest remain unchanged. list_creatives returns the exact
current selection lineage while that execution remains current.
The seller never performs that replacement implicitly. Once accepted, the
selection is pinned even if later product or seller capabilities would choose
a different representation. Capability drift affects future resolution and
assignment checks; it does not mutate the library creative or start re-review.
The buyer must explicitly resolve again with build_creative and submit the
new selected output here. This sync response acknowledges the update and starts
ordinary re-review. If the seller can no longer serve the pinned execution, it
uses the ordinary seller/system status-change and media-buy impairment
surfaces without substituting another representation.
A sync item carrying representation_selection MUST omit localization,
including null, in this version, and the stored creative must not already
have localization that ordinary omission would preserve. Remove an existing
topology first with a separate accepted sync carrying localization: null and
no representation_selection, then submit the selected output. Localization
replaces materialized serving assets and cannot be treated as digest-neutral library metadata. A future
localized representation-set contract must define locale topology inside the
pre-binding revision and selected-output projections explicitly.
Revision support does not add staged activation or revision history. A newly
accepted content revision follows the ordinary creative update and review
lifecycle, and prior approval does not transfer to changed content. The
buyer-initiated transition is acknowledged on this response rather than a
creative.status_changed webhook; subsequent seller/system review transitions
use the ordinary webhook. The prior revision is not kept serving during review.
A revised creative under re-review is ineligible for delivery like any other
pending_review creative until it re-reaches approved. Other creatives
assigned to the same package are unaffected and continue under the seller’s
ordinary selection behavior. A package that relies only on the revised creative
therefore has a serving gap by default; buyers that need zero-gap replacement
can sync the candidate under a new creative_id and change assignments after
approval. Staged activation of a replacement under the same identity is outside
this revision contract.
Creatives produced through build_creative
become buyer-authored revision state when the buyer accepts and syncs the
returned manifest, choosing the creative_id and minting (or omitting) the
revision_id. Seller-side drafts before that sync boundary are outside AdCP’s
revision history; seller transformation and transcoding after the boundary do
not mint buyer revision IDs.
Native localization
Discover support before writing. The agent’sget_adcp_capabilities.creative.localization block advertises structural
support, RFC 4647 Lookup, and an optional target ceiling. Locale, format, and
account support is validated against each request. A seller MUST reject an
unsupported locale/format pair, duplicate target locale/ID, target locale/ID
that reuses the source value, missing materialized assets, or invalid default
reference before mutating seller systems or the creative library. JSON Schema uniqueItems
compares whole objects and is not sufficient for those property-level rules;
conformance verifiers consume the schema’s x-adcp-validation constraints.
This is the only localization mutation surface. Inline package creatives in
create_media_buy and update_media_buy reject localization; sync the
localized library creative here, then assign it by creative_id.
target_variants may be empty to declare the canonical locale of a monolingual
source-only creative, such as a single fr-CA creative for French-only Québec
inventory. Do not invent a second locale variant merely to declare source
language.
default_locale_variant_id may select source or target. This task never asks
the seller to translate: use buyer tooling, build_creative, or a separate
translation/transformation agent first, then sync the resulting assets.
At delivery, the seller applies RFC 4647 Lookup to ordered locale preferences.
Each progressively truncated requested range matches only an equal available
canonical tag; it does not prefix-match sibling regional tags.
The ordered list comes from the seller’s serving environment and is outside
this task: AdCP does not define how browser, content, geography, user, app, or
platform signals produce it or their precedence.
For each preference, a strict miss is followed by the most-specific matching
locale_fallbacks rule before the next preference is tried. The example’s es
rule lets an es-ES preference use loc_es_mx; without that rule, no regional
substitution is inferred. After every preference misses both paths, the seller
follows unmatched_locale_action: serve default_locale_variant_id or make the
creative ineligible. It never silently assumes the source is the default.
Standalone library sync has no product context and does not apply product locale
policy. When assignments[] binds a creative to a package whose effective
format option has locale_policy, the
seller uses RFC 4647 Basic Filtering to derive the eligible source/target
variant set before running the buyer algorithm above. For example, seller range
fr accepts fr-CA and fr-FR. The assignment fails with
CREATIVE_LOCALE_NOT_ACCEPTED if no materialized variant matches. If
unmatched_locale_action is serve_default, the default variant must also be
seller-eligible. Buyer fallback and default rules never override the product or
placement constraint; nonmatching variants remain stored for other products.
The seller runs this check independently for every placement where the
assignment may serve. If one placement fails, the assignment is rejected unless
the buyer narrows its placement scope to compatible placements.
Accepted localized results include localization as a complete
source-plus-target variant list. The response preserves the request’s exact
source ID/locale, target ID/locale set, fallback-rule set, default ID, and unmatched action. Each
variant returns complete resolved assets under the same buyer-assigned
locale_variant_id; no seller- or platform-assigned variant ID is required.
The enclosing creative’s single status governs the complete set. If the
seller cannot read back any one of those values exactly, the item fails rather
than silently falling back to the source language.
Every accepted localized result (created, updated, or unchanged) MUST
carry top-level aggregate status and complete localization; failed and
deleted results MUST omit localization. A later
list_creatives read preserves the exact source/target identities.
delete_missing remains creative-scoped. If it archives a creative, every
locale variant follows the whole creative lifecycle, and omitted target locales
are never treated as missing creatives. A non-null localization object
transactionally replaces top-level source assets and the complete locale set;
failure leaves the prior state unchanged and must not expose orphaned locale
variants.
Null removes localization. Omission preserves localization only when top-level
source assets exactly equal the prior source assets. The normal active-delivery
update protection applies to all three operations.
Promoting a build_creative variant
When a buyer keeps a produced build leaf, the canonical promotion is to use the keptbuild_variant_id as the new creative_id. The seller does not need to hold a separate lineage mapping; delivery reporting can join back to the build leaf through the normal creative_id.
test=false
get_creative_delivery uses creative_id as the join key. A workflow that mints a different library id instead of using the kept build_variant_id loses this protocol-visible join unless a future scoped lineage field is adopted.
Asset structure
Assets are keyed by role name. Each role contains the asset details:test=false
published_post and the payload contains a post URL or platform post ID instead of uploaded media bytes. Buyers can submit these assets through the canonical creative path, for example format_kind: "video_hosted" plus the product’s format_option_ref, instead of creating a platform-specific format_id. If the seller can resolve the post but lacks a required downstream platform connection, such as the publisher identity that owns the post, the correctable error is AUTHORIZATION_REQUIRED. New implementations should include error.details.missing_connections[] so the caller can send a human through the correct connections flow and retry after authorization is restored.
Assignments structure
Assignments are at the request level, mapping creative IDs to package IDs. Standalone creative agents that do not manage media buys ignore this field.test=false
@adcp/sdk server-side): the typed syncCreatives(creatives, ctx) signature does not surface assignments as a positional argument. The wire envelope lands on RequestContext.input, so handlers read ctx.input.assignments to fan out package bindings and emit creatives[i].assigned_to in the response. The same escape hatch applies to any request field the typed signature intentionally does not model. See adcp#5797 for the trace that motivated this note (SDK ≥ 11.1.0 threads params into ctx.input; earlier lines dropped the field at the projector seam).
Response
Responses use discriminated unions — a response has exactly one of three shapes, never mixed: 1. Synchronous success — per-creative results:creatives- Results for each creative processed (includes both successful and failed items)dry_run- Boolean indicating if this was a dry run (optional)
errors- Array of operation-level errors (auth failure, service unavailable)
status- Always"submitted"task_id- Handle for polling viaget_task_statuson the A2A profile (or the advertised AdCP polling task on MCP), or receiving a webhook on completionmessage- Optional human-readable explanation of the queue state
creatives array lands on the task completion artifact, not on the submitted envelope. Per-item async review (one creative in pending_review while the rest of the sync resolves synchronously) belongs on the synchronous success branch with status: "pending_review" on that item, not here.
Each creative in the success response includes:
- All request fields
platform_id- Platform’s internal ID (whenactionis notfailed)revision_id- Exact request revision on acceptedcreated,updated, orunchangeditems when supplied. Omitted onfailedanddeleted.action- Lifecycle operation performed by this sync:created,updated,unchanged,failed,deletedstatus- Advisory review-lifecycle state (CreativeStatus):processing,pending_review,approved,suspended,rejected,archived. A UI hint and polling-scheduling signal — not a spend-authorization gate. Orthogonal toaction—actiondescribes what the sync did,statusdescribes where the creative is in the review lifecycle. Values come fromCreativeStatusonly, never fromCreativeAction(never putcreated/updated/failedinstatus). Sellers with async review returnprocessingorpending_review; sellers with synchronous review MAY return a terminal value (approved/rejected) orsuspendedwhen a recoverable dependency/authorization gate prevents serving. Buyers MUST NOT gate downstream spend or package activation onstatus: approvedfrom this response — reconcile vialist_creativesor a signed review webhook before committing spend. Authoritative state is always vialist_creatives. MUST be omitted whenactionisfailedordeleted— failed items have no meaningful review state (seeerrors); deleted items are gone from the library. The schema enforces the omission rule via a conditional constraint.localization- Exact materialized source/target locale state. Required with top-levelstatuson every accepted localized item, omitted on failed/deleted/unlocalized items. The top-level status is the single creative-wide review state.errors- Array of error messages (only whenaction: "failed")warnings- Array of non-fatal warnings (optional)
Common scenarios
Bulk upload
Upload multiple creatives in one call:Generative creatives
Use the creative agent to generate creatives from brand identity data. See the Generative Creatives guide for complete workflow details.Dry run validation
Validate creative configuration without uploading:Scoped update with creative_ids filter
Update only specific creatives from a large library without affecting others:- Scoped updates: Only specified creatives modified, even with 100+ in library
- Error recovery: Retry only failed creatives after bulk sync validation failures
- Performance: Publisher can optimize processing when scope is known upfront
- Safety: Explicit targeting reduces risk of unintended changes
Async approval workflow
Two distinct async patterns — match the right one to the agent’s behavior: Per-creative async review (common): the sync operation itself resolves synchronously, but one or more creatives require downstream review (brand safety, policy compliance). Items in review come back on the synchronous success response withstatus: "pending_review" (or processing during ingestion). The buyer reconciles terminal state via list_creatives or a webhook.
Operation-level async (less common): the whole sync is queued — the seller cannot return any per-item results before responding, because ingestion is batched or governance review gates the entire sync. The response is a submitted envelope:
- Top-level
status: "submitted"withtask_id message— optional human-readable explanation- No
creativesarray on this envelope
get_task_status on the A2A profile (or the advertised AdCP polling task on MCP), or wait for the webhook. The completion artifact carries the creatives array with per-item action/status results; operation-level failures surface as status: "failed" on the task.
See: Webhooks for webhook configuration.
Sync modes
Upsert (default)
- Creates new creatives or updates existing by
creative_id assignments[]remains the deprecated additive assignment shorthandassignment_operations[]can traffic existing IDs without resending creative bodies:assignupserts weight/placement scope,unassignremoves one assignment, andreplaceatomically swaps an existing creative for a replacement- Updates provided fields, leaves others unchanged
- Use
creative_idsfilter to limit scope to specific creatives
Dry run
- Rehearses the same
sync_creativesacceptance path without committing library, assignment, review, or serving changes - Returns operation-level errors, per-creative failures, assignment errors, and warnings the seller can determine before mutation
- Does not create or update creatives, package assignments, review state, or serving state
- Use for seller trafficking acceptance checks; use
validate_inputfor manifest-only canonical/product preflight
Error handling
Sellers that declare
creative_specs.vast_validation of document or wrapper additionally validate vast assets at sync time (including dry_run) and can return VAST_PARSE_FAILED, VAST_VERSION_MISMATCH, or VAST_WRAPPER_DEPTH_EXCEEDED. See VAST Validation.
Best practices
-
Use upsert semantics - Same
creative_idupdates existing creative rather than creating duplicates. This allows iterative creative development. Note: updates are blocked for creatives in active delivery (see #6). -
Rehearse seller acceptance first - Use
dry_run: truewhen you need to catch upload, upsert, assignment, account, policy, or format errors before mutating the seller’s creative library. Usevalidate_inputearlier in the workflow only for manifest-structure preflight or multi-target product comparison. -
Batch assignment operations - Use one idempotent
assignment_operations[]call for assignment updates, removals, and replacements. This keeps creative trafficking separate from MediaBuy commercial controls and avoids races between calls. - CDN-hosted assets - Use publicly accessible CDN URLs for faster processing. Platforms can fetch assets directly without proxy delays.
- Brand identity - For generative creatives, validate brand identity schema before syncing to avoid processing failures.
-
Active delivery protection - Creatives assigned to active, non-paused packages cannot be updated or deleted via
delete_missing. Pause the package first, useassignment_operationsto unassign or replace the creative, or create a new creative with a differentcreative_id.
Related tasks
- Canonical formats - Check product and publisher format contracts before upload
list_creatives- Browse and filter creatives in a librarybuild_creative- Build manifests from library creatives or generate from scratchpreview_creative- Generate previews of creative manifests- Creative Asset Types - Technical requirements for assets