Skip to main content
This alpha V3 MCP contract is available only to enrolled Buyer Accounts. It adds buyer-owned engine discovery and connection setup, campaign- and advertiser-scoped session reads, durable session saves, and explicit generation or refinement. Provider qualification and the end-to-end buyer journey remain separate work.
Creative Engines gates generation and refinement, not assembly. Any authorized buyer can use the Creative Library to assemble a draft in a campaign Creative Session by choosing a format, filling slots, adding a name and click-through URL, and saving. This does not create a Creative. When Creative Engines is not enabled, the composer leaves those assembly controls available and asks your Apostra account team to enable it for the Buyer Account. Your Apostra account team enables Creative Engines for enrolled Buyer Accounts. Contact them to ask about enrollment. For Buyer Accounts enrolled in the Scope3-funded preview, Apostra can generate images, hosted video, and hosted audio without setup. Apostra does not show or ask you to choose its paid engines. When a buyer has an active connected engine for the requested media kind, Apostra uses that connection first; otherwise it uses the eligible Scope3-funded engine. This preview has no retail IU charge. It is limited to 50 provider generation requests per enrolled account per UTC day and 500 globally per UTC day. An eligible funded media kind can also have separate account and global daily limits; a request that reaches any applicable limit is refused until the next UTC day. An image draft without an explicit direction uses three distinct composition directions only with the Scope3-funded preview engine, and only when partial_success is not false. A customer-key image engine keeps one direction unless the request supplies its own variant_axis; an explicit axis keeps its supplied number of directions. Refining a named parent is also one direction. Audio, video and every other non-preview branch stay one direction by default. The response returns one leaf per direction, and each preview leaf uses one daily-cap unit. For an engine-less draft, Apostra uses the buyer’s compatible active connection first, including a connected voice provider that holds their voice clones. If there is no compatible connection, it uses the Scope3-funded engine for the kind when the account is eligible. Otherwise, the save says whether an image, video, or audio connection is missing and directs the buyer to Settings → Connections. A failed customer-key request never switches a generation already bound to that connection to the preview credential. For an image draft, set request.variant_count to an integer from 1 through 8 when you want a specific number of directions without writing each one. The service creates distinct composition directions, adding lighting and mood variation after the first three. An explicit request.variant_axis.values always takes precedence. Customer-key engines honour variant_count too. For the Scope3-funded preview, the service checks that the daily account and global caps currently have room for the whole set before any provider request is sent; if not, it returns a cap error and creates no partial set. That check does not reserve capacity: each direction is reserved individually immediately before its provider request. Concurrent preview use can therefore leave an admitted batch with fewer generated directions than requested, but a provider request is never sent without its own reserved cap unit. variant_count cannot be combined with partial_success: false: that atomic single-image mode remains one generation. Complete ad concepts differ: they make three concepts by default with any engine, and a limit reached part way keeps the concepts already made. Omit engine unless the buyer explicitly asks to use their own connected engine. Put the buyer’s exact visual request in request.creative_brief.prompt. If the buyer asks for a specific number of variants, put that number in request.variant_count. For the first 24 hours after a variant_count release, the Creative Engines on-call owner reviews preview usage and provider-dispatch records every four hours. The check passes when every provider dispatch has its own daily-cap unit, and a refused precheck has no provider dispatch. An admitted batch may contain fewer provider dispatches than planned during concurrent use. After six clean checks the manual review ends. A mismatch or unexplained cap error pauses the Scope3 preview binding while the owner investigates and rolls back the release if needed.

Bring your own provider connection

Use Settings → Connections when the buyer needs their own provider account, such as a voice clone. Complete the secure setup there; never put a provider token into tool arguments or chat. A connection is the buyer’s authorization to a provider and can have its own provider accounts and advertiser mappings. The service uses a compatible active connection automatically when a draft does not name an engine. In Apostra, select Connections, then Creative tools. This section shows providers for which your account needs to connect its own credential. A provider is omitted only while your account is currently covered by a configured, Scope3-funded preview. Existing buyer credentials remain listed so you can manage or disconnect them. Availability depends on your enrolled preview and provider qualification. In an MCP Apps host, call open_creative_engines_page to open the Creative Engines Page. You can ask Apostra to find a registered provider and open its connection setup there; you start the secure connection yourself.

