Skip to main content
POST
Start Design Task

Authorizations

Authorization
string
header
required

API key from Settings > Developer > REST API

Headers

Moda-Version
enum<string>
default:2026-05-01

Calendar-dated API version pin. New integrations should pin 2026-05-01 to opt into the newest response shapes. For back-compat the server also accepts requests with no header and resolves them to the current default (today: 2026-04-12); that default advances on each sunset date. Any unsupported value returns 400 unsupported_version.

Available options:
2026-04-12,
2026-05-01
Example:

"2026-05-01"

Body

application/json
prompt
string
required

Natural-language description of the design task for the AI agent.

user_request_quote
string | null

For an agent handing work to Moda's agent on a user's behalf: the user's own words naming Moda as the ACTOR ("have the Moda agent design it"), quoted verbatim. Recorded on the usage event so the delegation decision is auditable. Not validated and not interpreted — it grounds the decision, it does not gate it. Optional here (the app and existing API integrations start their own tasks and have no user to quote); the agent surfaces that expose delegation as a choice — moda task submit and the connector's task_delegate — require it.

conversation_id
string | null

Prefixed conv_ wire ID (Crockford base32 body) — the canonical, recommended form. For back-compat, a bare UUID string is also accepted in both path parameters and JSON request bodies (older integrations that stored raw UUIDs keep working), as is the prefix over a UUID body (conv_00000000-0000-4000-8000-000000000000). All three are permanent, supported inputs; only the canonical form is ever emitted.

Pattern: ^conv_[0-9A-HJKMNP-TV-Za-hjkmnp-tv-z]{26}$
Example:

"conv_01HT9WK8N3M2J4A5Z6P7Q8R9TV"

canvas_id
string | null

Prefixed cvs_ wire ID (Crockford base32 body) — the canonical, recommended form. For back-compat, a bare UUID string is also accepted in both path parameters and JSON request bodies (older integrations that stored raw UUIDs keep working), as is the prefix over a UUID body (cvs_00000000-0000-4000-8000-000000000000). All three are permanent, supported inputs; only the canonical form is ever emitted.

Pattern: ^cvs_[0-9A-HJKMNP-TV-Za-hjkmnp-tv-z]{26}$
Example:

"cvs_01HT9WK8N3M2J4A5Z6P7Q8R9TV"

template_canvas_id
string | null

Prefixed cvs_ wire ID (Crockford base32 body) — the canonical, recommended form. For back-compat, a bare UUID string is also accepted in both path parameters and JSON request bodies (older integrations that stored raw UUIDs keep working), as is the prefix over a UUID body (cvs_00000000-0000-4000-8000-000000000000). All three are permanent, supported inputs; only the canonical form is ever emitted.

Pattern: ^cvs_[0-9A-HJKMNP-TV-Za-hjkmnp-tv-z]{26}$
Example:

"cvs_01HT9WK8N3M2J4A5Z6P7Q8R9TV"

canvas_name
string | null

Name for the new canvas. Used when creating (canvas_id omitted) or when remixing via template_canvas_id (overrides the default Remix of <source>).

brand_kit_id
string | null

Prefixed bk_ wire ID (Crockford base32 body) — the canonical, recommended form. For back-compat, a bare UUID string is also accepted in both path parameters and JSON request bodies (older integrations that stored raw UUIDs keep working), as is the prefix over a UUID body (bk_00000000-0000-4000-8000-000000000000). All three are permanent, supported inputs; only the canonical form is ever emitted.

Pattern: ^bk_[0-9A-HJKMNP-TV-Za-hjkmnp-tv-z]{26}$
Example:

"bk_01HT9WK8N3M2J4A5Z6P7Q8R9TV"

skip_brand_kit
boolean
default:false

If true, no brand kit is applied — every brand-kit source is suppressed, including the canvas's own kit, the team default, and any explicit brand_kit_id override. Use only when the design must be unbranded; to merely leave the canvas's existing kit alone, omit brand_kit_id instead.

callback_url
string | null

HTTPS URL to receive a webhook POST when the job completes, fails, or is cancelled. See the Webhooks documentation for payload format and signature verification.

idempotency_key
string | null

Client-generated unique key to prevent duplicate job creation. If a job with this key already exists, its status is returned instead of creating a new one.

attachments
(AttachmentInput · object | FileAttachment · object)[] | null

List of reference images or files for the AI agent to use as inspiration. Each item is either a URL-shape attachment ({url, name?, type?}) or a file-id-shape attachment ({file_id, role, label?}) referencing a file previously uploaded via POST /v1/uploads. The two shapes are distinguished by their required fields (url vs file_id).

format
FormatInput · object | null

Canvas format and dimensions. Controls the output size and layout type (e.g. slides, social media, custom).

model_tier
enum<string> | null

