Skip to main content
Connected-account campaigns are an alpha feature available only to enrolled design partners. Enrollment is one customer-facing capability; scoped internal kill switches may still protect connected-account writes and the external AdCP buyer edge independently. The alpha is API and developer-documentation only. Do not depend on change webhooks or scheduled-delivery integration yet.

Tracked and managed

Connecting a seller account puts its campaigns on the platform in one of two management states:
  • tracked — a campaign Interchange did not set up. On sync, the platform materializes a read-only projection of the seller’s own campaign and keeps it fresh: the shell is derived from the media buys underneath it and updates automatically as the seller changes things. Interchange supplies tenancy, identity, audit, governance configuration, and reporting access around it; it never acts on it.
  • managed — a campaign authored or adopted through the platform spine. For separately write-enrolled accounts, Interchange forwards an explicit media-buy create or update and then reconciles from the provider response. Campaigns authored this way — including by an external AdCP client addressing one storefront — are managed from birth.
In both states the seller’s execution system is the source of truth; the platform reflects it. Instructions flow down; truth flows up. The compatibility API value for both is mode: "directed" — a deprecated wire discriminator, not a product name, kept while the alpha cohort migrates to management. A discovery campaign that happens to finish with one seller remains an ordinary managed campaign; Interchange performed the selection. Every campaign response carries one mode and one management state: The directed invariant is one-to-one: the storefront campaign is one AdCP media buy and one Interchange campaign shell. The shell’s name, status, flight, and budget are projections of the buy, not independently editable values. The projection preserves both media-buy identifiers: Interchange’s media_buy_id and the storefront’s adcp_media_buy_id. This includes an external AdCP client calling one Interchange-hosted storefront. The storefront manages execution; Interchange records the contract, governance, reporting, and ledger envelope. The campaign still returns mode: "directed". With the buyer/storefront campaign-spine enrollment active, later update_media_buy and cancellation calls enter the same durable directed-write journal before the storefront is called. Accepted package-budget changes activate a new SCD2 version; accepted cancellation releases the governed exposure. Adding packages on this endpoint path is not yet supported. Every directed campaign also returns explicit provenance:
  • directed.provenance: "connected_account" includes connection/account ids, provider, mirror freshness, and the upstream media-buy id.
  • directed.provenance: "storefront_endpoint" includes the addressed storefront, the external buyer’s media-buy id, and Interchange’s media-buy id. It does not expose mirror state because this path is not an account mirror.
The same campaign delivery endpoint dispatches by that provenance. Connected-account campaigns read through the subscribed provider gateway; storefront-endpoint campaigns read through the addressed storefront, including direct social/ad-platform adapters.

Connect and subscribe an account

First connect the official adapter and map its discovered ad account to an advertiser. For an agent-driven setup, the complete sequence is:
  1. list_storefronts to find the official adapter, then connect_storefront to obtain the human OAuth handoff URL;
  2. list_storefront_connections and list_storefront_connection_accounts to select a buyable account returned by that connection;
  3. list_storefront_connection_account_mappings to read its mapping state, then map_storefront_connection_account_to_advertiser with the advertiser ID if the selected account is not mapped to the intended advertiser. The connection/account path identifies an official adapter; do not copy its storefront platformId into sourceId;
  4. subscribe_directed_campaigns to start its mirror.