Discover an engine

Call search with kind: "creative_engine". Use query to match an engine or provider name, filter.ids for up to 50 exact engine IDs, and limit plus the returned cursor to page results. IDs are positive integer strings.
Results contain one record per engine, including its name, description, provider, authentication modes and your existing grants. The capabilities declaration lists modalities, transformer IDs, supported format IDs and build/preview support when the registered adapter supplies them. get with the same kind and an engine id returns one record. Declarations describe support; they are not a live provider health check or proof of access to every model. Grant status describes your connection state. pricing: null means this read has not obtained a quote, not that generation is free. The current supportedFormatIds are adapter format identifiers, not canonical AdCP format declarations or executable capability IDs. Discovery currently covers registered Creative Engines visible to the active buyer. Arbitrary external MCP endpoints cannot be added through this preview.

Paused engines

An engine’s operator can pause it to hold new business. While an engine is paused:
  • It is hidden from search, get and the Creative Engines Page, as if it were not listed.
  • save_connection cannot begin or renew authorization for it.
  • save_creative_session, generate_variants and refinement against it return the SERVICE_UNAVAILABLE error code with details.reason: "engine_paused" and details.retryable: true. Try again later or choose another engine.
Generation already sent to the provider finishes, and you can still read its result. If a batch of variants was only partly sent when the pause started, the variants not yet sent are refused. A pause removes no connections: disconnect, account refresh, account selection and advertiser mapping keep working, and your grants still appear when you list creative connections. When the operator resumes the engine it returns to discovery and your existing connections work again without reconnecting.

Authorize and manage a connection

Use open_creative_engines_page to open Creative Engines in an MCP Apps host. Its Creative tools section supports secure connection repair, account selection, advertiser mapping and disconnect for providers that require your credential. It does not expose provider credentials, accept an arbitrary MCP URL, quote a price or start generation. Engines currently funded for your account do not appear as new connection targets. Call save_connection with exactly one change. To begin authorization:
An engine is also an Account, so target names the engine by its Account id, engineAccountId. A target.id for a creative engine is refused with a VALIDATION_ERROR that names engineAccountId. It is a different number from the engine’s own id: never copy an engine id into engineAccountId. Read engineAccountId from the engine on any read that returns one, as in the list below. An Account id that owns no live engine, or that owns something other than a creative engine, is refused with a VALIDATION_ERROR. An engine’s own id stays its Storefront id, and every reference to an engine uses its Account id. So search and get with kind: "creative_engine" return each engine with its id and engineAccountId beside it, and every other read names the engine by engineAccountId alone:
  • search and get with kind: "connection" for a creative engine grant, on the grant’s target and its engine, which carry no id;
  • a Creative Session’s engine, as {engineAccountId, connectionId};
  • the result of open_creative_engines_page, which names the engine by engineAccountId and no longer returns engineId.
The same field appears in the text of these results. An engine that is not found has no Account id to return, so missingIds is unchanged. The result contains a secure authorization handoff. Open it to complete OAuth or enter a bearer credential, according to the engine’s supported modes. Never put a provider token into tool arguments. The tool does not return token values. The browser handoff identifies the registered provider. In the OpenAI customer-key form, it asks for an OpenAI API key and links to the official OpenAI API key dashboard. This is an explicit customer-key connection only; it does not configure a platform-managed credential or authorize generation spending. To list your creative grants:
Read a grant with get({"kind":"connection","id":"77"}). It includes safe credential status, selected account, advertiser mappings and a bounded account list. Use connectionAccountsOffset with the returned accountsPage.nextOffset for another account page. Provider metadata and secrets are omitted. Use the existing save_connection fields with connectionId to reconnect (authorization), refresh accounts (refreshAccounts: true), select a provider account (selectedAccountId), map an advertiser (advertiserMapping), or disconnect (state: "removed"). A connection cannot change its target. Disconnect retries remain available for owned grants after catalog delisting or preview enrollment is removed. Creative connections do not accept seller selection, advertiser activation, media billing, buying policy or Enhanced Reporting. Signup-restricted credentials cannot use the creative preview. AudioStack and ElevenLabs require an advertiser mapping before generation. This selects the provider organization or workspace that pays for the request. Use advertiserMapping: {state: "mapped", advertiserId: "42", accountId: "88"} with the connection ID. Read accountMappings to find the link ID for unmapping; use connectionMappingsOffset with accountMappingsPage.nextOffset for another mapping page. Replacing the provider key requires remapping the advertiser. For a voice draft, include the exact spoken words in straight or curly quotation marks in request.creative_brief.prompt, or provide a creative_manifest.assets.script text asset. A tone or duration instruction by itself is not voice copy. When preparing a draft, write a short script in quotes from confirmed buyer intent, or ask the buyer for the words to speak before you call generate_variants.

