These workflows require a Seller Account. In v3, “Seller Account” is the
operator workspace; a Storefront is the buyer-facing selling surface it
operates.
Begin with readiness
Callget_status before changing configuration. Its blockers explain why work
is stopped before a buyer request reaches an inventory source and provide a
typed tool or Page for the next action.
Do not infer demand from source traffic alone. A Seller Account that is not
ready may correctly have no source calls because work stops earlier.
Read and configure Seller identity
The Seller Account is a singleton, so read it without an ID:configuredCapabilities— the declaration you saved; andcapabilities— what buyers can use after source topology and approval policy are applied.
capabilitiesLocked and capabilityDerivation
explain why. Send capability patches rather than replacing the whole set:
setupIntent describes how the Seller Account is intended to connect. It does
not apply a capability preset or change the capability flags. Declare each
supported capability explicitly through capabilities; then read the Seller
again to see the effective values derived from source topology and policy.
Changing operatorDomain may invalidate profile fields curated for the old
identity. If populated fields would be cleared, the tool refuses the write and
requires confirmOperatorDomainProfileReset: true after you review the impact.
Add and diagnose inventory
Usesave_inventory_source for typed source configuration. Credentials and
OAuth grants stay in the relevant Page rather than model-visible arguments.
Read a source with connection and diagnostic evidence:
moduleRoster before the detailed
modularReadiness projection. moduleRoster.modules is the complete attached
module list and carries each module’s instance ID, kind, name, contract ID, and
status; supportedStages lists the lifecycle stages covered by the attached
modules. A null contract ID means the contract could not be resolved — it does
not mean the module is absent. The detailed readiness projection can be large,
so treat an explicit truncation notice as evidence that only a prefix of that
detail is visible.
Testing an ad-server connection
get contacts no ad server. Every connection fact it returns — the adapter
block, health, sync state — is state recorded earlier, and none of it is
evidence that the connection works right now.
For an ad-server-backed source the read makes that explicit in adServerProbe:
when the connection was last probed, what that probe recorded, and null when
nobody has ever probed it. A connection reporting connected with
adServerProbe.lastTestedAt of null has never been checked against the live
ad server.
Probing is a live call with a real cost, so it belongs to a person rather than
to an agent acting alone. Open ad_server_diagnostics and run Test
connection there:
sourceId and its
ad-server connection id (managedSa.connectionId, used as esaId on Pages).
get accepts either and tells you which it resolved from, so holding one is
never a dead end.
Common Pages include:
connect_ad_serverfor credentials and OAuth;ad_server_sourcefor connection management;ad_server_diagnosticsfor sync history, refresh, and the connection test; andsource_diagnosticsfor call-level investigation.
Manage publisher coverage
Coverage separates declarations from evidence:- declared domains and properties are operator claims;
- discovered properties remain evidence from publisher sources; and
- authorization is a verdict derived from the current roster and proof.
save_coverage to add or remove one domain or property without rebuilding
the entire roster. Domain declarations in one call are applied before property
claims beneath them, so a new domain and property may be declared together.
Removing publisher-origin evidence is refused; retract only claims you own.
Add and inspect seller material
Sellers can select Add material at the top of the Library page to upload a supported file directly. The Library uses thesave_material upload lifecycle
below and then reads the finished Material back to show its units, pricing
marks, and reusable toggles. The other paths remain available: drop material
into Murph chat, or upload it while closing a specific Library request.
Use save_material to register teaching material without requiring a first-party
Page. Supported source kinds are url, site, upload, crawl_manifest,
inline, and history. For an upload, provide sha256 with the declared byte
count and media type. The first save returns an authorized, expiring PUT URL
and an immutable assetRef. Upload the exact bytes with the returned headers,
then call replace_source with that assetRef; it cannot be attached to a
different Material or a later refresh. Each refresh creates a new source
revision and retains the prior original and renditions.
The processing result has two complementary forms. Rendition blocks and visual
assets preserve extracted text, page or slide structure, images, crops,
captions, layout hints, and source locators for later human presentation. Typed
candidates project reusable facts such as selling points and case-study stories
for review. Neither extracted text nor an image becomes an approved proposal
claim merely because parsing succeeded.
reusable and whether it containsPricing. Every unit starts
with reusable: false. Only a unit from an uploaded deck or one-sheet can be
made reusable; sites, URLs, crawl manifests, spreadsheets, and dictated
Material do not yield reusable units.
Use save_material with action: "mark_reusable" after reading the Material
and the unit you intend to mark. A unit that containsPricing cannot be marked
reusable until its price figure is replaced with a rate-card value. A reusable
unit keeps layout figures, while its prices resolve from the rate card.
Review and confirm extracted candidates
Extraction returns review candidates; it never changes live selling state. Each candidate names its source Material and revision, stable candidate ID, exact evidence locator and digest, relevance and confidentiality scope, and canonical owner. It contains either a schema-validproposedMutation or an unwritable
reason.
Material-owned selling points and case-study stories are confirmed through the
save_material arguments returned on the candidate. Playbook instructions use
save_playbook; AI Business Rules use save_business_rules; wholesale products,
pricing, and formats use save_wholesale_product; signals use save_signal;
and Seller identity uses save_seller. Do not move a proposal to another tool
or remove its materialCandidate provenance.
An accepted Material-owned selling point or case-study story can ground later
RFP composition when its visibility and relevance match the RFP. Composition
reads only the candidate on the Material’s current immutable source revision
and preserves the Material ID, revision, candidate ID, and evidence locator in
the proposal claim. Replacing the source, correcting or withdrawing the
candidate, or changing its scope invalidates Quick RFP reuse. Visual assets pass
a separate rights, confidentiality, expiry, media-type, and accessibility gate;
accepting a text candidate does not authorize its images.
Playbook and AI Business Rules content saves replace their complete active
documents. Extraction therefore returns these suggestions as unwritable when
it does not have the current complete destination document. Merge the evidence
with the current document first, then save the complete result through the
named canonical tool; do not confirm a one-line replacement.
For example, a Seller-description candidate can return:
destinationOwner and the primary evidence locator remain available for
clients built against the first v3 Material response. New clients should use
proposedOwner and evidenceItems for the complete typed routing and evidence
envelope.
After a person or authorized agent explicitly confirms the proposal, call the
named tool with those exact arguments. A successful save adds
materialReceipt to the response. Reading the Material again projects the
bounded receipt with the destination tool and destination identity. Replaying
the same confirmation returns that receipt without writing twice. A conflicting
or concurrent decision returns an error and makes no additional write. If the
recorded destination save succeeds but receipt projection is interrupted,
retrying the same confirmation resumes the receipt projection without running
the destination save again. While a destination call is running, its dispatch
fence is heartbeated and cannot be reassigned. If the process ends without a
usable destination acknowledgment, the result becomes indeterminate: do not
repeat the save. Verify the canonical destination and reconcile that application.
Client cancellation after dispatch does not abandon the owner write; its
heartbeat is bounded and stops when the owner settles or the application is
marked indeterminate. An explicit candidate correction versions the exact new
typed proposal under the same source candidate identity, so confirming it does
not reuse the earlier proposal’s application or receipt. A correction cannot
replace a reserved, dispatching, partially saved, indeterminate, or
receipt-pending proposal; first let it settle or explicitly reconcile it.
For multi-part Playbook and AI Business Rules proposals, every requested part must
be acknowledged before the candidate becomes accepted. If only some parts are
saved, materialPartialReceipt records the completed and pending parts with the
owner response and its applicationId. Do not replay the full proposal. Resume
only the pending parts through the same typed owner, then call save_material
with action: "reconcile_candidate", that applicationId, and the verified
canonical record still in place. Reconciliation re-reads the named typed owner;
it does not accept a caller-supplied destination, dispatch, or repeat an owner save. Exact concurrent or replayed
reconciliation calls return the same receipt.
A late owner acknowledgment is stored as destination_saved before Material
projection. Projection failures retain bounded retry evidence and resume
without calling the owner again.
Use save_material with action: "decide_candidate" and
decision.action: "reject" or "correct" to record a review outcome without
applying a destination-owned proposal. A corrected typed proposal remains on
its original canonical tool and must be confirmed in a later call to that tool.
Material states are needs_upload, queued, processing, ready,
partial, or failed. partial and failed include diagnostics and a safe
next step. Unsupported facets are reported as unsupported; bounded or lossy
facets are degraded. Neither state is presented as complete or ready.
The Product Marketing Page is a v3 Material client. It lists Material with
search({ "kind": "material" }), reads each visible record with
get({ "kind": "material", "id": "MATERIAL_ID" }), and records
Material-owned candidate decisions with save_material. Sellers can select a
supported file in the Page; it verifies the type, size, and SHA-256 digest
locally, reserves seller-private storage, uploads directly with the expiring
PUT capability, and finalizes the exact reservation with replace_source.
The signed URL and headers are used transiently by the widget and are never
rendered, written to model context, or retained as retry state. Supported Page
uploads are PDF, PowerPoint (.pptx), Excel (.xlsx), CSV, PNG, JPEG, GIF, and
WebP files up to 100 MB.
Each Material card shows the canonical processing state and whether original,
extraction-diagnostic, and visual-asset extensions are available. Visual
inspection loads only bounded descriptors (25 at a time); it never requests
the original source-access URL or retains preview capabilities.
Pending Material-owned candidates can be accepted, rejected, or corrected in
the Page. Corrections are limited to the candidate title and summary and are
fenced to the source revision shown. A destination-owned proposal is displayed
as a handoff to its named canonical workflow; Teach never converts it into a
generic Material write. The Page does not call a separate product-marketing
corpus endpoint or infer inventory gaps locally.
Candidate collections are bounded. When candidates.nextCursor is present,
pass it back as options.pages.candidates.cursor; the cursor is scoped to that
Material revision and cannot continue another record.
get(material) returns bounded rendition summaries by default. Request large
collections explicitly and page each collection independently:
Review live RFP demand
Usesearch({ "kind": "rfp" }) for the seller’s saved RFP ledger. The Demand
Inbox Page applies that same read model: it shows bounded pages of saved RFPs,
uses continuations from the search response, and treats missing metrics as
unavailable instead of recalculating them in the Page.
An imported historical brief appears with origin: imported. Read its RFP with
get({ "kind": "rfp", "id": "RFP_ID" }) to see its pair state: whether a
response is attached, its commentary, and whether the pair is endorsed.
Open one response with get({ "kind": "rfp_turn", "id": "RFP_TURN_ID" }).
Proposal Pass reads the immutable turn, including its request, response state,
semantic response document, outcome, feedback, representations, receipts, and
diagnostics. Feedback, future revisions, and release actions go through
save_rfp; sent turns are not mutated in place.
Read aggregate seller analytics with get_rfp_performance. The tool owns
metric population, freshness, disclosure, dimensions, and pagination. Per-RFP
drill-in remains get({ "kind": "rfp" }), so the dashboard does not compute
aggregate rollups locally.
While the first rendition is still queued or processing, omit
renditionRevision: requested collections return bounded empty pages until an
active rendition exists. Selecting a rendition revision that does not exist is
still an error.
Blocks preserve page, slide, or sheet identity, reading order, tables, source
locators, geometry, and extraction provenance. Visual assets preserve their
digest, type, dimensions, crop and placement, caption/OCR/alt text,
confidentiality, and reuse rights. Original and preview binaries remain out of
band: source_access and asset access fields are tenant-authorized signed URLs
that expire in at most 15 minutes.
Extraction accepts at most 100 MB of source bytes, 5,000 archive entries,
10 MB per expanded archive entry, 50 MB across expanded archive entries, and
20,000 spreadsheet cells. Each rendition is also bounded to 500
page/slide/sheet units, 5,000 semantic blocks, and 500 visual assets.
Compressed spreadsheets and PPTX use the same archive expansion ceilings.
Reaching a bound produces an explicit failed or degraded
rendition while preserving the immutable original. An asset marked
requires_approval remains unusable until a durable approval receipt exists;
a caller-supplied approval assertion is never authorization.
Legacy Product Marketing projections retain their historical outer ready
state for compatibility. Their rendition remains partial, with unsupported
visual/table facets and a projection diagnostic. Requested rendition includes
return bounded empty or diagnostic pages instead of silently disappearing.
Upload reservations that are not finalized expire after 24 hours and are
cleaned in bounded worker batches. Finalized originals are immutable and are
retained with their Material revision; rendition refresh never overwrites or
aliases an older object. save_material({ "action": "reprocess", ... })
creates a new rendition revision over the same original. Candidate decisions
remain separate Material records and never update operational owners such as
products, rules, or inventory sources.
Create and revise seller RFPs
Usesave_rfp to create an RFP and automatically queue its first immutable
request-and-response turn. Poll that turn with get({"kind":"rfp_turn"}) until
it reaches ready, passed, needs_clarification, or failed. A ready turn
contains a populated response composed from this Seller Account’s active,
priced products and canonical creative formats; missing catalog facts produce
explicit clarification instead of an empty proposal.
See Seller RFP lifecycle for the action union,
idempotency contract, lifecycle states, response artifact, search filters, and
failure behavior.
To add the response you sent for a brief, use save_rfp with
attach_response. Use endorse or unendorse on the pair to control whether
it is offered as a good example on later compositions. Use the typed
record_feedback fields to save the pair’s grade and feedback; those fields
are commentary on the pair rather than a rewrite of its response.
Answer library requests
Usesearch({ "kind": "library_request" }) to find gaps the agent recorded
while composing, then read one with
get({ "kind": "library_request", "id": "LIBRARY_REQUEST_ID" }). Open and
close requests with save_library_request. Close a request by uploading the
material that fills it or by telling Murph the material in conversation; the
closed request states which path supplied it.
Operate work items and approvals
search({ "kind": "work_item" }) is the unified queue for work waiting on the
Seller Account. The returned workItemKind determines its state vocabulary and
the fields required by save_work_item.
For a creative review, the returned work-item
id is the exact immutable
reviewRef, not the reusable creative ID. Keep that id together with its
contentDigest, and pass both back when saving the decision:
save_work_item refuses
the decision. Search or get the work item again and review the replacement
content before retrying; a stale version is never reported as unchanged.
Saving the same completed result again returns unchanged. A conflicting
correction is refused rather than overwriting authoritative evidence.
AI evaluation, reassignment, and forwarding retry remain Page actions. They
cost money, move accountability, or repeat an external side effect, so they are
not fields on a declarative save.
Read seller-side media buys
When an External advertiser appears in Advertisers, opening it shows the Media Buys that relationship placed with you in every supported host. The Page is scoped to that seller-owned relationship; use the row’s Account setup action when you need to review the relationship instead. List every buy that landed in the Seller Account:sourceId, seller status, buyer customer ID, or ISO 8601 flight-start
instants. Pass the opaque nextCursor back unchanged while hasMore is true.
Partial source coverage and stale status are reported explicitly.
Read one media buy to receive its Seller-scoped exchange timeline, approval,
source legs, identifiers, and newest failure. Recovery classes distinguish a
transient failure from a correctable or structural one. Add
include: ["diagnostics"] for the supporting observation trail.
Query delivery and margin
get_delivery supports two reports:
delivery— seller-reported delivery over an inclusive range of at most 90 days; andmargin— the cumulative seller spread ledger.
Query aggregate RFP performance
Useget_rfp_performance for grouped RFP quality, efficiency, and commercial
metrics. It is the shared reporting contract that Seller Analytics will adopt.
In this release, call it through /mcp/v3; the existing Seller Analytics page
is unchanged. Individual responses, evaluations, feedback, outcomes, and
receipts remain on get({ "kind": "rfp" }).
The default population is live production RFPs. Drafts and evaluations require
an explicit purpose filter, while commercial metrics remain live and released
only. See RFP performance for metric formulas,
dimensions, privacy thresholds, and immutable cursor behavior.
Test your own supply
Every Media Company can run the no-spend own-supply campaign workflow directly from its Seller Account. Use/mcp/v3 to create a sandbox Advertiser and
Campaign, open the organization’s own Seller Products, stage a MediaBuy, add
Creative, activate the sandbox Campaign, and inspect bounded delivery. You do
not need a related Buyer account, switch_account, or a separately provisioned
sandbox entitlement.
The server binds the sandbox Advertiser to the organization’s exact Storefront.
The workflow cannot select another Seller’s inventory, create a production
Advertiser, or spend money. See Sandbox Mode
for the complete sequence and current UI boundary.
Start with the public Test a Sales Agent skill.
Version 1.5 uses the exact evidence names returned by ordinary V3 calls and
selects only from the same completed Product result
(resultsComplete: true). It keeps the selected Product ID, Seller, Source,
Sales Agent, Product query, revision, and pricing option together. If the
Product is absent or that provenance changes before save_media_buy, the
validation stops without staging instead of replaying a stale ID.
Certify the headless demand loop
The versionedv3-seller-demand-loop scenario is the portable certification
for Materials → RFP → reporting. It provisions a disposable Seller Account,
uses only /mcp/v3 tools, uploads representative source types, confirms typed
candidates, composes and revises immutable RFP turns, downloads every proposal
representation, exercises Quick RFP caching, reads Demand Inbox and Seller
Analytics contracts, then destroys the fixture. The trusted observer reads the
request audit ledger independently, rejects v2 MCP traffic, verifies bounded
collections, and publishes a credential-free JSON artifact.
Run the deterministic staging journey against the deployed canary revision:
/mcp/v3 credential, reject
any v2 fallback, record tool calls and artifact digests without tokens or
signed URLs, and clean up the disposable fixture. Its transcript is exploratory
product evidence; the deterministic artifact remains the certification result.