This account-selection step applies to operator-built social adapters, which can use only an existing platform account. Agent-built storefronts may instead sync/reuse an existing account or establish a new one. Account setup does not determine campaign mode: a direct buy is directed in either case, and a new account simply has no history to backfill. Organization/manager and publisher-identity accounts cannot be subscribed. Then subscribe the mapped ad account:
For official adapters, sourceId is optional and the canonical provider is derived from the connection. External AdCP storefront sources still pass their inventory-source sourceId. Subscription immediately attempts a mirror sync. The adapter’s get_media_buys operation is called without media-buy IDs so the account can be enumerated. Active campaigns are always included; terminal history is backfilled for one year by default. Subsequent worker sweeps reconcile changes every 15 minutes by default. Broad account enumeration is not treated as proof that a previously mirrored campaign was deleted. If a known upstream ID is omitted, Interchange reads that ID through a bounded, resumable direct-read cycle before treating absence as authoritative. A returned terminal campaign remains available as a canceled or completed mirror, including its prior packages and latest revision; an empty terminal package response does not erase package history. Already-terminal local mirrors do not require repeated provider reads. If a direct response fails or omits any requested ID, the sync reports ERROR and retains the last valid mirror. The one-year boundary limits new historical campaigns; it does not suppress a later terminal transition for a campaign already mirrored. A refresh for one campaign prioritizes that campaign inside the bounded direct-read cycle, so large connected accounts do not delay its readback behind the background continuation cursor. The subscribe request returns after the initial enumeration attempt. Its response contains backfillStart, lastSyncedAt, lastSyncStatus, lastSyncError, and the mirrored/retired/skipped counts. Read the same account-level state later with GET /api/v2/buyer/storefront-connections/{connectionId}/accounts/{accountId}/directed-campaigns/subscription. Campaign lists and the campaign widget show the mode, provider, mirror state, and directed.lastSyncedAt for each mirror. Active mirrors appear in the default campaign list (the live working set); mirrored history — completed, paused, or canceled campaigns — requires an explicit status filter or status=ALL; see Relationship rollup. On a failed reconciliation, lastSyncError and the single sync.errors entry use the fixed safe summary Connected provider account could not be synchronized. Use errorCode, errorField, errorReason, and upstreamCode for any available machine-readable diagnosis. Provider messages, request IDs, account IDs, and media-buy IDs are never returned in these error fields or persisted as the subscription error. backfillStart is the fixed metadata-history boundary, not a running progress percentage or completion timestamp. Enrollment is durable even if enumeration is unsupported or temporarily unhealthy; in that case the subscription reports status ERROR, lastSyncError, and zero reconciliation counts while other supported directed operations remain available. The one-year backfill does not pre-fetch delivery reports. To stop mirroring, delete the subscription. Interchange pauses its sweep and retires the local mirror shells; it does not delete campaigns from the connected platform. Status and unsubscribe remain available if alpha exposure is removed. Governance caps are stored with the subscription for directed writes. Phase 1 read enrollment does not grant write authority. Writes require the separate directed-campaign-writes customer gate plus maxMediaBuyBudget, maxAccountBudget, and currency; missing or inconsistent governance fails before a provider call. These values are set by an Interchange operator after pilot authorization. Ordinary buyer callers cannot set or raise them by subscribing again.

Registered AdCP storefront sources

An enrolled buyer can use the same connected-account campaign surface with a registered third-party AdCP storefront source. First register source credentials, call list_available_accounts, and map the returned account to an advertiser. Then call connect_adcp_storefront to project that existing relationship into the shared connection/account plane:
The response returns connectionId and connectionAccountId; use those values with the normal subscribe, product, campaign, and delivery operations. Official adapters dispatch through their delegated adapter credential. Registered AdCP sources dispatch through the AdCP SDK and the mapped buyer account. Identity, governance, mirroring, idempotency, metering, and reconciliation are shared. Every active storefront can serve directed mode. Connection records the seller’s reported tools as readiness evidence rather than requiring a separate seller flag. Each call still fails closed if the source, pinned credential, connection account, or advertiser mapping is no longer active. An unsupported operation is reported for that operation without hiding the storefront’s other capabilities. For registered sellers, a snapshot is complete only when every requested page returns an explicit boolean pagination.has_more and every continuation cursor advances. Every media buy must include a valid ISO currency; when it echoes an account, that account_id must equal the pinned connection account. Invalid or incomplete snapshots never retire existing mirrors. Sellers that omit the optional account echo must prove account-scoped completeness before their snapshots can retire existing mirrors. Previously mirrored nonterminal IDs omitted by a broad snapshot are also read directly in bounded, lease-renewed batches. A persisted cursor resumes large accounts, and every direct batch must return the complete requested set before the sync can proceed. Budget and package updates require a provider revision observed by the latest sync; revisionless sources remain eligible only for safe operations such as pause or cancel. This alpha operation does not accept an arbitrary endpoint URL or raw secret. The seller source must already be registered on an active storefront. Endpoint ownership, seller identity, and adagents.json authorization must be established before a URL can become a transacting relationship.