Generation and funding

This alpha provides discovery, setup, session reads and Creative Session operations. save_creative_session saves a brief, selected output, approval or finalisation, and save_creative with fromCreativeSessionOutput saves an exact approved output into a reusable Creative Asset revision. Neither starts generation. generate_variants explicitly prepares and executes one saved session revision. These are generation operations and require Creative Engines. Do not choose a Scope3-funded engine: the service resolves the compatible buyer connection or funded engine for the media kind when it saves the draft. A connection alone does not authorize spending. The Scope3-funded preview is the limited exception described above; its platform-managed engines are paid by Scope3 rather than the customer’s provider account. The operations do not provide a request estimate or turn an unknown catalog price into a quote. For accounts and clients with the existing V2 generation tools, use the generative creative workflow. Use the generation workflow’s applicable funding and price information before requesting paid work. The current catalog’s pricing: null cannot be used as a quote. Customer-key eligibility and provider account requirements still apply; see provider setup. A failed customer-key request does not authorize switching to a platform-funded request. During iteration, preserve the brief, reference assets, target format and parent variant. Retain returned session and task IDs so an interrupted request can resume without submitting another build. Review the exact output that will be finalized, then read back the saved creative. Content acceptance remains separate from seller review and campaign launch. Video generation, and a provider build expected to run for longer, returns a submitted leaf promptly instead of keeping the tool call open. Use the exact poll get request returned by generate_variants; it refreshes the same session and returns the completed variant when ready. Do not submit another generation action while that leaf is still generating. A task that later fails becomes a terminal generation failure rather than a fresh provider request.

Complete ad concepts

Complete concepts are in beta. Your Apostra account team enables them for enrolled Buyer Accounts.
For a format with one image slot and text slots, starting with the Meta Feed Image Ad (format_option_ref facebook.com / meta_image_feed), the first generate_variants action makes complete concepts instead of separate parts. Each concept is one generated image and every text slot written for that image: primary text, headline, description and call to action for a Meta post.
  • How many. Three concepts by default. Set request.variant_count from 1 through 8 for another number, or give one direction per concept in request.variant_axis.values, up to 8.
  • One direction per concept. Every concept has a direction. Its copy and its image are written from the same direction, so the text fits the picture it is shown with.
  • One copy call. One language-model call writes the text of every concept together, so the concepts differ from each other. The writer reads the brief (request.creative_brief.prompt and the objective), the advertiser’s brand profile (voice, dos and don’ts, disclaimers) and the format’s slot limits. The brief and brand text are sent to a language-model provider to write the copy.
  • Your text stays as written. Text you supply for a slot is copied unchanged into every concept, and the writer writes only the other slots. When you supply every text slot, no copy is written and each concept differs only in its image.
  • Checked, never cut. Apostra measures every slot against the format’s limits. Copy over a limit is rewritten once and otherwise refused; it is never shortened. A call to action comes from the format’s allowed list. The copy never contains a link; the click-through URL comes from your request or the brand’s website.
