Repository navigation
RFC: per-account execution readiness for products (required resources, candidates, and binding) #7763
Description
Working-group proposal
Let get_products tell a buyer, for each product and in the context of the buyer's account, which account resources the product needs before create_media_buy can succeed, whether the account has them, and which one to use when there are several.
This sits next to three existing pieces and is meant to compose with them, not replace them:
measurement_readinessgrades whether the buyer's event data is good enough for a product to optimise well. It does not say whether a buy can be created, and a low grade still counts as viable.downstream-connection-requirementdeclares the platform grants a product or format needs (advertiser account, publisher identity, post authorization). It covers authorization, not the other account resources a platform requires.- RFC: advertise valid optimization and bidding execution combinations #6709 (valid optimization and bidding combinations) and RFC: advertise conditional package constraints and campaign-scoped inheritance #6706 (conditional package constraints) describe which settings combine. This proposal describes which account resources must exist and be bound.
Problem
Many platform products need account resources that exist outside the media buy itself. The buy fails at creation when one is missing or ambiguous. Typical cases on social platforms:
- a conversion or website-sales product needs a pixel or dataset on the ad account;
- a lead-generation product needs a page and, depending on the destination, a lead form or a messaging destination;
- an app-promotion product needs a registered app;
- a catalogue-sales product needs a product catalogue and product set;
- a product that runs as a page or profile needs that identity to be connected.
What the platforms document:
- Meta. The ad set's
promoted_objectis "The object this ad set is promoting across all its ads. Required with certain campaign objectives." Conversions need apixel_id(withcustom_event_type), app installs needapplication_idandobject_store_url, lead generation needs thepage_id, and catalogue sales need aproduct_set_id. "If you usepage_id, the creative must promote thatpage_id." Lead ads also need a lead form created under the Page and referenced bylead_gen_form_idon the creative. (Ad Set reference, Ad Promoted Object, Create lead ads) - TikTok. "You must use a TikTok Pixel to run a conversion campaign." App campaigns depend on a TikTok App ID, which "is required to complete the process of connecting your app with a Mobile Measurement Partner (MMP)", the TikTok SDK or the Events API. Lead-generation ads attach "a new or … existing Instant Form at the Ad level". (Conversions objective, TikTok App ID, Lead generation with Instant Form)
- Snap. "The pixel_id parameter must be set in the Ad Squad creation call" to track conversions. Snap also exposes an eligibility endpoint "to find out which Optimization Goals a specific Pixel/Snap App/Ad Account is eligible to use", which is the same pre-creation check this proposal would standardise. (Snap Pixel, Ad Squads)
A buyer planning from a wholesale catalogue today cannot see any of this before create_media_buy. The answer is also rarely a yes/no. Common states are:
- ready: the account has exactly one suitable resource, or the seller has a documented default;
- setup required: the account has none, and the buyer can create one on the platform;
- selection required: the account has several, and the buyer must choose which one the buy uses;
- input required: the resource cannot be discovered from the account, and the buyer must supply it;
- unknown: the seller could not read the account's resources (permission or platform error).
Omitting products that are not ready hides products the buyer could run after one setup step, and cannot express "choose one of these three". Leaving it to vendor extensions means each buyer agent needs per-seller code.
Proposed direction
Add an optional, account-scoped readiness declaration per product. Illustrative shape:
{
"execution_readiness": {
"status": "selection_required",
"resources": [
{
"kind": "event_source",
"status": "ready",
"selected": { "resource_id": "px_123", "name": "Main site pixel", "reason": "only_candidate" }
},
{
"kind": "publisher_identity",
"status": "selection_required",
"candidates": [
{ "resource_id": "pg_1", "name": "Brand FR" },
{ "resource_id": "pg_2", "name": "Brand BE" }
],
"binding": "…where the chosen resource_id goes on create_media_buy…"
}
]
}
}This is deliberately illustrative. Open design points:
- Resource kinds. A closed, canonical set: at least
event_source,publisher_identity,catalog,app,lead_form,messaging_destination. Reuse existing AdCP concepts where they exist:event_sourceshould line up withsync_event_sourcesidentifiers,catalogwithsync_catalogs, and identity/grant cases withdownstream-connection-requirement. - Binding. How the buyer passes a chosen resource on
create_media_buy. Some kinds already have a standard place (optimization_goals[].event_source_id,packages[].catalogs). Others (page or profile identity, lead form, messaging destination, app) have none today. The working group should decide whether to add typed package fields for them or a single typedresource_bindingslist keyed by kind. - Status vocabulary. One status set for the product plus one per resource, distinguishing "the buyer can fix this" (
setup_required), "the buyer must choose" (selection_required), "the buyer must supply" (input_required), and "the seller could not check" (absent, or an explicit unknown). The last must never be read as "not runnable". - Caching. Readiness depends on the account, while the product catalogue is often the same for every account. Readiness should not force an otherwise public wholesale response into
cache_scope: "account". One option is to carry readiness in a separate response-level map keyed byproduct_id, versioned separately fromwholesale_feed_version.
Design requirements
- Account-scoped: present only when the request carries an
accountthe caller is authorized for. Candidate names and IDs are never disclosed across accounts. - Advisory: a readiness result is not a guarantee.
create_media_buystill revalidates, and its errors should name the same resource kind and status. - Annotate, never filter: sellers keep returning products that are not ready, with the reason.
- Canonical kinds and statuses, not provider field names.
- Composes with
measurement_readiness(event-data quality),downstream-connection-requirement(grants), and RFC: advertise valid optimization and bidding execution combinations #6709 / RFC: advertise conditional package constraints and campaign-scoped inheritance #6706 (setting combinations) without duplicating them.
Acceptance criteria
- A buyer can tell, before create, that a product needs a resource the account lacks, and which kind.
- A buyer can see the candidates when the account has several, and knows where to put the chosen one on
create_media_buy. - "Seller could not check" is distinguishable from "account lacks the resource".
- A public wholesale catalogue stays cacheable across accounts when readiness is added.
create_media_buyfailures for a missing or unbound resource return an actionable, field-addressable error naming the kind.- Conformance covers: ready by unique candidate, setup required, selection required with candidates, and the seller unable to read the account.
Metadata
Metadata
Assignees
Labels
Type
Projects
- StatusShow more project fieldsShipped
Activity
bokelley commentedon Sep 29, 2026
Triage
Classification: Feature request (RFC)
Bucket(s): spec / protocol
Status: ready-for-human
Milestone: Spec Backlog (#9)
What the experts said:
measurement_readinessprecedentMy take: Well-formed RFC filling a genuine buyer-agent gap. Two WG decisions must settle before schema work begins.
Decision 1 — Binding mechanism for chosen resources on
create_media_buy:event_source(optimization_goals[].event_source_id) andcatalog(packages[].catalogs) already have binding slots. The WG must decide how buyers pass the chosenresource_idfor kinds that have none today (publisher_identity,lead_form,app,messaging_destination).Option A — typed per-kind fields:
Discoverable via schema; typesafe. Requires a new field per future kind.
Option B — generic
resource_bindingslist:Accommodates future kinds without schema changes; less discoverable.
Decision 2 —
publisher_identity/ DCR authorization interaction:downstream-connection-requirementalready expresses authorization state. Mustexecution_readiness[kind=publisher_identity]withstatus: "selection_required"be gated on DCR authorization beingconnected? Showing candidates for an identity the account isn't authorized to use misleads the buyer agent.@bokelley, your call on both.
Triaged by Claude Code. Session: https://claude.ai/code/session_01LCV9s7CiqkcJbJCd4196bP
feat(schema): add experimental product execution requirements
bokelley commentedon Sep 30, 2026
Decision: split — static requirements ship in 3.2, per-account readiness moves to 3.3
Piece 1 — 3.2, experimental (
media_buy.execution_requirements): #7774A product can now say "you can buy this, but you have to give me these things." It doesn't depend on the account, so wholesale catalogues stay publicly cacheable and
cache_scopedoesn't change.Product.execution_requirements[]has three kinds, each tied to a request field that already exists:event_source(optionalevent_types) →packages[].optimization_goals[]ofkind: "event", viaevent_sources[].event_source_idcatalog(catalog_types) →packages[].catalogs[]. App promotion usescatalog_types: ["app"];app-itemalready carriesapp_id,bundle_id,apple_idandstore_url.downstream_connection→ reusesdownstream-connection-requirement(for examplepublisher_identity). It's met by completing the connection, not by a request field.event_source, it must also declareconversion_tracking. If it requires acatalog, it must declarecatalog_types.VALIDATION_ERROR, witherror.fieldat the binding anderror.detailsper the newerror-details/execution-requirement-unmet.json(reason:not_bound/not_found/ineligible, plus the product's requirement repeated back). An unmet connection keeps usingAUTHORIZATION_REQUIRED.This covers the acceptance criteria "buyer can tell, before create, that a product needs a resource, and which kind" and "
create_media_buyfailures … name the kind" for these three kinds.Piece 2 — deferred to 3.3 (this issue stays open for it)
execution_readiness:ready/setup_required/selection_required/input_required/unknown, with account-scoped candidates.product_id, versioned separately fromwholesale_feed_version, so readiness doesn't forcecache_scope: "account".lead_formandmessaging_destination. Meta and TikTok attach lead forms at the ad/creative level, so check whether they belong on the creative before adding package fields.Resolving the two triage decisions for Piece 2:
resource_bindingslist. Buyer agents build calls from the schema; a generic{kind, resource_id}list is harder to discover and validate.publisher_identitycandidates: yes, only list identities that areconnected. An unconnected identity shows assetup_requiredand links to the connection'sauthorization_url.feat(schema): add experimental product execution requirements (#7774)
bokelley commentedon Sep 30, 2026
Consolidated 3.3 scope, after #7774 merged
#7774 is merged (static
Product.execution_requirements, experimental in 3.2). This collects everything we deferred, what we learned while reviewing it, and what the Meta adapter work (AI-10516) exposed, so 3.3 design can start from one place.What 3.2 can already express natively
execution_requirements:event_source,catalog(includingapp),downstream_connectionsync_event_sourceswith noevent_sources(read-only; includes seller-managed sources with health)measurement_readinesson the product (account-scoped;insufficientwithmissing_event_typesandissues)sync_catalogs, read-only moderequired_connectionswithstatusandresource_ref.identity_id, in account-scoped responsesThe answers are spread over several places and the buyer has to assemble them. That's why Meta, TikTok and Snap each ship
ext.scope3_execution_readiness.Still open for 3.3
One readiness answer per product.
ready/setup_required/selection_required/input_required/unknown, per requirement and rolled up per product. "Seller could not check" must be distinguishable from "account lacks it".Candidates. Account-scoped, never disclosed across accounts. A Pixel or catalogue candidate's
resource_idmust be a value the buyer can put directly into the existing field: thesync_event_sourcesID (not the raw platform Pixel ID, if they differ) or a catalogue reference.Caching. Carry readiness in a response-level map keyed by
product_id, versioned separately fromwholesale_feed_version, so a public wholesale catalogue doesn't have to becomecache_scope: "account". One simpler option was considered for 3.2 and not taken: allow the map only in account-scoped responses. Decide which one 3.3 uses.Bindings for kinds with no request field:
lead_formandmessaging_destination. Meta and TikTok attach lead forms at the ad/creative level, so check whether they belong on the creative before adding package fields.The triage decision stands: typed fields, not a generic
resource_bindingslist.Proposal buys. Packages created from
create_media_buy.proposal_idcarry nooptimization_goalsorcatalogs, so feat(schema): add experimental product execution requirements #7774 left them out of the rejection rule. 3.3 needs either proposals that carry bindings, a binding step after creation (update_media_buyreplacingpackages[]), or a rule that sellers must not finalize a proposal whose requirements are unmet.Conformance. Storyboards for: ready by unique candidate, setup required, selection required with candidates, seller unable to read the account, and each
VALIDATION_ERRORreason (not_bound/not_found/ineligible).Lessons from review and the Meta adapter work
event_sourcerequirement. Declaring it pushes buyers into an event goal that changes how the platform bids. Check the adapter mapping: on Meta, instant-form leads, calls and messaging need a Page, form or destination, not a Pixel.platform_managedis true and the product requiresevent_source, the buyer needs the seller-managed source's ID fromsync_event_sources(managed_by: "seller"). Discovery could be smoother.Housekeeping
tests/mcp-schema-projection.test.cjs) is 1,265,000 bytes, with about 4.6 KB of headroom. The readiness map will go over it. Plan to raise it, or move the seeded Product incomply_test_controllerout of the parity-compiled path.execution_requirementsfrom their templates with no inventory reads. The ext readiness field should keep the shape of the planned map so moving to 3.3 is a rename.bokelley commentedon Oct 6, 2026
WG decision brief (3.3)
Problem. A buyer planning from a wholesale catalogue cannot tell, before
create_media_buy, whether its account has the pixel, catalogue, app or connected identity a product needs, or which one to use when it has several. #7774 (merged, experimental in 3.2) declares what a product needs; nothing says whether this account has it. Pulling for it: the Meta, TikTok and Snap adapters (AI-10516), which each shipext.scope3_execution_readinesstoday and would move to the standard shape as a rename; #7782 (advertiser identity) composes with it.Proposed shape. Draft PR: #7934 (experimental
media_buy.execution_readiness, additive, optional fields, changeset, 10 schema tests, conformance scenariomedia_buy_seller/execution_readiness; all local gates green, CI pending). Reviewed by the protocol and product experts; their changes are folded in.get_productsrequest: opt-ininclude_execution_readiness: trueplusaccount.execution_readinessmap keyed byproduct_id, with its ownversion. It is not part of the cache layer, socache_scopeandwholesale_feed_versionare unchanged and a public catalogue stayspublic.ready | setup_required | selection_required | input_required | unknown, per declared requirement and rolled up per product.unknown(seller could not read the account) carriesunknown_reasonand is never reported assetup_required.readydoes not waive binding: buyers still passresolved.resource_idin the existing field.Open questions for the WG
cache_scope: "account"on the whole catalogue and loses public dedupe. Cost of A: one extra version token and the rule that buyers key it by(account, version). Both experts agree.resource_idbe directly usable in the existing binding field (sync_event_sourcesID or catalogue ID, never a raw platform ID)? Recommend yes. Otherwise the buyer needs a per-seller translation step. Both experts agree; ratify unless someone objects.lead_form/messaging_destination: typed package fields now, or check creative-level placement first? Recommend creative-first, nothing in 3.3. Meta and TikTok attach lead forms at the ad level, so a package field could be the wrong home and 3.3 is additive-only. Vocabulary stays at the three kinds feat(schema): add experimental product execution requirements #7774 declares.connection_statefor the identity the seller would use. If the WG says "choice in 3.3", settle RFC: advertiser identity model (brand claims, account connections, buy binding) #7782 Q3 first.connected(maintainer call) or all with status? Recommend confirm connected-only. A candidate is something the buyer can use now; a non-connected identity shows throughconnection_statewithauthorization_url. No identity list ships in this slice, so this settles the rule for RFC: advertiser identity model (brand claims, account connections, buy binding) #7782 without blocking the PR.Out of scope (3.4 unless noted)
lead_form/messaging_destinationrequirements and bindings (Q3).proposal_idstay outside the feat(schema): add experimental product execution requirements #7774 rejection rule.unchanged: true.list_products, and settings combinations (RFC: advertise conditional package constraints and campaign-scoped inheritance #6706 / RFC: advertise valid optimization and bidding execution combinations #6709).publisher_identityrename (Rename publisher_identity to advertiser_identity (4.0; optional 3.3 alias) #7783).bokelley commentedon Oct 8, 2026
Cross-linking #8023 (audience size as a range, and audience overlap as an optional read; 3.3.0 milestone), which is written to compose with this proposal:
audienceas a resource kind. Line it up withsync_audiencesidentifiers, the wayevent_sourcelines up withsync_event_sources. Retargeting and CRM products need an audience on the account just as conversion products need a pixel.audiencecandidate here MAY carry RFC: report audience size as a range, and audience overlap as an optional read #8023'saudience_size/targetable_sizeobjects (lower_bound,upper_bound,precision,as_of). A buyer choosing between existing custom audiences can then compare them the same way it reads a synced list.setup_requiredhere andtoo_smallinsync_audiences.One piece of implementation evidence on
readymeaning "exactly one suitable resource": suitability has to include the event type, not just the resource kind. A Meta dataset receives every event type, but a LinkedIn conversion rule is one event type. An account whose only rule is "Lead" is notreadyfor a purchase-optimised product, even though it has exactly one candidate. If candidates carry theirevent_types, buyers and sellers can both apply that check.feat(schema): add experimental per-account execution readiness (#7934)
bokelley commentedon Oct 31, 2026
Shipped in 3.3 (experimental) via #7774 (static
execution_requirements, first in 3.3.0-beta.0) and #7934 (per-accountexecution_readiness, 3.3.0-beta.1). Piece 2 was moved into 3.3 here: #7763 (comment).Deferred to 3.4 and tracked in #8655:
lead_formandmessaging_destination, proposal-buy bindings, theaudienceresource kind and conditional fetch. Buyer choice among identities is #7782; thepublisher_identityrename is #7783 (4.0).bokelley commentedon Nov 2, 2026
Meta Page evidence for Q5, and an identity read for 3.4
Two proposals from building Meta Page support in our adapter. They change nothing in #7934's 3.3 slice; the first is input to Q5, the second is a 3.4 item that composes with #7782.
1. Q5: report every identity candidate with its own status, not only connected ones
The brief recommends connected-only. Meta argues for the other answer.
An ad account can see several Facebook Pages. A Page can fail for a product in two different ways, and they need different fixes:
Our own adapter filtered both cases out and returned only the winners. A buyer who expected a particular Page saw it vanish, with no way to tell which problem applied.
connection_stateplusauthorization_urlcovers the first case for one identity. It can't express the second, and it can't say which of several Pages is the problem.Proposal: where a requirement lists identity candidates, each candidate carries its own
status(same vocabulary as requirements:ready,setup_required, and so on), plus areasonwhen it isn't ready that says which cause applied:not_authorizedornot_eligible. Areadycandidate behaves exactly as in the connected-only rule. Buyers that only want usable candidates filter onstatus: "ready", so nothing is lost for them.This keeps
resource_refas it is: an opaque routing hint, not proof of authorisation. Statuses belong on candidates in the readiness response, not onDownstreamConnectionRequirement.2. 3.4: a way to list an account's identities without going through a product
Today a buyer agent can only find out which Pages an account has by asking for readiness on a specific Page-gated product. The natural question, "what identities can this account use?", has no direct answer.
Proposal:
list_accounts(or a sibling read) can optionally return identity sub-resources per account: Pages on Meta, the user identity on TikTok, the Public Profile on Snap. Each would use the same candidate shape and statuses as point 1.On type: an advertiser's own Page is
connection_type: "advertiser_account"withscope: "identity". It is notpublisher_identity, which AdCP keeps for a third party's granted identity, such as TikTok Spark authorisation (#7783).This belongs with #7782 (advertiser identity model) and its Q3 binding field. I'd rather it land as part of that than as a separate mechanism.
We'll carry both in our adapter as a named extension until AdCP has an equivalent, and drop the extension when it lands.
bokelley commentedon Nov 2, 2026
Published a concrete proposed 3.4 design under #7782 incorporating this evidence: account identity discovery without a product, per-candidate authorization/eligibility diagnostics, and typed package bindings.
It includes proposed wire shapes, rollup rules, pagination and visibility semantics, failure handling, creative validation, and acceptance cases. Discovery shape, binding placement, and connection terminology are explicit recommendations for review, not recorded decisions. The shipped 3.3 behavior stays unchanged; this is a design proposal, with implementation to follow after those choices are accepted.