Alpha operation readiness

The service uses an adapter-neutral AdCP task contract. Readiness describes which operations have passed live end-to-end verification; it is not a product allowlist.

List and inspect mirrors

Use the normal campaign surface and filter by mode:
GET /api/v2/buyer/campaigns/{campaignId} returns the same campaign resource as other modes, including the single mirrored media buy and its upstream packages. Discovery-only operations such as execute and product auto-selection always reject directed campaigns. In mirror-only enrollment, pause/reactivate and ordinary field updates also reject. Buyers separately enrolled in the write alpha must use the explicit mode: "directed" create or update branch described below; unsupported provider mutations continue to fail closed. To pull a fresh upstream snapshot without changing it, send { "mode": "directed", "refresh": true } to the normal campaign update endpoint. This re-enumerates the subscribed account; it does not write to the seller. A brief is never valid for mode: "directed"; it is a validation error, not an ignored field. When the buyer starts with an advertiser brief, call plan_directed_campaign before create. The preflight returns controlled provider decisions or explicit clarification requirements without changing the provider. Accept a ready proposal, then pass its exact reference on an assisted create. The subsequent create still contains only reviewed, explicit AdCP fields and never accepts a hidden brief.

Relationship rollup

Scale lives in the relationship, not the campaign list. Tracked campaigns never appear as ambient rows; the connected-account relationship carries the rollup and drill-in enumerates on demand. Each account on GET /api/v2/buyer/storefront-connections/{connectionId}/accounts returns an optional campaignRollup object: Spend is seller-reported net in the account currency: directed buys dispatch the full media budget zero-fee, so net equals the buyer’s budget. Rollups are never summed across currencies — the rollup is per account, and it is omitted when the account currency is unknown or the account has no live campaign mirrors. The connection rows on GET /api/v2/buyer/storefront-connections carry counts only: campaignsTracked and campaignsActive across the connection’s accounts. Money never rolls up to the connection level, because accounts on one connection can settle in different currencies.

Create and update through the connection