Each concept is an ordinary variant of the session. Read it with get and kind: "creative_session": each entry in variants has its direction, its image preview and text_assets, the text slots as AdCP text assets keyed by the format’s asset ID:
Approving a concept approves its text together with its image. That approval is your own content check, not seller review. To refine a concept, send generate_variants with variantAction: "feedback" and that concept as parentVariantId, as described in Read a creative session. The refined variant keeps the concept’s text; only its image is regenerated.

Choose a concept in the composer

Choosing a concept is part of the complete-concepts beta. It is available only to Buyer Accounts your Apostra account team has enrolled in it. Other accounts do not see these controls, and the tools refuse the request.
In the Creative composer, Generate on a Meta image post with no copy written yet makes the concepts and opens them in the gallery. Each concept card shows Apostra’s labelled approximation of the whole ad. Where Meta’s own preview is available, on a campaign’s draft or an advertiser’s, you can open one card at a time for it, as described in Creative previews. Use this concept fills the composer draft: the concept’s image goes in the image slot and its text in every text slot, each marked Selected concept. Text you wrote yourself keeps its own mark. The choice is the session’s selected variant, so get with kind: "creative_session" returns it as selected_variant_id. Choosing approves nothing; you approve the finished ad in the composer. You can choose a concept on a campaign’s draft or on an advertiser’s draft with no campaign. After you choose a concept:
  • Edit the ad. Changes to slot text, images and the click-through URL are saved. The brief, the format, the concept directions and the draft’s name stay as they were when the concepts were generated; start a new draft to change them.
  • Rewrite one slot. Generate on a text slot rewrites only that slot, with the chosen concept’s direction and your other slots as context. It replaces text you wrote only when you choose Generate on that slot, and it uses one copy call from the daily copy limit.
  • Replace the image. Pick a Library file to replace the concept’s image.
A format with several required image slots keeps the existing generation flow.

Limits and partial results

During the preview, copy is free. A Generate action uses one copy call, and copy has its own daily limit: 100 calls per account and 1,000 across all accounts per UTC day. Each concept’s image uses one unit of the image limits described above.
  • Copy limit reached. No concept is made and no image is generated. The error names the limit and the time it resets, the next UTC midnight.
  • Copy could not be written. If the language model fails or does not answer in time, no image is generated and the error says why. Sending the call again starts over and uses another copy call. While a call’s copy is still being written, repeating that same call is refused and asks you to try again in a minute, and a new action on the session is refused as still running.
  • Image limit already reached. No copy is written and no concept is made. The error names the limit and the time it resets.
  • Image limit reached part way. Apostra keeps the concepts whose images were made and stops the rest. The session’s notices says how many of the requested concepts are ready and when the limit resets. A concept without its image is never shown as a finished ad. If no image could be started, the action returns the same message as an error.
  • Finish the rest. After the reset, repeat the same generate_variants call with the same actionKey and expectedRevision. Each waiting concept’s copy is already saved, so the retry generates their images and writes no new copy. A new action on the session leaves the waiting concepts unfinished.

When an engine is ready for buyers

A Creative Engine is ready for buyers when it is listed, not paused and not archived. Nothing else is required. Unlike a sales storefront, an engine does not need inventory, products, a brand domain or a settlement currency, because it generates creative and does not sell media. An engine never appears in media-buying (sales) discovery, and it is never admitted to a media buy. Use search with kind: "creative_engine" to find it; get_products and seller connections list sales storefronts only.

Existing seller integrations

search({"kind":"connection"}) continues to list seller grants by default. Seller grants carry sellerAccountId, the seller’s Account id. Send sellerAccountId, or target: {kind: "seller", sellerAccountId}, to save_connection. sellerId and a seller target.id are refused with an error that names sellerAccountId. See Naming a seller by Account id. You can continue making creative directly with a provider and bring that creative into Apostra. This alpha does not change that workflow or start a generation job without an explicit generate_variants call.

Read a creative session

