Skip to main content
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

Call get_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:
The projection distinguishes:
  • configuredCapabilities — the declaration you saved; and
  • capabilities — what buyers can use after source topology and approval policy are applied.
These values may disagree. 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

Use save_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:
Connection and health answer different questions: usable credentials can exist while every call fails. Diagnostics follow the source’s actual connection. If the source has no supported diagnostic marker, the include is reported as unsupported instead of guessing another source or agent ID. For a modular source, request its module roster and lifecycle coverage with:
The response places a compact 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:
The Page reports the probe’s own result, and the probe updates the recorded state whether it passed, failed, or could not reach the ad server. On FreeWheel the same probe is what observes an execution currency, so a source that has never been probed cannot declare one. An ad-server-backed source has two identifiers — its 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_server for credentials and OAuth;
  • ad_server_source for connection management;
  • ad_server_diagnostics for sync history, refresh, and the connection test; and
  • source_diagnostics for 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.
Read coverage with:
Use 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 the save_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.
Read it back with:
Uploaded decks and one-sheets expose unit summaries. A unit summary says whether it is 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-valid proposedMutation 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.
Advertiser-confidential evidence requires an exact advertiserRef. Any advertiser-scoped candidate is not writable to a Seller-wide record when that record cannot preserve the advertiser scope; confirmation returns an error without writing that record.
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

Use search({ "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

Use save_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

Use search({ "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:
If either value no longer matches the version read, 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:
Filter by 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; and
  • margin — the cumulative seller spread ledger.
Delivery is seller-reported, not buyer-side measurement. Finality does not by itself make a result eligible for billing. Missing source values remain unavailable rather than being invented as zero. Reporting pages are live per call; a cursor anchors continuation but does not create snapshot isolation.

Query aggregate RFP performance

Use get_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 versioned v3-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:
The result contains the immutable evidence reference and digest. A failure to provision credentials, reach the canary, render an artifact, or validate an authorized exchange is reported as a failure; the harness never substitutes a local or synthetic pass. For an independent MCP-capable host, create an isolated Conductor workspace and give the host the same machine-readable task. Replace the project id and base commit with the deployed revision being certified:
The external-host prompt must use the supplied /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.