tools/list is authoritative for the active account. A principal with both
Buyer and Seller access receives their deduplicated union at connection time,
while calls remain authorized against the selected account. Enrollment,
permissions, feature rollout, and host support can narrow the catalog. This
page explains the complete registered families and intended use.Navigation and shared tools
The Identity and brands guide covers current identity and provenance, domain correction, public brand lookup, confirmation and human proof follow-up in text-only clients. These operations useget_status, get, save_buyer_operator, save_advertiser and save_seller.
Select identityContract: "confirmed-v1" for the preview and confirmation
workflow; existing save payloads keep their earlier contract.
Catalogs
Buyer accounts can search and read their advertiser-scoped catalogs withsearch(kind: "catalog") and
get(kind: "catalog", id, advertiserId: "12345"). Use
save_catalog to declare one AdCP Catalog or archive it. Item reads are a
bounded get include and never expose feed credentials.
Open Media Buys
open_media_buys_page opens the Seller Media Buys Page. It accepts an optional
positive-integer-string accountRelationshipId and optional view of
media_buys, creatives, or delivery. With no relationship ID, it opens the Seller’s
unfiltered Media Buys Page.
When a relationship ID is supplied, the tool first proves that the relationship
belongs to the authenticated Seller Account. An unknown or another seller’s
relationship fails closed: it returns no Page directive and opens nothing. The
Page then shows only that buyer relationship’s activity with the Seller — its
media buys and synced creatives — never the buyer’s own campaigns.
Every search call must provide query, kind, or both. An empty call is
invalid. Use query for a match term or documentation question and kind to
list account objects.
A Buyer can browse the selected advertiser’s visible products across eligible
Sellers before creating a campaign:
productId, sellerId, and Seller name
needed for a subsequent creative_format search. Pagination traverses each
qualified product once, even when multiple seller proposals reference it. Pass
nextCursor back with the same advertiser and limit. When resultsComplete
is false, replace the provisional page after polling; when partial is true,
do not treat an absent product as unavailable. persistenceIncomplete
identifies a terminal partial result where otherwise visible products were
withheld because a complete, buyer-safe identity could not be persisted;
restart without a cursor to retry them. This read may use live or cached
catalogue results and does not create a proposal, campaign, or media buy.
A Creative search must name exactly one owner. Use filter.advertiserId to
browse the advertiser’s visible Creative summaries, or filter.campaignId to
list summaries attached to one campaign:
formatKind, assetType, role, source, and
promoted. Omitting promoted returns all visible Creatives; true selects
the promoted reusable shelf, and false selects non-promoted Creatives.
Campaign scope supports the top-level query only. Each successful response
repeats the effective owner scope and filters in both text and structured
output. Results are plain Creative summary rows; this search does not open or
return a Creative Library Page. Pass nextCursor back only with the same
selected account, owner scope, effective filters, and limit.
A Seller asking what it currently offers uses:
Conversation history
Buyer and Seller members can explicitly search their prior Murph rooms withkind: "conversation":
matchedText
evidence from the matching title, participant, or message, even when a matching
message is older than the recent transcript tail. Follow a returned id with
get({"kind":"conversation","id":"..."}) to read up to 20 recent,
display-safe user/assistant messages. That bounded detail read does not limit
the history searched. Tool output and system context are never returned.
Service credentials without an end-user identity fail closed, and conversation
search runs only when explicitly requested; it is not included in an
unqualified cross-kind search.
Retained Sessions
Retained Sessions are restricted to signed-in platform operators acting in a seller account without user impersonation; they are not enabled for customer use.search({"kind":"session"}) finds only native Murph conversations whose
history has already been retained.
get({"kind":"session","id":"..."}) reads that retained history, and
save_session can add an idempotent private coaching note. See the
Retained Session timeline for access,
cursor, import-limit, and unsupported-operation boundaries.
save_session: record a private note
save_session accepts only action: "record_note". Use the exact
sessionId returned by Session search or read, a clientRequestId, and the
private note. throughEventId is optional; when supplied, it anchors the
note to one accessible retained event in that Session.
sessionId, clientRequestId, and throughEventId are opaque strings. They
are trimmed, must not be empty, and can contain at most 512 characters. The
private note is also trimmed and required, with a maximum of 8,000
characters.
structuredContent response is limited to the write result:
get({"kind":"session","id":"SESSION_ID"}) to inspect the retained
note.
The same scoped request key with the same content replays the saved note.
Reusing that key with changed content returns a conflict. The tool never sends
an outbound message. A retry is denied when current access no longer permits
the note, and every action other than record_note is unsupported.
This tool is listed only for a signed-in platform operator in an active seller
account. It requires no user impersonation and the current native-room
permission check. The seller catalog entry does not expose it to customers;
the tool also rechecks the operator, end-user, and seller boundaries at call
time. See the Retained Session timeline for
the complete access and retry rules.
Seller and product filters
Forsearch({"kind":"wholesale_product"}), add sourceId to narrow
the list to one ad-server-backed source, or
filter.productStatus to select draft, active, or archived products.
For Buyer seller reads, filter.ids accepts up to 50 exact Storefront ids in
one call, preserves requested order, and reports unavailable ids as
objects.missingIds.
As an alternative Buyer read scoped to one Seller, call get with
kind: "seller", that exact Seller id, the current account’s
advertiserId, and include: ["products"]. Preserve the returned
productQueryId and catalog revision when polling the same request to a
terminal result; do not reuse a Product from an older catalog.
Buyer search(kind:"seller") also accepts these filter fields to narrow results:
seller and connection are intentionally separate buyer nouns. A seller is
one exact Storefront commercial counterparty and can exist before authorization.
A connection is one authorization grant, identified by its typed target.
Seller grants retain sellerId. Enrolled buyers can also connect a
Creative Engine using
target: {kind: "creative_engine", id: "..."} and search its grants with
filter.targetKind: "creative_engine". Omit that filter to list seller grants.
One seller can have zero, one, or multiple connections, and each connection can
contain multiple discovered provider accounts. Use search(kind:"connection")
for questions such as “who am I connected to?” and join the returned sellerId
to the seller catalog when names or marketplace policy are needed.
A get(kind:"seller") call for a single seller also returns
connectionState.directedCampaignSubscription when an active directed campaign
subscription exists between the buyer and that seller. The field is absent on
search results and null when no subscription exists.
Internal Marketplace administration
Directly authenticated Apostra SuperAdmins may also receive two internal tools:
These tools are omitted from every non-SuperAdmin catalog and re-check staff
authorization at execution. Apply performs a whole-batch stale-state preflight,
then commits each Storefront independently. Its response labels this behavior
BEST_EFFORT_WITH_BATCH_PREFLIGHT; callers must inspect every item before
retrying failures.
Plan and billing
save_billing is the model-visible shared settings tool. It accepts exactly one
intent per call: terms or paymentAuthority. Terms acceptance requires the
current version shown in Plan & Billing or the required-terms response, plus
direct organization-admin authority:
action: "terms_not_required" with
terms.accepted: false and terms.governedByExistingContract: true so the
agent does not report a legal acceptance that did not occur.
Card setup keeps all card data outside MCP. Call paymentAuthority with
action: "request", then repeat with action: "confirm" and the returned
confirmationToken. The confirm response has
action: "human_action_required" and a one-time
paymentAuthority.url for the organization’s cardholder. Poll with
action: "status" every 15–30 seconds until the nested status is verified
or expired. The only supported method today is capture_link; branch on the
returned method so future methods remain additive.
Legal acceptance and payout changes remain authorization-sensitive. The three
other tools in this table are private Plan & Billing Page capabilities and may
be omitted from model context. Follow the tool response and Page requirements;
never pass card or bank details through free text.
Buyer tools
Buyer
search and get kinds include the account’s advertisers, campaigns,
creatives, creative formats, creative collections, wholesale products,
proposals, media buys, sellers, asks, and organization-owned Agents, plus other
kinds advertised by the live schema. Follow the Buyer
workflows page for sequencing.
On every buyer read, a sellerId identifies a Storefront. It is not an internal
customer ID. For one compatibility release, a seller’s deprecated
connection.customerId remains available for existing integrations. Use
sellerId or storefrontId instead; connection.customerId will be removed
in a follow-up release after this transition period.
For a saved Creative, add include: ["preview"] to get. The read returns a
15-minute render URL bound to the exact current Creative state revision, or a reason
when the format has no first-party renderable asset. The URL runs only on the
isolated Apostra render origin. A changed Creative invalidates the old URL,
and the response never includes storage URLs, provider preview HTML, or
measurement trackers. Direct image, video, and audio source assets are
renderable; active HTML, VAST, DAAST, and ZIP documents return a reason instead.
Before assembling uploaded assets, search the selected advertiser’s visible
canonical format declarations. This read does not require a campaign and does
not make a provider call or setup request. Seller-owned product declarations
are available without a provider connection; direct-adapter products keep
their existing active-connection visibility rules:
productId is required to keep the catalogue read bounded. Add sellerId or
formatKind when the selected product supplies that scope.
Each result returns an opaque id, the seller’s display name and id, the exact
formatOptionRef, its canonical formatKind, any declared frame and size, and
its slots. Every slot includes its stable slotId, required flag, minimum and
maximum cardinality, accepted asset kind, and the exact authored constraint
fields supplied by the product. Use the opaque result id with
get({kind: "creative_format", id, advertiserId}) for stable readback. The
read includes only currently buyer-visible product and publisher declarations;
it does not add entries from the legacy global format catalogue. Pass the
returned id as creativeFormatId when calling advertiser-scoped
save_creative. The server revalidates the selected advertiser, seller,
product route, option, and declaration before reading an asset or writing a
Creative. If formatKind or formatOptionRef is also supplied, it must match
the selected format.
Search creative collections with exactly one campaign or advertiser scope. You can
create an advertiser collection without attaching it to a campaign. To read one,
use get with kind: 'creative_collection', its id, and advertiserId. To change
an advertiser collection, use save_creative_collection with advertiserId,
collectionId, and the returned updatedAt as expectedUpdatedAt. Updates allow
name, description (description: null clears it), or parentId (parentId: null clears it); member changes accept saved creative ids only. Results include
parentId and descendantMemberCount, which counts distinct members across the
collection and its active descendants. A parent must belong to the same
advertiser, cannot be the collection or one of its descendants, and cannot make
the hierarchy deeper than 16 levels. Archive with isArchived: true only after
archiving child collections. Restore with isArchived: false and the archive
response’s expectedUpdatedAt; a collection with a parent can be restored only
while that parent is active and belongs to the same advertiser. A stale revision
does not change the collection, and expectedUpdatedAt is refused on campaign
collections, which carry no revision fence. Advertiser collections remain
non-executable: they do not attach campaigns or set roles, sync policy, or
arbitrary metadata.
Replay an uncertain advertiser create
When creating an advertiser, you may supply anidempotencyKey of 16–255
letters, numbers, underscores, periods, colons, or hyphens. Use one key for one
logical create and reuse that exact key with the unchanged create payload if the
response is lost or uncertain. The replay returns the originally created
advertiser; changing the payload with the same key returns a conflict. The key
is create-only and optional, so a create without it retains ordinary create
behavior. Keep correlationId unique for each transport attempt: it is a
diagnostic handle, not the replay key.
Create and verify a campaign creative
Callsave_creative with a campaignId, name, and optional assets to add a
creative directly to a campaign. Each asset supplies exactly one public url
or base64 dataUrl, plus its assetType. The direct tool accepts image, video,
audio, HTML, VAST XML, and text media; ZIP bundles continue through the inspected
HTML5 upload flow. Add clickUrl
when the creative has a click-through destination. makePrimary is available
for image, video, audio, HTML, and VAST assets; text can be attached only as a
subsidiary asset.
For a local JPEG, PNG, or MP4, select the owning advertiserId and call
upload_creative_asset. A destination Storefront connection and provider
account are deliberately not part of this V3 source identity.
The Task hashes the file in the browser and sends the bytes directly to private
storage. File bytes never enter model or chat context. The signed PUT URL is
returned only to the embedded Task app; it is excluded from model-visible
results, chat/activity, logs, and persistence.
Configured buyer ingress accepts JPEG and PNG files of 1–30,000,000 bytes.
When managed-video ingress and inspection are configured, authenticated Buyer
Accounts also accept MP4 files of 1–2,000,000,000 bytes.
Finalization verifies the declared MIME type, exact size, and digest. MP4
finalization also reports asynchronous media inspection state. An expired
preparation must be started again; retrying a completed upload returns the same
source identity.
Pass a finalized JPEG/PNG source reference verbatim as sourceAssetRef to
save_creative. The advertiser is the supplied advertiserId, or is derived
from campaignId.
For an eligible reference, use sourceAssetRef instead of assets:
campaignId, the creative is created under that campaign’s advertiser
first and then attached through normal campaign membership. Retry the same
sourceAssetRef and name after an uncertain response: an existing adoption
is returned and any interrupted campaign attachment is completed. A different
name is refused rather than renaming or duplicating the adoption. Use
advertiserId instead of campaignId to keep the creative in the advertiser
library for later assignment.
To assemble uploaded assets before a campaign exists, search the selected
product with search({kind: "creative_format", filter: {advertiserId, productId}}), then pass the result’s opaque id as creativeFormatId. Bind
each durable asset to a declared slot through sourceAssets[].assetId. The
upload Task does not choose a format. save_creative derives the canonical
formatKind and formatOptionRef from the signed selection and resolves only
its exact seller and product route.
Use advertiserId with creativeFormatId to keep the assembled Creative in
the Library without a campaign. For a campaign-scoped create, use campaignId,
formatKind, and the campaign product’s exact formatOptionRef instead; the
save also attaches the new Creative to that campaign. V3 does not yet attach an
existing advertiser-only Creative; use the V2
attach_creatives_to_campaign operation for that later step. Ordinary
assets are unbound and
cannot satisfy those slots in the same call. Repeatable groups use
group[index].member: bind uploaded media through sourceAssets[].slot and
text or URL members through social.components[].slot, using the same
zero-based index for every required member in an instance. Indices must be
contiguous from zero. For example, a hosted-video format can bind an MP4 to
video and a JPEG or PNG to thumbnail:
"mode": "draft". A draft is scoped to
the advertiser and can omit required media, copy, destination, or repeat-group
slots. The response and every later Creative read return its state and
whole-state stateRevision. The existing opaque revision remains the
buyer-preview projection digest.
Revise the same draft by sending its creativeId, current stateRevision as
expectedRevision, the signed creativeFormatId, and the complete replacement
sourceAssets and authored-slot state. The save replaces the prior submitted
state; it never merges two revisions. A stale revision fails without changing
the Creative.
Use "mode": "complete" on that same replacement when all required slots are
present. Completion runs the format’s current server-side validation and keeps
the Creative in the advertiser Library without attaching it to a campaign or
contacting a provider. Existing calls that omit mode keep complete-save
behavior.
The server re-proves every source against the advertiser. A video must have
completed inspection and reached promoted. Saving under advertiserId
creates the canonical Creative without a campaign or provider call. Saving
under campaignId also attaches it. Video delivery remains
destination_required until V2 attach_creatives_to_campaign resolves a
compatible selected Meta destination. That governed attachment rechecks the
durable Library source and current account authorization, then uses normal Meta
review and readback. Other destinations remain unsupported for this bridge. Do
not substitute the provider-bound V2 adoption operation for a buyer-owned V3
source.
After the campaign executes, call get with kind: "creative", sourceId set
to the campaign ID, and id set to the returned creative ID. When a legacy
Sales Agent library receives the creative through sync_creatives,
platformLinks rows show the
downstream ad-platform sync status, platform ID, approval status, and last sync
time. Inline package delivery does not create a platformLinks row. Each agent
has one authoritative row: the most recently updated account lineage wins
after a credential or account rotation. A platform ID confirms that the
destination created its creative object; the status and approval fields still
determine whether it is ready to deliver. Existing metadata-only
save_creative calls require no changes.
Start with get_status. Its operatorIdentity.usableForBuying field is false
when the operator is missing or still uses a platform-owned legacy fallback.
In that state, an account administrator must call save_buyer_operator with
the buyer’s real non-platform domain and choose whole_operator or a stable
specific_unit before new discovery or buying work. When the domain is usable,
scopeStatus is unclassified, and locked is false, reuse that domain and
choose its scope before new AdCP 3.2 provisioning. If the identity is locked,
follow the support action from get_status instead. This confirms the
commercial operator identity used with sellers; it does not add users, change
account membership, or change the login organization.
Launch a campaign with explicit confirmation
Launching withsave_campaign is a two-call operation. First request a
preview without changing the campaign:
action: "pending_confirmation" — a successful, structured
response, not an error — with campaign.revision, the campaign budget and
flight, and under launch exactly what would go live: mediaBuys (each
staged media buy’s id, name, phase, budget, and seller; the first 25, with
mediaBuysTruncated: true if there are more), mediaBuyCount, and
combinedBudget (the sum across those buys when they share a currency;
null with a per-currency budgetsByCurrency list when they do not).
nextStep carries the exact follow-up call, including a fresh idempotencyKey for the confirmation (the preview’s key must not be reused, or the preview is replayed). It does not launch the campaign.
Do not combine this preview with campaign field changes; save those changes in
a separate call before requesting the preview.
After reviewing the preview, send that campaign.revision as
expectedRevision with explicit confirmation:
confirmLaunch: true requires the expectedRevision returned by the preview.
The server checks that revision again while holding the campaign mutation lock,
before any provider dispatch. If the campaign changed after the preview, the
call returns REVISION_CONFLICT; re-read the campaign, request a new preview,
and confirm that new revision instead of reusing the earlier confirmation.
Cancel a campaign without canceling its media buys
To cancel a campaign, senddesiredPhase: "canceled" by itself with the
campaign’s current expectedRevision:
phase: "canceled".
If the cancellation response is lost, re-read the campaign and retry with its
committed revision. An already cancelled campaign then returns its terminal
state; this is terminal-state convergence, not a replay of the original
response body.
Archive is separate: use isArchived: true only when you want to remove a
campaign from default visibility.
Archive and restore
save_advertiser and save_campaign archive with isArchived: true and
restore with isArchived: false. Archiving is a soft delete: the record moves
to archived state and everything under it is retained and stays readable.
Archiving an advertiser does not lock its campaigns, media buys, or creatives
— search and get on those children keep working — and it frees the
advertiser’s name for a new advertiser. Restoring an advertiser whose name is
now held by an active advertiser returns CONFLICT; rename or archive the
other advertiser first.
To archive several advertisers in one confirmed action, pass advertiserIds
(up to 50) with isArchived instead of advertiserId. Each advertiser is
archived or restored independently and the response lists every outcome under
results; partialWrite: true marks a mixed result.
A restored campaign comes back as a draft: its media buys were retired when it
was archived, so stage inventory again before launching. save_media_buy
archives a draft media buy only (isArchived: true); a dispatched buy is
cancelled through the campaign or the v2 update contract, because that
cancellation may wait on seller or operator approval and must not be reported
as done before it is. An archived media buy cannot be restored; stage a new one
on the campaign.
Advertiser and campaign tracking
Tracking is a typed field on the existingadvertiser and campaign nouns;
it is not a separate V3 noun or tool family. V3 uses the same tracking services
as the V2 REST compatibility surface.
Set advertiser defaults with save_advertiser. This HappyDemics example keeps
the raw vendor tag, identifies its documented dialect, and lets the server
compile it to AdCP universal macros:
tracking.trackers[] returns a stable trackerId, the
retained rawUrl, the translated canonicalUrl, and the auditable mapping
metadata. In the example, documented HappyDemics tokens canonicalize as
{{USER_ID}} → {DEVICE_ID} and {{GDPR_CONSENT_STRING}} →
{GDPR_CONSENT}. Other double-brace spellings are not inferred without their
own vendor evidence.
V3 returns bounded mapping, diagnostic, and documentation summaries with their
total counts; the V2 tracking-config response retains the complete stored
mapping artifact for non-model audit clients. Long URL values use bounded
previews with their original length and a truncation flag, and effective
campaign entries do not duplicate the source tracker’s mapping artifact. When
updating an existing tracker, send its trackerId and omit url to preserve
the complete stored URL; a returned truncated preview is also recognized and
will not overwrite that stored value. Send the returned advertiser revision
or campaign campaignRevision as tracking.expectedRevision to make any
tracking update an atomic compare-and-set; URL-preserving updates add that
guard automatically.
Tracker URLs are limited to 8,192 characters and 64 macro tokens. For a custom
event, set trackerType to custom and supply customEventName; that field is
invalid for impression or click trackers. Stored free-form tracking values
returned by V3 are bounded and fenced as untrusted external data. Tracker
labels, custom event names, and custom-macro descriptions can be passed back
unchanged on an update; the server restores their exact stored values. New or
changed custom-macro descriptions are limited to 240 characters.
Before saving or trafficking a tracker, call test_creative_macros. The tool
does not fetch the URL or change a creative. Standard request auditing retains
only statuses and counts, never tracker URLs or binding values. The tool
returns four independently
copyable stages—exact raw input, canonical AdCP form, recipient form, and final
synthetic substitution—plus mapping evidence, bindings, and diagnostics.
{{USER_ID}} → {DEVICE_ID} →
%%ADVERTISING_IDENTIFIER_PLAIN%%, while the final stage uses a visibly
synthetic advertising identifier.
For consent syntax inspection, gvlVendorId can show the corresponding GAM
${GDPR_CONSENT_<id>} form, but a caller-supplied number is not verification:
the report remains failed and not preview-ready. Without the number, the
consent parameter is removed and the report also fails closed. A production
consent mapping needs separate evidence that the ID belongs to the measurement
vendor; the tester never infers that relationship from a pixel URL.
Available scenarios are device_id_present, device_id_unavailable,
gdpr_applies_with_consent, gdpr_does_not_apply, and
missing_required_value. The unavailable-device scenario deliberately shows
an empty device value and labels it privacy_suppressed. Change scenarioKey
to obtain a different deterministic cachebuster. Explicit values must be raw
synthetic test values, never real user identifiers and never pre-encoded; a
value that already contains percent-encoded octets is flagged as possible
double encoding. Binding values and stage templates in the report are bounded
by UTF-8 bytes, and projection reports any truncation or omitted detail. The
whole Murph result stays within a 96 KiB budget. Inspect the substituted stage
for placement and encoding. Explicitly required macros that are absent, missing
required values, unknown or wrong-case tokens, ambiguous vendor syntax, unsafe
nesting, and missing recipient mappings keep passed and readyForPreview
false.
Campaigns inherit advertiser trackers dynamically. Add a campaign-local
tracker or disable one inherited default with save_campaign:
include: ["tracking"] when reading a campaign. Its tracking field
contains the local trackers, inherited overrides, and effectiveTrackers
with sourceScope, inherited, effectiveEnabled, and statusReason.
Within tracking, each supplied array is the complete desired array for that
scope; omit an array to leave that part unchanged.
Seller tools
Seller
search and get kinds include the Seller singleton, inventory sources,
material, RFPs and RFP turns, library requests, coverage, wholesale products, playbook, business rules, media buys,
work items, signals, asks, organization-owned Agents, and other kinds advertised by the live schema. Follow the
Seller workflows page for sequencing.
Inventory-source recorded health evidence
Read one source withget({"kind":"inventory_source","id":"SOURCE_ID", "include":["diagnostics"]}). Its compact health projection preserves the
recorded lastErrorAt, lastSuccessAt, and lastCheckedAt values from source
diagnostics, including null. These are recorded observations, not a new
provider probe made by get: when the check timestamp is null, freshness is
unavailable rather than assumed to be now. A later recorded success makes an
earlier recorded error historical evidence; it does not erase the original
evidence or prove a transaction succeeded. A successful health observation is
not proof that a media buy was accepted or delivered. To request a new
no-spend check, use the existing refresh_inventory_source_health flow.
search({"kind":"library_request"}) and
get({"kind":"library_request","id":"LIBRARY_REQUEST_ID"}) are gated by
the sales-library rollout. Search accepts filter.status (open or
closed) and filter.originRfpTurnId; get returns the request’s gap, status,
origin turn, and closing Material evidence.
Organization-owned Agents
search({"kind":"agent"}) lists the software Agents the active account’s
organization owns. Add query to match an Agent ID, Agent display name, or
operator display name. This explicit-only kind does not appear in unrelated
broad object searches and does not turn a buyer counterparty Storefront into an
Agent.
Read one result with get({"kind":"agent","id":"AGENT_ID"}). Add
include:["certification"] for the complete customer-safe certification
summary, include:["validationRuns"] for up to five server-bound run summaries,
or include:["diagnostics"] for observed implementation health and the current
production-revision label. A returned run’s diagnosticRead shows the exact
follow-up: pass its validationRunId with include:["diagnostics"] to receive
the bounded Activity graph. Sales Agent detail also names its immutable
versioned public validationSkill. These reads intentionally omit
credentials, private evidence, operator identifiers, relationship identities,
and owner-only action URLs.
Interactive seller Pages that run inside a host use the account-resolved v3
surface for these reads and writes. In Apostra’s hosted bridge, the nested
/mcp/:toolName proxy accepts surface: "v3" and forwards the call to
/mcp/v3; callers still use the tool’s canonical arguments, not REST paths.
The Seller RFP lifecycle guide defines the
save_rfp action union, polling states, complete response requirements, and
clarification/failure behavior.
The RFP performance guide defines aggregate
metric formulas, valid dimensions, disclosure thresholds, and immutable
pagination. Individual RFP facts remain on get({ kind: "rfp" }).
Material is evidence and teaching input. It does not replace inventory sources,
products, pricing, Playbook instructions, business rules, signals, formats, or
Seller identity. Use
get({ "kind": "material", "id": "MATERIAL_ID" }) to inspect the current
source revision, ingestion state, diagnostics, typed candidates, confirmation
receipts, bounded rendition summaries, and source artifact references. Explicit
includes expose independently paginated rendition blocks, reusable visual
assets, extraction diagnostics, composition receipts, and expiring source
access; originals and derived binaries are never embedded in the response.
Confirm a candidate by
calling the exact proposedMutation.tool with its arguments: only
Material-owned selling points and stories use save_material; every other
candidate uses the save tool named in the suggestion. Review, reject, and
correct do not change Seller configuration. Source records may carry supplied original and
derived structure references such as page or slide order, geometry,
table/image/chart assets, OCR/caption artifacts, digests, provenance,
confidentiality, and reuse rights. Completeness is reported per extraction
facet, and unsupported or degraded parsing is never presented as ready. See
Seller workflows for upload finalization,
selection, retention, and access behavior.
MCP App and resource-bound tools
These tools support interactive Pages or resources. A compliant host may keep some of them out of model context and invoke them only through the associated app contract. The Product Marketing Page receives a session-bound capability fromopen_page. It uses the host-only teach_search_materials,
teach_get_material, teach_save_material, and teach_renew_capability
aliases for Material listing and exact reads, seller-private URL and file
additions, upload finalization, Material-owned candidate decisions, and
capability renewal. MCP clients continue to use the public search, get, and
save_material tools. The bridge does not permit generic Material writes or
return source-access or visual-preview URLs. Expiring upload credentials are
returned only for the transient browser PUT step.
An active, unexpired Demo can also run the fixed synthetic evaluation from the
Product Marketing Page. These app-only tools require the same session-bound
Teach capability and cannot be invoked as general chat actions:
All results are rehearsal-only. Synthetic rate-card figures are planning
examples, not live prices or buyer-quotable rates. Custom fulfilment requires a
named human or Connect follow-up; the evaluation does not make it automated or
available now. See Controlled synthetic evaluation
for the full seller workflow.
The Library Page uses the host-only
library_* aliases the same way, including
library_get_rfp_turn and library_open_proposal_pass for opening the
authorised Proposal Pass of a response from the Usage view; see
MCP Apps for the
full list.
The Buyer Page companion tools in this table are app-only and are not part of
the model-visible buyer catalog.
Current Media Partners Page bundles use public V3
search, get, save_connection,
and save_ask; the two closed Media Partners Page facades remain only for a rolling
deploy window. Current Campaigns bundles instead use the resource-bound
app-only buyer_campaigns_page_search and buyer_campaigns_page_get tools,
backed by canonical V3 projections; Advertisers uses its closed
landing-projection read. None of these Pages receives the generic api_call
surface.
Except for download_discovery_printable_card, the Listing and ChatGPT
destination tools above are shared between the model-visible seller catalog
and the Listing page (see Seller Pages). They use
the same account, administrator, and confirmation checks in both paths. The
printable listing tool is app-only because it returns PDF bytes for a browser
download; print fulfillment and provider orders remain outside the tool.
Core read examples
List objects:proposals, recentActivity, deliverySummary, and sourceIdentity
are accepted include names so the API can return a precise
unavailableIncludes explanation, but they are not populated in the preview.
Search documentation:
document path:
Read structured results
Every tool returns MCPcontent for a person or model to read. Integrations
should make decisions from structuredContent. tools/list is authoritative
for inputs and publishes an output schema where the current tool declares one;
the patterns below cover the remaining preview tools.
Do not parse IDs, revisions, actions, or recovery guidance out of rendered
prose. A write may return
action: "unchanged"; that is a successful
idempotent outcome. On partial work, preserve partialWrite, warnings,
errors, per-seller or per-source outcomes, and any returned current revision.
request_proposals.status is normally running while durable background work
contacts the cohort; retry that same key until it becomes complete,
partial, or failed. A buyer can have only one running proposal execution
across campaigns. Terminal result cursors can continue a product-heavy outcome
for the same seller, and detailsTruncated marks byte-bounded product fields.
When a seller cannot execute an exact age range, its proposal remains available
as a counter-pitch and its semantic document names the limitation and the
seller’s supported ranges. A direct get_products response carries the same
information in its additive limitations array: code, buyer-readable
message, requested min/max/include_unknown, and supported_ranges.
AI-8599 bounded targeting continuation (cursor protocol v1)
Capability details can exceed a model-safe response page. V3 therefore exposes two signed, opaque continuation fields; they are discovery/readback only and do not contact a seller or start a new proposal round.
Cursors are account- and snapshot-bound. A forged, stale, or wrong-scope cursor
returns a validation error; a Proposal’s expiry remains explicit in its
read-only
state and never gives a cursor execution authority. Follow a
continuation only while the response supplies its next cursor. A terminal page
has complete: true and no next cursor. A capability marked unavailable or
blocked is not complete actionable targeting: demographic selections remain
rejected before seller dispatch while the application seller transport remains
on AdCP 3.1. If a signed continuation cannot fit its approved field limit, V3
omits the token and marks the capability unavailable rather than truncating its
scope or presenting omitted details as complete.
For example, a successful advertiser creation returns the new identity under
the noun rather than as an unlabelled string:
request_proposals returns enough state to continue each seller branch:
page.nextCursor before treating the review as complete.
Errors and result handling
Tool errors use bounded structured codes and explanatory text. Common classes include validation errors, access denial, not found, revision conflict, unsupported preview behavior, external failure, and partial results.- Treat
isError: trueas a failed tool result even when the MCP transport itself returned successfully. - Preserve structured IDs and recovery fields; do not parse prose to recover an
identifier already present in
structuredContent. - A partial result is not an empty result. Read its warnings, coverage, and per-source or per-seller outcomes.
- Re-read after any response that reports a partial write.