A creative session holds work in progress: the brief, plan, variants, evaluation, selection and any finalized creative. Reading it does not start generation. Creative sessions are where generated variants live; they are separate from product variants in a catalog and from saved Library creatives. To find a session by name, list the scope below and match the session title in the results; text queries are not supported. Then open its variants with open_variant_gallery. List sessions within exactly one campaign or advertiser Library:
For a Library session, use filter.advertiserId instead:
Use filter.status to choose drafting, refining, evaluating or finalized. The limit is at most 100. Each result identifies its scope with either a campaignId or an advertiserId, alongside its session ID, title, status and revision. When nextCursor is present, pass it as cursor with the same campaign-or-advertiser scope and status filter. Each page reflects current state; the list does not promise a fixed snapshot or a total count. Text queries and other filters are not supported for sessions. Open a session by ID alone. Apostra resolves its saved owner and checks your current access again:
You may also assert the owner from the search result with sourceId for a campaign or advertiserId for a Library session. The object includes its persisted revision, plan, variants and evaluation.
The read returns the selected variant and the latest session history first. It does not return inline asset data. If a session has more history or detail than one tool response can carry, truncated: true and omitted identify the bounded fields; use the existing V2 workflow for the complete durable record. When the session has a saved engine connection, engine contains its engineAccountId and connectionId. Credential material is not included. A draft names its engine the same way: send engine as {engineAccountId, connectionId}, so the engine object from a read can be sent back unchanged. A draft that sends engine.engineId is refused with a VALIDATION_ERROR that names engine.engineAccountId. Hosted image, audio and video plans can identify their format with format_kind (image, audio_hosted or video_hosted) and params, without an agent URL. Image dimensions use params.width and params.height; an exact audio duration uses params.duration_ms_exact. The declared modality must match the selected engine. A canonical declaration cannot also specify a legacy target format. Explicit legacy format requests retain their existing compatibility path. Video on the Veo engine is generated by Google’s Gemini Omni Flash model. The requested video duration is a target rather than an exact output length; the generated media reports its actual duration when it is available. When you do not set config.resolution, video generation uses the requested height or short side: 360 pixels or less selects 360p, 1080 pixels or more selects 1080p, and 2160 pixels or more selects 4k. Other sizes select 720p. Set config.resolution to 360p, 720p, 1080p, or 4k to choose a different output resolution explicitly. Use the canonical fields directly in a draft request. For an image draft:
Do not put an agent_url in this declaration. It is a legacy-format field. For common image requests, aspect_ratio is also accepted either beside format_kind or inside params; it is saved as canonical dimensions. For example, "9:16" becomes { "width": 1080, "height": 1920 }. Use explicit dimensions for a ratio that is not supported. A draft save rejects an unmappable ratio before it can be generated. An image draft that names neither dimensions nor an aspect ratio is planned as a square 1024 by 1024 image, and the saved plan’s params shows that size. Every funded image engine accepts it. A draft that names only a width or only a height keeps what it named, and its generation is refused until it names both. Drafts saved before this default existed keep their saved request and are refused the same way; save a new draft with a size to generate from them. When preparing image placement renders, the session uses each placement’s resolved dimensions. A placement without dimensions returns a warning instead of generating at the original image size. These renders still need the applicable seller compatibility checks before delivery. Session reads do not support include. Both reads require current access to the campaign and advertiser, and expired sessions are unavailable. save_creative_session saves a campaign or advertiser brief and locked references, selects or approves one exact output, or finalises that approved output. Saving does not start generation. generate_variants is the separate explicit action for one saved revision. To save an approved output into a reusable Creative Asset revision, call save_creative with fromCreativeSessionOutput. Reuse its actionKey only for an identical retry; name the parent output and feedback when refining. Both operations require the Creative Engines account capability; the service saves a compatible connection or funded binding with the draft. Generation can remain submitted or uncertain while its original task or receipt is recovered; it never silently submits a replacement request. A session runs one generation action at a time. To refine a variant after a generation, send variantAction: "feedback" with a new actionKey, the session’s current expectedRevision, the variant as parentVariantId and your feedback. The refined variant records its parent in parent_build_variant_id and has status refined. The parent becomes the session’s selected_variant_id, and the new variant its refined_variant_id. A refined Meta image post keeps its parent’s text and click-through URL; only the image is regenerated. A new action is refused while a variant of the previous action is still generating; poll with get and send it once that finishes. An actionKey the session has already used is refused, so a retry never buys the same work twice. The one exception is the session’s current action: repeating its call exactly, with the same expectedRevision, returns that action. Once a later action replaces it, its key is refused for the rest of the session; use a new key for new work. A session takes at most 256 generation actions; create a new session after that. Every save_creative_session request names its owner with exactly one of campaignId, for a campaign session, or advertiserId, for an advertiser Library session. The other fields say what the request saves: Each request makes one change: send exactly one of draft, selectedVariantId, approvedVariantId or finalization. To select an output and then approve it, make two requests, sending the expectedRevision the first response returns to the second. A request that sends more than one of them, or a field that belongs to a different change, is refused with an error naming the fields, and saves nothing. Each response includes the current session, revision, and, when present, sessionGeneration. A draft response also includes nextGenerateVariants: a copy-ready generate_variants call with the saved revision and session generation plus a fresh action key. Use that key for the first request and reuse it only if that same request needs a retry. Generation returns its actionId and each leaf’s status, task ID, and variant IDs. For every completed variant, completedVariants includes an asset URL, MIME type, preview and, when the completed asset reports them, its dimensions, so an MCP client can use the image without a second lookup. poll is returned only when a submitted leaf has a task ID. A leaf marked uncertain or not_dispatched is terminal for that action: it is not retried automatically. An uncertain leaf may already have incurred a provider charge. The response states this terminal condition and, when no leaf completed or was submitted, is an error result; create a new generation action after correcting the request instead of polling. A not_dispatched leaf was refused before any provider was contacted, so no provider charge occurred. When the refusal is one Apostra can name, the leaf carries a failureReason: creative_pre_provider_invalid_format when the requested format cannot be generated, for example an image with no size, or creative_pre_provider_invalid_request when another part of the request is invalid. When every leaf was refused for one of these reasons, the error message says so and says how to fix the request, for an image by setting a size or aspect ratio such as params.width and params.height. Without a failureReason, the message stays general. Approval and finalisation controls remain in the session. Session detail is bounded in these responses. When sessionTruncated: true is present, sessionOmitted identifies omitted detail, while the returned action and retry controls remain exact. The durable session history is not paginated by these operations; use the existing V2 creative-session workflow to retrieve the complete record. If already-persisted action controls alone cannot fit in one response, the operation returns a bounded recovery error instead of clipping those IDs. Read the durable session before retrying the same saved action; this does not create a replacement generation request.

