> ## Documentation Index
> Fetch the complete documentation index at: https://docs.apostra.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Creative Engines

> Discover Creative Engines, save a campaign or advertiser Library creative session, and explicitly generate or refine its variants through V3 MCP tools.

<Note>
  This alpha V3 MCP contract is available only to enrolled Buyer Accounts. It
  adds discovery, connection setup, campaign- and advertiser-scoped session
  reads, durable session saves, and explicit generation or refinement for
  registered Creative Engines. The Creative Engines Page is available for
  enrolled Buyer Accounts. Provider qualification and the end-to-end buyer
  journey remain separate work.
</Note>

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. When Creative Engines
is enabled but the draft has no connected engine, the composer says generation
needs a connected Creative Engine on the draft.

Your Apostra account team enables Creative Engines for enrolled Buyer Accounts.
Contact them to ask about enrollment.

An engine is a creative service you can discover and connect. A connection is your authorization
grant to that service. One engine can have several connections, each with its
own credential and provider accounts.

For Buyer Accounts enrolled in the Scope3-funded preview, Gemini, OpenAI,
fal.ai/FLUX, Veo and ElevenLabs are also available without setup and are labelled **Paid by
Scope3 (preview)**. 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. Veo requests also count against separate video limits of 3 per
enrolled account and 50 globally per UTC day; 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. An image draft
with no engine uses the Scope3-funded OpenAI image engine when eligible. A
voice draft with no engine uses Scope3-funded ElevenLabs only when ElevenLabs
is available in this preview and the buyer has no customer ElevenLabs or
AudioStack connection. Video drafts must explicitly select Veo. A customer-key
voice connection is never replaced with Scope3 funding, and a failed or missing
customer key never switches a request 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.

When an enrolled account uses the Scope3-funded image preview, omit `engine`
unless the buyer explicitly asks for a named 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.

## Open Creative Engines in Murph

In Murph, select **Creative Engines** in the Discover section of the Buyer
navigation. The entry is shown only when Creative Engines is enabled for the
active Buyer Account. It opens the same Page and does not grant access by
itself.

You can also ask Murph to find a registered provider and open its connection
setup on the Page; you start the secure connection there.

## 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.

```json theme={null}
{ "kind": "creative_engine", "limit": 20 }
```

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.

## Authorize and manage a connection

Use `open_creative_engines_page` to open the Creative Engines Page in an MCP
Apps host. The Page has Connected and Available views. It separates declared
capability from observed connection state and account access, and shows when no
provider price has been quoted. It supports secure connection repair, account
selection, advertiser mapping, and disconnect. It does not expose provider
credentials, accept an arbitrary MCP URL, quote a price, or start generation.

Pass `connectionAction: "connect"` with a registered `engineId` to focus that
engine's secure setup control. This opens no authorization handoff by itself:
the buyer starts setup from the Page.

Call `save_connection` with exactly one change. To begin authorization:

```json theme={null}
{
  "target": { "kind": "creative_engine", "id": "90" },
  "authorization": {}
}
```

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](https://platform.openai.com/api-keys). 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:

```json theme={null}
{ "kind": "connection", "filter": { "targetKind": "creative_engine" } }
```

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 an ElevenLabs 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,
finalisation or promotion of an exact approved output into a reusable Creative
Asset revision, but never starts generation. `generate_variants`
explicitly prepares and executes one saved session revision. These are
generation operations and require Creative Engines. Keep the chosen engine,
provider account and advertiser explicit when moving from setup into a session.
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](/v2/buyer/creatives/generative-creative).

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](/v2/buyer/creatives/generative-creative). 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](/v2/buyer/creatives/approval) and campaign launch.

## Existing seller integrations

`search({"kind":"connection"})` continues to list seller grants by default.
Seller grants gain `target: {kind: "seller", id: "..."}` and retain `sellerId`.
Existing `save_connection` calls using `sellerId` continue to work; new callers
can use a seller target instead. Supplying conflicting fields fails validation.

You can continue making creative directly with a provider and
[bring that creative into Apostra](/v2/buyer/creatives/bring-your-own-creative).
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.

List sessions within exactly one campaign or advertiser Library:

```json theme={null}
{ "kind": "creative_session", "filter": { "campaignId": "42" }, "limit": 25 }
```

For a Library session, use `filter.advertiserId` instead:

```json theme={null}
{ "kind": "creative_session", "filter": { "advertiserId": "42" }, "limit": 25 }
```

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:

```json theme={null}
{ "kind": "creative_session", "id": "cs_example" }
```

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.

```json theme={null}
{ "kind": "creative_session", "id": "cs_example", "advertiserId": "42" }
```

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
`engineId` and `connectionId`. Credential material is not included.
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.

Use the canonical fields directly in a draft request. For an image draft:

```json theme={null}
{
  "request": {
    "format_kind": "image",
    "params": { "width": 1080, "height": 1080 },
    "creative_brief": { "prompt": "A garden product photograph." }
  }
}
```

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 brief and locked references, selects
or approves one exact output, finalises that approved output, or promotes that
approved output into a reusable Creative Asset revision. Saving does not start
generation. `generate_variants` is the separate explicit action for
one saved revision. Reuse its `actionKey` only for an identical retry; name the
parent output and feedback when refining. Both operations require the Creative
Engines account capability and a saved engine connection. Generation can
remain submitted or uncertain while its original task or receipt is recovered;
it never silently submits a replacement request.

Both operation responses include the current `session`, `revision`, and, when
present, `sessionGeneration`. A `save_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_session` with `operation: "promote_approved_output"` after
the buyer has approved the exact session variant. Supply the campaign, session,
advertiser, approved variant, approval revision, output digest and an
idempotency key. The service resolves the approved inline rendition
from the durable approval, so callers do not pass an internal rendition ID.
The response contains the Creative Asset ID, immutable
revision ID, SHA-256 digest and approval receipt ID.

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. 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.

## 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 calls `promote_approved_output` 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.
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.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.