Upload avails, inspect product projections, reserve capacity, prepare supported execution handoffs, and manage source-side human work
A modular inventory source is an operator-managed source composed from smaller modules: an inventory feed, an optional booking ledger, optional execution modules, and optional human work queues. The storefront still presents one buyer-facing sales-agent surface. The modules describe how that source gets inventory, prevents overbooking, books upstream supply, traffics campaigns, syncs creatives, and imports reporting.Use a modular source when inventory and execution do not come from one fully compliant upstream sales agent. For example, a publisher may send a periodic avails spreadsheet, confirm bookings manually, traffic a campaign in an addressable TV system, and upload the final delivery report after the campaign ends.
Modular source operations are storefront-operator endpoints. Buyer agents do not call them directly. Buyers still transact through the storefront’s AdCP media-buy workflow.
Modular inventory sources are currently feature flagged for pilot customers. If an operation returns FEATURE_NOT_ENABLED, ask your Scope3 contact to enable the modular-inventory-sources pilot for your storefront account.
Set up your storefront first, then decide which source type each inventory
system should become:
Source type
Use it when
External sales agent
The vendor already runs a compliant AdCP sales agent that buyers can use through your storefront.
Ad-server-backed source
Scope3 has a managed integration for your ad server, such as GAM, FreeWheel, or SpringServe.
Linked storefront
Another Interchange storefront should supply products or execution.
Modular source
Inventory, booking, creative, trafficking, and reporting live in different systems or human workflows.
A modular source is the right pilot shape when the seller can provide a feed of
wholesale inventory but cannot yet expose the whole lifecycle through one
upstream API.
Bring back final delivery after the campaign ends.
Delivery export with delivered impressions and upstream references.
The CitrusAd pilot is a standard composition, so sellers connect it as an
ad server rather than assembling modules. It uses a retailer-namespace catalog
module and a campaign-execution module behind one inventory source. The
storefront remains in CHEF routing mode; buyers see the storefront, not a
CitrusAd adapter or the private module graph. This standard ad-server flow is
available independently of the advanced modular-source pilot flag.The first recipe supports sponsored-product campaigns. Their creative is
rendered from retailer catalog data, so creative sync completes without an
asset upload. CitrusAd also offers static banners and Banner X, but those are
not exposed by this recipe until separate banner campaign and creative APIs are
implemented and verified.Connect the standard recipe through
POST /inventory-sources/ad-servers/citrusad, then save the storefront-scoped
credential through
POST /inventory-sources/{sourceId}/ad-servers/citrusad/credentials/{credentialKind}.
These ad-server endpoints do not expose the private module graph.
Credentials belong to one module instance on one storefront inventory source.
They are not process environment variables and are not shared across
storefronts. Raw auth values are written to the configured secret manager;
the API response contains status, scopes, expiry, and other non-secret metadata
only. Credential mutations require a storefront admin role or the dedicated
StorefrontCredentialsAdmin permission.Create a credential with POST, rotate it with PUT, and revoke it with
DELETE at:
Credential-shaped fields are rejected from module config and credential
metadata. Put all provider secrets under auth.Storefront-level approval policies still apply outside the modular source. For
example, advertiser approval and creative review can happen before a modular
source asks a human to map the approved creative into an upstream ad server.
Ask the seller for whatever they already have, then classify each file into one
of these setup areas:
Area
What good input looks like
Business profile
Channels, markets, verticals, brand voice, sales owners, and seller positioning.
Properties and collections
Publisher domains, apps, channels, platforms, shows, networks, or collections, plus adagents.json ownership.
Products and signals
Durable packages, targeting dimensions, audience/context signals, and creative formats.
Avails feed
Row-level availability with stable ids, dates, capacity, price, and collection mapping.
Bookings/reservations
Upstream commitments already sold outside the storefront, if the avails feed is gross capacity.
Creative workflow
Specs, restrictions, approval owner, due dates, and upstream creative id requirements.
Trafficking workflow
OMS/ad-server owner or API, required ids, and what confirms a booking.
Reporting workflow
Sample final report export and the columns needed to reconcile delivery.
Media kits, co-viewing studies, market-size notes, and screenshots are useful
context. They are not avails feeds unless they contain row-level sellable
capacity for a specific collection and time window.
The first successful upload should be boring: one row per sellable line, with
stable ids and clear capacity semantics.Required columns:
Column
Meaning
collectionId
Stable seller-side id for the container.
collectionName
Seller-facing collection name.
availId
Stable seller-side id for this availability row. If missing, Interchange can derive one, but explicit ids are better.
name
Seller-facing row name.
startTime
ISO date or date-time for the availability window start.
endTime
ISO date or date-time for the availability window end.
impressionsCapacity
Net sellable impressions available to this storefront.
Optional columns:
Column
Meaning
cpm, rateCpm, or priceCpm
CPM for this row.
currency
ISO currency code.
channel or mediaChannel
CTV, audio, OLV, display, home screen, podcast, etc.
targeting
JSON object with structured targeting facts.
sourceMetadata, source_metadata, or metadata
JSON object with source details.
Any other column
Preserved as source metadata when possible.
If the seller only has gross capacity, include one of avails, impressions,
monthlyAvails, monthlyVideoAvails, or monthlyHomeScreenAvails, plus
bookedImpressions, upstreamBookedImpressions, booked, or
reservedImpressions. Preview will calculate net capacity as:
Murph should not force a seller into a blank template. A good setup conversation
looks like this:
Ask the seller to upload what they have: deck, media kit, rate card,
publisher list, avails export, booking export, creative specs, reporting
export, or screenshots.
Classify the material. Keep market context as context; do not commit it as
avails.
Ask for missing row-level avails if the seller only supplied market scale.
Create the feed-backed modular source only after the operator confirms the
source name and lifecycle plan.
Preview the feed. Show normalized rows and whether capacity is net or
gross-minus-booked.
Commit only after explicit confirmation.
Run a small test reservation and validate the handoff requirements. Only run
finalization when the source has a real execution module or a configured demo
execution module.
Route unsupported integrations or missing systems into the normal Murph
escalation flow so the need is tracked centrally.
For example, a note that says “150 million monthly video avails and 1.5 billion
home-screen avails” is not enough to launch. Murph should ask for actual rows
with collection names, stable ids, dates, net capacity or booked counts, pricing,
and reporting/booking ownership.
The response includes lifecycleSummary, one row per stage:
Status
Meaning
UNSUPPORTED
No active module implements this stage.
MISSING_SETUP
A module supports the stage, but required module config is missing.
RUNTIME_INPUTS_REQUIRED
Setup is complete, but the stage needs runtime input such as an avails feed, creative, or report upload.
HITL_PENDING
A human work item is open for this stage.
READY
The stage has enough setup and runtime inputs for the current source state.
BLOCKED
A module has an error or source-health issue that needs operator attention.
activeAvailCount tells you whether the source currently has usable avails. openWorkItemCountsByKind tells you what human queue is blocking a module or stage, for example MAP_CREATIVE_REF or UPLOAD_FINAL_REPORT.
An inventory-feed module accepts normalized avails. The feed can come from a publisher upload, a pasted CSV/JSON payload, or a file that Murph has parsed into rows. Murph previews parsed rows first; commit the feed only after an operator confirms the normalized rows and confirms impressionsCapacity is net sellable capacity.
Each product maps back to one normalized avail. Generic feed-only sources return cadent: null. Cadent fields appear only when the source has an active Cadent execution module, so uploaded publisher avails are not implicitly treated as Cadent-backed inventory.
You can pass either productId or availId. The reservation prevents this modular source from overbooking against capacity it controls. Upstream booked supply must be removed from impressionsCapacity before commit; upstreamBookedImpressions is explanatory metadata and does not increase sellable capacity.
Execution is module-specific. In the current Cadent demo path, the handoff requires an active booking ledger and an active Cadent execution module. It keeps the reservation HELD, renders the Cadent campaign XML, and creates source-side work items for trafficking, creative mapping, and reporting. Do not treat the line as upstream-booked until the trafficking step succeeds; completing the TRAFFIC_TO_CADENT work item moves the held reservation to BOOKED.
For a source that books through a person rather than an execution API, the same lifecycle should surface a human work item instead of pretending the stage is automated.
Some stages are intentionally human-in-the-loop. Common examples:
Work item kind
When it appears
CONFIRM_AVAILS
An operator must confirm or correct incoming avails before products are shown.
MAP_CREATIVE_REF
A buyer creative needs a broadcast-system creative ID or trafficking reference.
TRAFFIC_TO_CADENT
A Cadent campaign payload is ready for a human operator to traffic; completing it books the held reservation.
UPLOAD_FINAL_REPORT
The campaign has ended and delivery reporting needs a file upload.
RESOLVE_SOURCE_HEALTH
A module is blocked or misconfigured.
These work items belong to the inventory source, not the buyer-facing storefront task. The storefront can still expose buyer task status or webhooks while source operators complete the underlying queue.
POST /inventory-sources/modular/cadent-demo creates or resets a demo-only source with static avails, a booking ledger, and Cadent execution. Use it to test the end-to-end lifecycle, not as a publisher avails ingestion path. Demo source IDs must be talpa-cadent-demo or start with demo-.