Promote an approved output

Use save_creative with fromCreativeSessionOutput after the buyer has approved the exact session variant. Supply advertiserId (the Library that receives the asset), campaignId (the campaign that owns the session), an idempotencyKey, and fromCreativeSessionOutput with the sessionId, approved variantId, sessionRevision that recorded the approval, and the outputHash of the approved output. Send nothing else: this request saves the approved output on its own, and it does not attach anything to the campaign. The service resolves the approved rendition from the durable approval, so callers do not pass an internal rendition ID: the image for an image output, or the audio track for a voice or audio output. A companion image generated beside a voice track is not the approved deliverable and is not promoted in its place. The response has action: "promoted" and contains the Creative Asset ID, immutable revision ID, SHA-256 digest and approval receipt ID. Approved audio joins the advertiser’s Library through managed audio storage, the same inspection an uploaded WAV or MP3 file receives. Until that inspection finishes, the response has action: "promoting" and a processingState of quarantined, inspecting or approved; no Creative Asset exists yet. Repeat the same call with the same arguments, usually after about a minute, to receive the Creative Asset. A repeat never stores the audio twice. If storing the audio for inspection takes longer than 30 seconds, the call fails with a retryable SERVICE_UNAVAILABLE error; repeat the same call. If inspection rejects the audio, promotion fails and no Creative Asset, revision or receipt is created. Audio approved before this behaviour existed carries no audio evidence and is refused; approve the output again, then promote it. Repeat an uncertain request with the same key and the same input while the named approval is still current to receive the same receipt without creating another revision. Reusing a key with a different approved output or advertiser fails. The service checks the buyer’s current advertiser access before it saves the immutable evidence and rejects a stale, replaced or unapproved output. Promotion retains the approved bytes as an advertiser-owned Creative Asset. It does not finalise or create a campaign Creative, export the bytes, contact a publisher, launch a campaign or approve seller inventory. Finalising a Creative does not promote or export it. When a buyer promotes an approved output, the revision records where it came from: the Engine, the provider, and whether it ran on the buyer’s own provider account or the Scope3-funded preview. That record comes from the generation call that produced the output, so outputs generated before provenance was recorded can still be promoted but carry no provider record. Reuse rights follow that provider’s terms; Interchange does not verify them. Check the provider’s terms before using the asset outside Interchange. Its current inspection is strict JPEG/PNG container and active-content validation for images, and the managed WAV/MP3 container inspection for audio. It records container_validated for that work; no malware scan runs during promotion today, and clean is reserved for a scanner verdict. The service does not create immutable evidence when inspection cannot complete. Promotion uploads the deterministic private copy before its final database write, but it has no Creative Asset catalog entry until the current advertiser grant is checked and locked. If that check fails, no catalog asset, revision or approval receipt is created.