Upstream writes are a narrower alpha. FEATURE_NOT_ENABLED means the customer has mirror access but is not write-enrolled. Never bypass the campaign API by calling an adapter directly.
For an explicit buyer-authored plan, first call list_directed_campaign_products with the mapped connection/account path and advertiserId query. It reads the provider’s no-brief product catalogue and returns the exact product_id and pricing_option_id values accepted by that account. Do not use ordinary discovery output from another seller and do not invent provider IDs.
This catalog read does not create a discovery session or apply a brief. TikTok returns all six static products and skips historical scoring and recommendation ranking when called through this path. TikTok’s ordinary AdCP get_products discovery, including when Murph uses it to explore campaign options, is a separate read-only path. For a non-empty brief, it returns runnable recommendations only when the buyer affirmatively names one outcome. Otherwise Murph asks the buyer to choose reach, video views, traffic, conversions, app installs, or lead generation and returns no products or proposal. Reply with an explicit choice such as Objective: traffic and retry the Murph request. This does not enable TikTok in the named plan_directed_campaign operation, which currently supports Meta only, and it does not authorize a provider write. Create a directed campaign through the normal campaign endpoint. The request is an explicit AdCP media buy: there is no brief, discovery session, or execute step. connectionId, accountId, idempotencyKey, and currency live at the campaign-request root so account routing, replay protection, and governance cannot be overridden inside mediaBuy. Every create records decision provenance. Use decisionMode: "raw" for an explicit buyer-authored pass-through; omission remains backward-compatible and also defaults to raw. Raw writes cannot claim Scope3 brief strategy. A Meta brief-assisted create instead uses decisionMode: "assisted" and the exact accepted reference from accept_directed_campaign_plan.
The TikTok canary requires paused: true and rejects creative assignments or inline creatives server-side until the upstream object, mirror, governance, and delivery reads are verified. Use future-dated campaigns as an additional operating precaution. TikTok packages can include canonical AdCP catalogs[] entries of type offering or job; the adapter expands their items into provider-native promoted offerings. Other catalog types return CAPABILITY_NOT_SUPPORTED before the provider write begins. Every TikTok package must include a non-empty targeting_overlay.geo_countries array using a country supported by the provider catalog. Interchange converts those ISO country codes to TikTok locations and uses the explicit PLACEMENT_TIKTOK provider placement; missing geo fails before the provider write begins. Interchange disables TikTok’s automatic Search Results toggle and does not select an account-specific subplacement. Lemon8, Search Feed, Pangle, and Global App Bundle are not advertised as writable inventory. TikTok for Web, Profile Feed, and Following Feed are not separate API selections in this flow. The community catalog keeps the stable buyer-facing placement ID tiktok_for_you_feed; Interchange maps it to the provider’s PLACEMENT_TIKTOK enum internally. TikTok Reach packages also require an explicit targeting_overlay.frequency_cap. max_impressions must be from 1 through 1000, and the window.interval must be from 1 through 30 with unit: "days". Interchange validates those provider bounds before creating anything in TikTok and forwards the buyer-selected cap unchanged. currency must match both the subscription governance currency and mediaBuy.total_budget.currency. The total and package budgets must stay under the stored per-buy and authored-account caps. TikTok’s campaign minimum applies to the net media amount after fees; see Provider minimums apply after fees. Meta packages may use targeting_overlay.geo_regions with ISO 3166-2 codes such as AU-NSW. Interchange resolves each subdivision to Meta’s native region ID before creating the campaign and returns the canonical ISO code on readback. If Meta cannot resolve exactly one region in the requested country, creation stops before any provider campaign is created. When a package includes both a region and its parent country, the region is authoritative; Interchange removes that parent country from Meta targeting so delivery is not broadened nationally. For Meta, every finite-flight package is written as an authoritative lifetime_budget using the selected ad account’s ISO 4217 minor unit. A native Meta campaign that exposes only daily_budget cannot be interpreted as total exposure, so mirror and update operations fail closed until it has an authoritative lifetime budget. Values that cannot be represented exactly in the currency’s minor unit are rejected before Meta creates a campaign. A controlled Meta update may decrease each identified package budget under the latest provider-derived revision; one package cannot increase even if another package decreases by the same amount. Schedule changes, resume, and package additions remain unavailable during this canary stage. Meta packages may reference stable creative_ids that were already synced to the selected account on raw writes. Assisted decision-plan v1 rejects inline creative execution; creative attachment remains unavailable for assisted v1 until the separate sync/assignment flow lands. A sync requires the legacy Meta format_id returned by list_creative_formats. Scope3 auto-selects the only Facebook Page authorized for the selected ad account; when several are authorized, provide one of the named page_id choices returned by zero-write validation. When needed, the validation message tells you the next ext.meta_page_selection_offset to send. An explicit page_id or optional instagram_actor_id must belong to the selected account and is validated before provider writes. Single-image and video assets must be reachable at public HTTPS URLs and satisfy the declared format’s roles, file types, dimensions, aspect ratio, duration, and size constraints. Interchange validates the supplied roles and metadata before writing. Image downloads additionally pin public DNS, reject redirects, cap bytes, and verify JPEG/PNG content; Meta performs final provider-side processing. Interchange does not ingest a host-local file or upload assets from an MCP host; host the asset first. Carousel child attachments, native localization/translation, and sync-time assignment or delete mutations are not supported. Creative-bearing creates remain paused. Interchange reports success only after Meta reads the ad back from the selected account, campaign, and ad set with the requested creative and paused status. A pending review status is still not a claim that the ad is launch-ready or that no Ads Manager follow-up will be required; that claim requires affirmative provider approval for the same ad. Every Meta package must also include explicit geographic targeting. Country values are normalized as ISO 3166-1 alpha-2 codes (UK is accepted as an alias for GB); a missing country, invalid code, or postal area without its own country fails before Meta creates a campaign. Region strings, free-form interest themes, and custom-audience signals are not applied until they can be resolved and round-tripped without losing provider targeting semantics. After creating a paused ad set, Interchange reads Meta’s stored targeting back and requires exact normalized country, region, city, and postal equality before reporting success. A mismatch deletes the campaign and returns an error. Campaign package responses expose representable geography and device choices as targetingOverlay; providerTargeting carries the normalized provider country, region, city, postal, age, and gender readback. For a package created through Interchange, requestedTargeting retains the canonical request and targetingMatchesRequest reports whether the current provider-normalized value still equals it. This makes a later Ads Manager edit visible without rewriting the original request. Provider-authored campaigns created outside Interchange do not receive an invented request, so those two fields are omitted. When mirroring an existing Meta account, Interchange also checks for native targeting constraints that the directed-campaign projection cannot represent without losing meaning. A nonempty excluded geography, locale, interest, behavior, included or excluded custom audience, publisher platform, or Facebook/Instagram placement makes the account sync fail instead of returning a partial package. The previous complete mirror remains available and the subscription reports an error until every native constraint can be represented or is removed. City-radius or distance-unit proximity and unknown Meta targeting dimensions fail the same way. Meta does not offer an atomic compare-and-swap for these fields. Interchange assigns a durable monotonic revision whenever the provider campaign or ad-set state fingerprint changes, including multiple changes in the same second. The token remains an optimistic preflight: a native edit after the read and before the write can still race it. Run the no-spend canary only in its dedicated account, refresh before operator changes, and treat a revision conflict as a requirement to reread rather than retry blindly. Meta directed writes begin a new durable revision domain with this capability. Revisions are opaque: always use the value from the latest read, never compare their magnitude or reuse an experimental token observed before Meta directed writes became available. Update the same object through the normal campaign update endpoint. The URL provides both the local campaign identity and its upstream media-buy identity; do not repeat account, media_buy_id, idempotency_key, or revision inside mediaBuy.
A confirmed synchronous provider result returns the projected campaign plus a directedWrite block whose status is CONFIRMED. If the provider accepted the operation but the mirror cannot yet prove it, the endpoint returns 202 Accepted with the write result’s status AWAITING_CONFIRMATION and a possibly null campaignId; poll get_campaign or run the read-only refresh branch. Replaying the same idempotency key and payload returns the recorded result. Reusing the key for a different payload is a conflict, and an ambiguous provider outcome is never automatically dispatched a second time. Connected-account responses keep the two identifiers separate: directed.upstreamMediaBuyId is the platform’s campaign identifier and directed.mediaBuyId is Interchange’s internal media-buy identifier used by the embedded mediaBuys[] entry. The embedded media buy also returns its provider-derived revision and currently callable validActions; do not compare the internal identifier to the upstream identifier. If the seller accepts an update but Interchange cannot finish the local campaign projection, the write is recorded as ambiguous rather than left dispatching. New mutations stay blocked until that accepted result is reconciled; the seller request is not sent again automatically. Some platforms, including TikTok, omit a deleted campaign from subsequent complete account snapshots instead of returning a terminal row. When that authoritative absence follows a pending cancellation for the known mirror, Interchange confirms the operation, records the projected buy as canceled, and keeps its terminal shell readable so the response or an identical idempotent retry can report CONFIRMED. The same absence never confirms an unrelated write. After cancellation, reuse only the original idempotency key to read its result; a new mutation is rejected before the provider is called. The retained campaign shell reports status: CANCELED, as does its projected media buy. The sync sweep marks any write left dispatching for more than five minutes as ambiguous. Updates can still reconcile through their known upstream ID. For a create with no returned upstream ID, inspect the connected account before taking any further action and do not retry with a new idempotency key. Product enumeration and directed create/update usage are recorded as dark, platform-borne usage with zero billable amount during the alpha. Each provider dispatch is counted once; a later async confirmation does not add a second usage event. TikTok updates use the latest provider-derived revision to reject a stale write before changing the platform. Supported changes are campaign pause/resume, package budget, bid, end time, and media-buy cancellation. Package cancellation, new packages, start-time changes, and other package fields remain unsupported. Interchange bounds each request to 20 package mutations, pauses and verifies an enabled campaign before child writes, and reads the complete provider hierarchy back before reporting success. Reversible partial failures are restored to the pre-write provider values. If that restoration cannot be verified, Interchange makes one final verified disable attempt and reports an unrecovered partial update; the error states when provider containment itself cannot be verified and manual reconciliation is required. TikTok creation also fails closed at each provider boundary. Interchange verifies that the campaign, every ad group, and every ad belong to the selected advertiser, have the expected parent, and remain paused before activation. It activates children before the campaign, validating each response identity and enabled-state readback before progressing. If activation or later readback fails, cleanup never mutates an ownership-unconfirmed object. For an owned campaign, cleanup first disables the exact campaign and confirms its paused readback before requesting deletion. The result is reported as rolled back only after TikTok returns terminal deletion. If deletion cannot be confirmed after the pause is confirmed, the result is contained_paused and requires operator reconciliation without being marked possibly active. If the pause itself cannot be confirmed, the result remains possibly active and requires reconciliation. Offering-based TikTok packages can currently be created only while paused because the adapter cannot yet materialize offering assets as runnable ads; use creative_assignments for delivery-ready packages. For every new ad group, Interchange also reads back placement_type, placements, tiktok_subplacements, and search_result_enabled. The campaign is deleted while paused if TikTok broadens, filters, omits, or changes that placement contract. Provider-native campaigns that use automatic placement, partner inventory, allowlisted subplacements, or Search Results remain visible in account inventory but are read-only through Interchange. Cancellation is terminal only after a bounded full-hierarchy poll confirms TikTok campaign deletion. This path remains in live-canary readiness rather than Green production evidence.

