You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
each account's notification_configs[] via sync_accounts
N calls to sign up, N calls to unwind a bad endpoint
Media-buy delivery reports
each buy's push_notification_config
M configs
Buyer version/capability declaration
nowhere durable
webhooks have no request context, so async payload versioning has no negotiation channel at all
Push when seller-side connection state changes (destination validating → ready, expiring share grants)
nowhere
buyers poll get_agent_configuration
Concretely: an agency principal managing 200 accounts at one seller makes 201 registration calls to "sign me up for everything," and when the endpoint is misconfigured, 200 more to pull it. A seller that wants to fire a webhook at a buyer six weeks after registration has no way to know what payload version the buyer speaks. And the moment a Delta share grant is about to expire, nobody gets told.
Proposal
Build on #6966's principal, proof, versioning, and revocation machinery. Three additions, one rule flip:
1. Connection-level webhook subscriptions
Allow caller-level subscribers (the notification_configs section) to include account-anchored event types, with authorization evaluated at fire time: each fire covers only accounts the caller is currently authorized for. Losing account authority silently stops that account's fires — the subscription is standing; the authorization is not.
This flips the current enum rule (notification-type.json today rejects caller-level entries carrying account-anchored types), which is why this RFC should land while protocol.agent_configuration is still experimental.
No wildcard. "Everything" is an enumerated event_types list plus an explicit include_future_event_types: true opt-in for callers who want new invalidation-style events to flow automatically.
Account-level and connection-level subscriptions are independent; both fire, receivers dedupe by notification_id (every account-anchored event already carries stable IDs).
Subscriber-level active: false is a one-call kill switch: all fires to that endpoint across all accounts halt within the seller's advertised interval — the webhook twin of feat(protocol): add agent configuration sync #6966's destination suspension.
Deferred: media-buy-anchored delivery reports (scheduled, final, …) keep per-buy registration; they carry per-buy cadence choices. A connection-level default with per-buy override is a later step.
2. A declarations section — the flip side of capability negotiation
A third replaceable section in sync_agent_configuration where the buyer declares consumption facts: supported AdCP versions for async payloads, webhook signing algorithms it can verify, experimental features it opts into, accepted transports. The seller returns the accepted intersection in readback state.
Solves async payload versioning: the durable declaration is the version-negotiation channel that webhook fires lack.
Discipline: bounded, enumerable declarations of fact about what the buyer can consume — not an open-ended preference language, and not a second capability document. get_adcp_capabilities stays objective seller facts; this stays caller-declared facts; the intersection is the contract.
3. A connection.changed caller-anchored event
An invalidation doorbell for seller-driven connection-state transitions: destination validating → ready, setup.expires_at approaching, proof invalidated, accepted declaration intersection changed. Payload is invalidation-only; receivers repair by reading get_agent_configuration. This closes the poll loop for destination setup and gives buyers early warning before delivery breaks, following the exact capabilities.changed pattern.
Non-goals
No role field. A campaign governance agent and a buyer agent are different transport principals with their own connections; what each may bind is an account-authorization fact, not a self-asserted body field. Same task, same schema, role-blind connection layer.
feat(protocol): add agent configuration sync #6966 — the foundation: stable principal, proof-bound destinations, optimistic concurrency, get_agent_configuration, suspension/revocation. This RFC extends its section model and flips one enum rule it currently ships.
Is the problem real for you? Especially multi-account operators: how many per-account webhook registrations do you carry today, and have you had to unwind a bad endpoint account-by-account?
Is fire-time authorization scoping the right model, or do connection-level subscriptions need explicit per-account filters in v1? (Proposal: all-authorized-accounts in v1, filters later if pulled.)
Problem
Configuration between one authenticated caller and one seller agent is scattered across three layers, and only one of them is unified:
capabilities.changed)sync_agent_configuration(#6966)creative.*,account.*,product.*,signal.*, …)notification_configs[]viasync_accountspush_notification_configvalidating→ready, expiring share grants)get_agent_configurationConcretely: an agency principal managing 200 accounts at one seller makes 201 registration calls to "sign me up for everything," and when the endpoint is misconfigured, 200 more to pull it. A seller that wants to fire a webhook at a buyer six weeks after registration has no way to know what payload version the buyer speaks. And the moment a Delta share grant is about to expire, nobody gets told.
Proposal
Build on #6966's principal, proof, versioning, and revocation machinery. Three additions, one rule flip:
1. Connection-level webhook subscriptions
Allow caller-level subscribers (the
notification_configssection) to include account-anchored event types, with authorization evaluated at fire time: each fire covers only accounts the caller is currently authorized for. Losing account authority silently stops that account's fires — the subscription is standing; the authorization is not.protocol.agent_configurationis still experimental.event_typeslist plus an explicitinclude_future_event_types: trueopt-in for callers who want new invalidation-style events to flow automatically.notification_id(every account-anchored event already carries stable IDs).active: falseis a one-call kill switch: all fires to that endpoint across all accounts halt within the seller's advertised interval — the webhook twin of feat(protocol): add agent configuration sync #6966's destination suspension.reporting.delivery_readyregisters here too, matching the connection-scoped reporting destinations it fires about.scheduled,final, …) keep per-buy registration; they carry per-buy cadence choices. A connection-level default with per-buy override is a later step.2. A
declarationssection — the flip side of capability negotiationA third replaceable section in
sync_agent_configurationwhere the buyer declares consumption facts: supported AdCP versions for async payloads, webhook signing algorithms it can verify, experimental features it opts into, accepted transports. The seller returns the accepted intersection in readback state.get_adcp_capabilitiesstays objective seller facts; this stays caller-declared facts; the intersection is the contract.3. A
connection.changedcaller-anchored eventAn invalidation doorbell for seller-driven connection-state transitions: destination
validating→ready,setup.expires_atapproaching, proof invalidated, accepted declaration intersection changed. Payload is invalidation-only; receivers repair by readingget_agent_configuration. This closes the poll loop for destination setup and gives buyers early warning before delivery breaks, following the exactcapabilities.changedpattern.Non-goals
Relationship to in-flight work
get_agent_configuration, suspension/revocation. This RFC extends its section model and flips one enum rule it currently ships.reporting.delivery_readyshould register at the connection level per this RFC; the reporting destinations it fires about already live there.Questions for the WG
An implementation PR (stacked on #6966) will follow this issue for concreteness; schemas remain subject to this discussion.
🤖 Generated with Claude Code