Generate an asset from the Creative Library

When Creative Engines is enabled for your Buyer Account, open an advertiser’s Creative Library, choose the Assets tab, then select Generate. Choose an image, video, or voice asset and enter a short brief. Apostra saves an advertiser-scoped Creative Session, starts generation, and opens the generated variants gallery. You do not choose an engine. The request uses the account’s existing engine-resolution support for its asset type; if it cannot start, it explains the required setup and does not create a Draft. Choose one completed output in the gallery and select Use selected asset. The chosen output is saved as a Library Draft for that advertiser. Review or discard the Draft in the Assets tab before using it elsewhere. Choosing an output does not attach it to a campaign or start another generation request.

Review generated variants in an MCP App host

When generate_variants returns a Creative Session with generated outputs, its MCP App result identifies the ui://agentic-api/variant-gallery/mcp-app.html resource. To show an existing session after search or get, call open_variant_gallery with its sessionId; the optional campaignId or advertiserId asserts the owner, but the operation resolves and checks the saved owner when omitted. This is the canonical gallery operation. Compatible hosts render the Variant gallery beside the conversation; hosts without MCP App support retain the normal text result and asset URLs. The checked gallery field contains the bounded session state the widget needs: variants, previews, the selected output, the current revision and the advertiser identity required to save an approved output. Each completed image variant is also checked against the exact saved brief. The gallery shows whether the rendered image passed, needs review, or missed the brief, with a short reason. A warning does not stop draft review. Ask to refine a flagged variant when the result identifies a missing requested object or an unrelated dominant object. A failed brief-match check blocks finalising that output. The check uses only the generated image and the saved brief; a temporary evaluator failure is shown as a warning for human review. Selecting a variant does not start a generation. Refinement is a separate, explicit paid action: enter feedback for a selected parent, then choose Refine selected. The gallery calls generate_variants with that parent and feedback and renders a cap-exhausted RATE_LIMITED error without retrying it. Save to library is also explicit. It selects and approves the chosen output, then saves it to the Library with the exact approval revision and output digest. That creates an advertiser-owned Creative Asset revision and returns its identity. A retry uses the same deterministic idempotency key, so it replays the saved result instead of creating another revision. While approved audio is still being inspected, the gallery says so and asks the buyer to choose Save to library again in a minute. The gallery confirms Saved to your Library. and offers the Creative Library link without exposing the returned identifiers. It records one bounded, best-effort completion activity; if that activity cannot be recorded, the saved state remains visible and the gallery does not retry it. Saving to the Library does not use the output in a campaign. Use in campaign is a separate, explicit action that finalises the same exact approved output as a campaign Creative. If promotion is refused because access, inspection or rights checks fail, or the approval is stale, the gallery shows the reason and keeps the approval available. It never auto-generates or auto-saves an alternative.