Read delivery through the seller

Delivery is read through live from the connected platform’s get_media_buy_delivery operation:
When dates are omitted, startDate is bounded to the subscription’s one-year backfill window and endDate defaults to yesterday because same-day platform reporting is commonly incomplete. Every delivery request calls the connected platform. Interchange returns that response to the caller but does not persist or later serve the raw delivery payload or its time series in Phase 1. It persists only the latest aggregate media-buy and package metrics together with the exact requested windowStart/windowEnd and refresh time, so the campaign projection can label what period its snapshot represents. Subscription and the 15-minute metadata sweep do not pull delivery automatically. Provider reporting limits are handled inside the adapter. TikTok daily ranges longer than 30 days are read as consecutive windows and combined into one delivery response, so the caller can request the full one-year window. Snap delivery verifies the selected account and its ISO currency, enumerates the complete ad-squad inventory, and reconciles package metrics to the campaign report for the exact requested window. Empty packages remain visible at zero; malformed, partial, duplicate, cross-campaign, or non-reconciling evidence fails the read rather than returning a partial snapshot.

Errors and recovery

  • FEATURE_NOT_ENABLED means the customer is not enrolled in the requested read or write alpha. Mirror access does not imply write access. There is no environment-variable or direct-adapter bypass.
  • If subscribe reports that the account is not mapped, re-list the official adapter connection accounts and mappings, map the account to the intended advertiser, then retry with only IDs returned by those list operations.
  • If lastSyncStatus is ERROR, show lastSyncError and lastSyncedAt as the time of that failed attempt. A malformed or partial upstream snapshot fails closed and retains the previous mirrors. Reconnect first for authentication errors; otherwise retry a read-only refresh after the provider recovers.
  • A successful sync with mirrored: 0 is an empty eligible metadata window, not a failed reporting backfill.

Alpha boundaries

The directed-campaign alpha includes account subscription, campaign mirroring, a one-year historical window, delivery read-through, and separately enrolled create/update canaries. It does not include:
  • buyer webhooks for upstream changes;
  • including mirrors in managed scheduled-delivery exports;
  • public website positioning or general availability.
Write enrollment remains per customer and per verified provider. Citrus Ads and other modular sources remain separate from the native social-adapter canary.