Skip to main content
Semicola is built on the Ad Context Protocol (AdCP). When this page and the AdCP spec disagree about what the protocol means, the spec wins.

Two directions

Separately, any AdCP buyer (Semicola or not) can call a storefront Semicola hosts. That’s always a single-seller conversation.

The cross-seller pattern

AdCP addresses one agent at a time. Semicola fans the same task out across your connected sellers and keeps each seller call a normal, one-to-one AdCP call. A seller never sees a multi-seller request. Each seller’s answer is validated on its own before it’s combined, and only the seller can change its pricing, allocations or terms: refining a proposal goes back to the seller that made it.

What a hosted storefront answers

Every storefront Semicola hosts is an AdCP sales agent at /seller/<storefront>/mcp. It answers get_adcp_capabilities, get_products, list_creative_formats, create_media_buy, update_media_buy, get_media_buys, get_media_buy_delivery, sync_creatives, list_creatives, provide_performance_feedback, sync_event_sources, log_event and sync_audiences. A hosted storefront declares conversion tracking and audience targeting (hashed email and phone; the audience-sync specialism), so buyers can share measurement data with it. It keeps what it receives per storefront, buyer account and brand:
  • sync_event_sources registers a buyer’s source and answers with the storefront’s own id for it (seller_id). It honors delete_missing and discovery-only calls.
  • log_event needs an event_id, a type the source accepts and a valid time (more than an hour ahead is refused). It drops a repeated event_id for the same type and source and keeps each other event’s type, time, value and currency, never user identifiers. It takes the storefront’s id for the source, or the buyer’s id when that names one source; otherwise it answers REFERENCE_NOT_FOUND.
  • sync_audiences counts members by the buyer’s external_id. Hashed identifiers are checked for shape and not kept. With no identity graph to match against, every audience stays processing and no match count is ever reported.
Sellers can’t see these events or audiences in the app yet. Callers need a credential. Semicola’s own buyer gateway calls hosted storefronts with a platform buyer credential, plus the sandbox flag for sandbox accounts; production refuses anonymous calls. New media buys go through the seller’s approval gate, sandbox or not (see Approvals & reviews).

Versions

AdCP negotiates at release precision (MAJOR.MINOR, like 3.1); patches aren’t negotiated. The rule: a seller downshifts a pin to the highest release it supports at or below the pin within the same major, and serves the request. VERSION_UNSUPPORTED is only for a different major. Semicola’s AdCP client pins 3.1 and sends adcp_major_version alongside adcp_version for older sellers. When Semicola probes a seller, it records the seller’s advertised major versions and its supported_versions. Hosted storefronts advertise supported_versions: ["3.0", "3.1"] in get_adcp_capabilities and serve a 3.0 pin by downshifting.

Request shape is checked separately

Negotiating a release and validating a request’s shape are separate. A 3.2 client can’t send the account-identity fields AdCP 3.2 introduced (operator_unit, currency, timezone, brand.countries) to a storefront that serves only 3.0 and 3.1 and expect them to be dropped: dropping them could merge two distinct advertiser accounts. So a hosted storefront refuses such a sync_accounts call with VERSION_UNSUPPORTED before writing anything. field names the first unsupported value, and details carries:
That isn’t a refusal to negotiate. Retry without the 3.2 fields, using an existing 3.0/3.1 account binding, or wait until get_adcp_capabilities advertises 3.2. If a seller returns VERSION_UNSUPPORTED for a same-major request, that’s a stale seller build; the seller has to upgrade its AdCP server.

Not available yet

  • Signals discovery across sellers (get_signals); see Signals.
  • A cross-seller get_products page with seller-qualified ids, progressive polling and screening (accept / reject / refine) for external buyers.
  • Account setup with sellers over AdCP. The buy side doesn’t call list_accounts or sync_accounts, and a hosted storefront answers them with the caller’s own account without creating or approving one.
  • Performance feedback (provide_performance_feedback) from the buy side: we don’t send it. A hosted storefront stores what buyers send (one row per idempotency_key), but nothing reads it yet.
  • Hosted storefronts answering get_signals.