AI model tier: 'pro' (best for complex tasks), 'pro-fast' (the same quality as Pro with faster output and higher credit usage), 'fable-5.1' (Claude Fable 5.1 at low effort; premium plans only), 'standard', 'lite', 'kimi-k2.5' (Fireworks-hosted Kimi K2.5), 'kimi-k2.6' (Fireworks-hosted Kimi K2.6), 'kimi-k3' (Moonshot-hosted Kimi K3), or 'gpt-5.6' (OpenAI GPT-5.6 at high reasoning). Defaults to automatic selection based on task complexity.

Available options:
pro,
pro-fast,
fable-5.1,
standard,
lite,
kimi-k2.5,
kimi-k2.6,
kimi-k3,
gpt-5.6
reference_canvas_ids
string[] | null

List of prefixed cvs_ IDs to use as design inspiration. The agent can see these designs and reference their style, layout, or content.

Prefixed cvs_ wire ID (Crockford base32 body) — the canonical, recommended form. For back-compat, a bare UUID string is also accepted in both path parameters and JSON request bodies (older integrations that stored raw UUIDs keep working), as is the prefix over a UUID body (cvs_00000000-0000-4000-8000-000000000000). All three are permanent, supported inputs; only the canonical form is ever emitted.

Pattern: ^cvs_[0-9A-HJKMNP-TV-Za-hjkmnp-tv-z]{26}$
number_of_slides
integer | null

Optional maximum number of slides for slide-generation jobs. When omitted for slides, Moda defaults to an 8-slide target and clamps to your plan limit. Rejected with a role='import' attachment — an existing-deck edit keeps the deck's own slide count.

Required range: x >= 1
export_on_complete
ExportOnCompleteOption · object | null

Auto-export preferences applied when the task finishes. The finished design is rendered to result.export (and the completion webhook), so a follow-up POST /v1/canvases/{id}/export for the same canvas hits the cache instead of re-rendering. Omit to use the canvas category default (slides→PPTX, pdf→PDF, others→PNG); pass {enabled: false} to opt out of the auto-export entirely. Multi-page PNG/JPEG bundles into a .zip of per-page files; result.export.format reflects what was actually delivered (png, jpeg, pdf, pptx, or zip).

Response

Successful Response

Canonical wire-format for every async design operation.

All consumers -- REST, webhooks, SSE, MCP -- serialize through Task.from_db() so the shape is always consistent.

id
string
required

Prefixed task_... identifier.

Pattern: ^task_[0-9A-HJKMNP-TV-Za-hjkmnp-tv-z]{26}$
Example:

"task_01HT9WK8N3M2J4A5Z6P7Q8R9TV"

kind
enum<string>
required

Discriminator for the kind-specific result payload.

Available options:
design,
export,
remix,
brand_kit_extract,
layerize_assets
status
enum<string>
required

Current lifecycle status.

Available options:
queued,
running,
succeeded,
failed,
canceled,
expired
attempt
integer
required

Current attempt number (1-based).

max_attempts
integer
required

Maximum attempts before dead-lettering.

attempts_started
integer
required

Number of attempts STARTED (claimed by a worker) — never attempts completed. 0 means the task has never been claimed. The claim itself increments the counter, so a task on its first attempt reports 1 while RUNNING and stays at 1 through that attempt's retry backoff. The retry signal is therefore status == "queued" && attempts_started >= 1 (a queued task that has already burned an attempt), NOT >= 2. Unlike attempt, this is the raw counter and is not floored to 1.

HATEOAS links for this task.

created_at
string | null

ISO 8601 timestamp.

started_at
string | null

ISO 8601 timestamp.

completed_at
string | null

ISO 8601 timestamp.

progress
TaskProgress · object | null

Live progress for running tasks. Null when not applicable.

first_started_at
string | null

ISO 8601 timestamp of when the FIRST attempt was claimed. null means unknown — either the task has never started, or it predates this field being recorded. started_at remains the CURRENT attempt's start, so on a retried task the two differ and the gap is the real wall-clock age of the work.

input
Input · object | null

Sanitized echo of the original request.

result
TaskResult · object

Result payload of a design or remix task.

Populated when status is succeeded, and partially populated for some in-flight tasks (a remix surfaces its source canvas before the design task finishes). Extra keys are permitted so synchronous-completion payloads pass through without schema churn.

error
Error · object | null

Error info: {message, retryable, attempt}. Present for failed tasks, and also for a NON-terminal task that carries an error from an earlier attempt — on a non-terminal task this always describes the PREVIOUS, already-dead attempt, never the one currently in flight. attempt is the attempts_started value the error is tied to (0 when the failure happened before any claim).

credits
CreditUsage · object | null

Credit usage. Present only for completed tasks when billing is enabled.

retry_after_ms
integer | null

Suggested milliseconds to wait before the next poll. Null for terminal tasks.