Skip to content
Talk to the Website Director
  1. Docs
  2. Reference
  3. Studio

Studio

Make and edit websites, documents, apps, images and video by talking to the same Studio director the product uses. Each message is a turn.

Talk to the Website Director — build or change a website#

POST/v1/studio/website/turns
API key May take minutes — stream or backgroundstudio_website_turn

One message to Website Studio's director, the same turn the app runs. Without artifact_id it starts a new website: when the request is clear (or auto: true) the director writes the creation brief, the site is created, and its build is queued — the answer comes back in a few seconds with status: "building", the new artifact.id and a job. The site itself builds in the background in 2–5 minutes; poll GET /v1/websites/{id} (or GET /v1/turns/{id}) until status is completed, then public_url is where it lives once published.

If the director needs something first (what you sell, who it's for) it answers needs_input with questions; reply with another turn carrying the same conversation_id, or send auto: true to let it decide.

With artifact_id (a website's id) it changes that site: the Page Editor makes the edit (20–90 s) and a rebuild is queued (status: "building", 1–3 min). A question about the site is simply answered (completed).

Example: { "message": "Build a landing page for Harbor Dental, a family dentist in Portland. Goal: book a first cleaning.", "auto": true }

The answer (also what GET /v1/turns/{id} returns):

field
idThe turn. Poll it with GET /v1/turns/{id}.
statuscompleted · needs_input (answer questions/outline with another turn, same conversation_id or artifact_id) · building (still working — poll) · failed (see error).
artifact{ id, type, name, url, public_url } — url opens it in Attria; public_url is set once it is public.
conversation_idThe director conversation this turn belongs to.
messageThe director's own words.
questions / outlineWhat it needs from you when status is needs_input.

Send an Idempotency-Key header: a retry with the same key replays the turn instead of running (and charging) it twice. Once a turn has been claimed, a failure is answered as the turn with status: "failed" and an error; refusals before that (not found, no credits) are ordinary HTTP errors.

Slow: can take several minutes. Agents should send background: true and poll GET /v1/turns/{id} (tool studio_turn_get).

auto: true lets Attria decide instead of answering with status: "needs_input" (questions or an outline to confirm).

stream: true answers with Server-Sent Events; the last event is result (the same body a waiting call returns) or error.

background: true answers 202 Accepted at once with an id; poll GET /v1/turns/{id} (tool studio_turn_get) every 5–10 s until it finishes.

Send an Idempotency-Key header: a retry with the same key replays the first result instead of doing the work twice.

Headers

  • Idempotency-Keystringoptional

    Any unique string (a UUID) per logical write. Retrying with the same key replays the original result.

Bodyapplication/json

  • messagestringrequired

    What you would type to this Studio's director, in plain words. Answers to its questions go here too.

    max length 3800
  • artifact_idstring · uuidoptional

    Work on an existing artifact of this Studio (from a previous answer's artifact.id or a list endpoint). Omit to start a new one.

  • conversation_idstring · uuidoptional

    Continue a conversation: the conversation_id of a previous answer. Needed to answer a website director's questions before the site exists; otherwise artifact_id already implies it.

  • autobooleanoptional

    "Decide for me": the director settles anything unclear itself and makes the artifact now instead of asking. Default false — the director may answer needs_input with questions or an outline, exactly as in the app.

    Default false
  • streambooleanoptional

    Answer as server-sent events: turn, plan, status, then result (the same body a waited-for call returns).

    Default false
  • backgroundbooleanoptional

    Answer 202 as soon as the turn is claimed and keep working; poll GET /v1/turns/{id}.

    Default false

Can fail with 400 · 401 · 402 · 404 · 409 · 429 · 500 — the shape is in Errors & limits.

POST
curl -X POST "https://app.attria.io/api/v1/studio/website/turns" \
  -H "Authorization: Bearer $ATTRIA_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{
    "message": "Build a landing page for Harbor Dental, a family dentist in Portland. Goal: book a first cleaning.",
    "auto": true
  }'
Response200
{
  "id": "5b7e…",
  "object": "studio.turn",
  "status": "building",
  "studio": "website",
  "artifact": {
    "id": "0c1d…",
    "type": "website",
    "name": "Harbor Dental",
    "url": "https://app.attria.io/studio/websites/0c1d…",
    "public_url": null
  },
  "conversation_id": "9f2a…",
  "message": "The website is building. It usually takes 2–5 minutes.",
  "job": {
    "id": "77aa…",
    "status": "queued",
    "stage": "generate",
    "error": null
  },
  "created_at": "2026-09-27T18:02:11Z",
  "completed_at": "2026-09-27T18:02:14Z"
}

Talk to the Documents director — write or change a deck, proposal or document#

POST/v1/studio/document/turns
API key May take minutes — stream or backgroundstudio_document_turn

One message to Documents Studio's director — decks, proposals, résumés, invoices, one-pagers, reports — the same turn the app runs. Without artifact_id it opens a new document and writes it; with one it revises that document — a section, the look, or the whole thing. The director designs it and may add images. Usually 20–60 s, longer for long decks.

By default the director may first propose an outline or ask questions (status: "needs_input"). Reply "Build it" (or any go-ahead, or auto: true) to approve an outline, or answer the questions in another turn with the same artifact_id. auto: true skips all of that and writes immediately.

Put every fact, figure, name and date the document needs in message — the director uses only what you give it and the workspace's brand. Read the result with GET /v1/documents/{id}.

Example: { "message": "A 6-slide investor update for Q3: revenue $412k (+38% QoQ), 3 enterprise logos signed, runway 22 months, hiring 2 engineers.", "auto": true }

The answer (also what GET /v1/turns/{id} returns):

field
idThe turn. Poll it with GET /v1/turns/{id}.
statuscompleted · needs_input (answer questions/outline with another turn, same conversation_id or artifact_id) · building (still working — poll) · failed (see error).
artifact{ id, type, name, url, public_url } — url opens it in Attria; public_url is set once it is public.
conversation_idThe director conversation this turn belongs to.
messageThe director's own words.
questions / outlineWhat it needs from you when status is needs_input.

Send an Idempotency-Key header: a retry with the same key replays the turn instead of running (and charging) it twice. Once a turn has been claimed, a failure is answered as the turn with status: "failed" and an error; refusals before that (not found, no credits) are ordinary HTTP errors.

Slow: can take several minutes. Agents should send background: true and poll GET /v1/turns/{id} (tool studio_turn_get).

auto: true lets Attria decide instead of answering with status: "needs_input" (questions or an outline to confirm).

stream: true answers with Server-Sent Events; the last event is result (the same body a waiting call returns) or error.

background: true answers 202 Accepted at once with an id; poll GET /v1/turns/{id} (tool studio_turn_get) every 5–10 s until it finishes.

Send an Idempotency-Key header: a retry with the same key replays the first result instead of doing the work twice.

Headers

  • Idempotency-Keystringoptional

    Any unique string (a UUID) per logical write. Retrying with the same key replays the original result.

Bodyapplication/json

  • messagestringrequired

    What you would type to this Studio's director, in plain words. Answers to its questions go here too.

    max length 18000
  • artifact_idstring · uuidoptional

    Work on an existing artifact of this Studio (from a previous answer's artifact.id or a list endpoint). Omit to start a new one.

  • conversation_idstring · uuidoptional

    Continue a conversation: the conversation_id of a previous answer. Needed to answer a website director's questions before the site exists; otherwise artifact_id already implies it.

  • autobooleanoptional

    "Decide for me": the director settles anything unclear itself and makes the artifact now instead of asking. Default false — the director may answer needs_input with questions or an outline, exactly as in the app.

    Default false
  • streambooleanoptional

    Answer as server-sent events: turn, plan, status, then result (the same body a waited-for call returns).

    Default false
  • backgroundbooleanoptional

    Answer 202 as soon as the turn is claimed and keep working; poll GET /v1/turns/{id}.

    Default false

Can fail with 400 · 401 · 402 · 404 · 409 · 429 · 500 — the shape is in Errors & limits.

POST
curl -X POST "https://app.attria.io/api/v1/studio/document/turns" \
  -H "Authorization: Bearer $ATTRIA_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{
    "message": "A 6-slide investor update for Q3: revenue $412k (+38% QoQ), 3 enterprise logos signed, runway 22 months, hiring 2 engineers.",
    "auto": false
  }'
Response200
{
  "id": "1e0f…",
  "object": "studio.turn",
  "status": "needs_input",
  "studio": "document",
  "artifact": {
    "id": "a3c2…",
    "type": "document",
    "name": "Untitled",
    "url": "https://app.attria.io/studio/documents/a3c2…",
    "public_url": null
  },
  "conversation_id": "c81b…",
  "message": "One quick question before I write this.",
  "questions": [
    {
      "text": "Who is this deck for?",
      "options": [
        "Investors",
        "Customers",
        "My team",
        "Custom"
      ]
    }
  ],
  "created_at": "2026-09-27T18:02:11Z",
  "completed_at": "2026-09-27T18:02:19Z"
}

Talk to the App Builder — build or change a workspace app#

POST/v1/studio/app/turns
API key May take minutes — stream or backgroundstudio_app_turn

One message to Apps Studio's builder, the same turn the app runs. Without artifact_id it builds a new app on the workspace's own records (Objects) — screens, the data they read and write, and any Actions — compiles it and commits it; an app that has never been live is published so it appears in the workspace's Apps. With artifact_id it changes that app; a change to a live app stays a draft until someone publishes it in Studio. Usually 45–120 s.

Say what the app is for, who uses it, what it shows and what people do in it. The builder may ask questions (needs_input); auto: true makes it decide and build.

Example: { "message": "A job tracker for our crew: list open jobs by date, mark a job done, and add notes and photos to a job.", "auto": true }

The answer (also what GET /v1/turns/{id} returns):

field
idThe turn. Poll it with GET /v1/turns/{id}.
statuscompleted · needs_input (answer questions/outline with another turn, same conversation_id or artifact_id) · building (still working — poll) · failed (see error).
artifact{ id, type, name, url, public_url } — url opens it in Attria; public_url is set once it is public.
conversation_idThe director conversation this turn belongs to.
messageThe director's own words.
questions / outlineWhat it needs from you when status is needs_input.

Send an Idempotency-Key header: a retry with the same key replays the turn instead of running (and charging) it twice. Once a turn has been claimed, a failure is answered as the turn with status: "failed" and an error; refusals before that (not found, no credits) are ordinary HTTP errors.

Slow: can take several minutes. Agents should send background: true and poll GET /v1/turns/{id} (tool studio_turn_get).

auto: true lets Attria decide instead of answering with status: "needs_input" (questions or an outline to confirm).

stream: true answers with Server-Sent Events; the last event is result (the same body a waiting call returns) or error.

background: true answers 202 Accepted at once with an id; poll GET /v1/turns/{id} (tool studio_turn_get) every 5–10 s until it finishes.

Send an Idempotency-Key header: a retry with the same key replays the first result instead of doing the work twice.

Headers

  • Idempotency-Keystringoptional

    Any unique string (a UUID) per logical write. Retrying with the same key replays the original result.

Bodyapplication/json

  • messagestringrequired

    What you would type to this Studio's director, in plain words. Answers to its questions go here too.

    max length 18000
  • artifact_idstring · uuidoptional

    Work on an existing artifact of this Studio (from a previous answer's artifact.id or a list endpoint). Omit to start a new one.

  • conversation_idstring · uuidoptional

    Continue a conversation: the conversation_id of a previous answer. Needed to answer a website director's questions before the site exists; otherwise artifact_id already implies it.

  • autobooleanoptional

    "Decide for me": the director settles anything unclear itself and makes the artifact now instead of asking. Default false — the director may answer needs_input with questions or an outline, exactly as in the app.

    Default false
  • streambooleanoptional

    Answer as server-sent events: turn, plan, status, then result (the same body a waited-for call returns).

    Default false
  • backgroundbooleanoptional

    Answer 202 as soon as the turn is claimed and keep working; poll GET /v1/turns/{id}.

    Default false

Can fail with 400 · 401 · 402 · 404 · 409 · 429 · 500 — the shape is in Errors & limits.

POST
curl -X POST "https://app.attria.io/api/v1/studio/app/turns" \
  -H "Authorization: Bearer $ATTRIA_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{
    "message": "A job tracker for our crew: list open jobs by date, mark a job done, and add notes to a job.",
    "auto": true
  }'
Response200
{
  "id": "d4b1…",
  "object": "studio.turn",
  "status": "completed",
  "studio": "app",
  "artifact": {
    "id": "6e2f…",
    "type": "app",
    "name": "Job Tracker",
    "url": "https://app.attria.io/studio/apps/6e2f…",
    "public_url": "https://app.attria.io/apps/6e2f…"
  },
  "conversation_id": "0a9d…",
  "message": "Built a job tracker with an open-jobs list, a done toggle and notes.",
  "created_at": "2026-09-27T18:02:11Z",
  "completed_at": "2026-09-27T18:03:20Z"
}

Talk to the Images director — make images on a board#

POST/v1/studio/image/turns
API key May take minutes — stream or backgroundstudio_image_turn

One message to Images Studio's director, the same turn the app runs. Without artifact_id it opens a new board; with one (a board id from GET /v1/images/boards) it works on that board. When the director decides to make something it renders with the Studio's own pipeline (brand-aware planning, model routing, storage, metering) and the answer carries the finished images with their URLs. Usually 20–60 s. A question or chat is simply answered.

The director may ask questions (needs_input); auto: true makes it decide. Images are made at 4:5 by default — say another size or how many (1–4) in the message. For a precise operation (edit, remove background, reframe, upscale, product photo…) use POST /v1/studio/image/apps/{app} instead.

Example: { "message": "Two scroll-stopping images for a summer iced-latte promo, bright and minimal", "auto": true }

The answer (also what GET /v1/turns/{id} returns):

field
idThe turn. Poll it with GET /v1/turns/{id}.
statuscompleted · needs_input (answer questions/outline with another turn, same conversation_id or artifact_id) · building (still working — poll) · failed (see error).
artifact{ id, type, name, url, public_url } — url opens it in Attria; public_url is set once it is public.
conversation_idThe director conversation this turn belongs to.
messageThe director's own words.
questions / outlineWhat it needs from you when status is needs_input.

Send an Idempotency-Key header: a retry with the same key replays the turn instead of running (and charging) it twice. Once a turn has been claimed, a failure is answered as the turn with status: "failed" and an error; refusals before that (not found, no credits) are ordinary HTTP errors.

Slow: can take several minutes. Agents should send background: true and poll GET /v1/turns/{id} (tool studio_turn_get).

auto: true lets Attria decide instead of answering with status: "needs_input" (questions or an outline to confirm).

stream: true answers with Server-Sent Events; the last event is result (the same body a waiting call returns) or error.

background: true answers 202 Accepted at once with an id; poll GET /v1/turns/{id} (tool studio_turn_get) every 5–10 s until it finishes.

Send an Idempotency-Key header: a retry with the same key replays the first result instead of doing the work twice.

Headers

  • Idempotency-Keystringoptional

    Any unique string (a UUID) per logical write. Retrying with the same key replays the original result.

Bodyapplication/json

  • messagestringrequired

    What you would type to this Studio's director, in plain words. Answers to its questions go here too.

    max length 3800
  • artifact_idstring · uuidoptional

    Work on an existing artifact of this Studio (from a previous answer's artifact.id or a list endpoint). Omit to start a new one.

  • conversation_idstring · uuidoptional

    Continue a conversation: the conversation_id of a previous answer. Needed to answer a website director's questions before the site exists; otherwise artifact_id already implies it.

  • autobooleanoptional

    "Decide for me": the director settles anything unclear itself and makes the artifact now instead of asking. Default false — the director may answer needs_input with questions or an outline, exactly as in the app.

    Default false
  • streambooleanoptional

    Answer as server-sent events: turn, plan, status, then result (the same body a waited-for call returns).

    Default false
  • backgroundbooleanoptional

    Answer 202 as soon as the turn is claimed and keep working; poll GET /v1/turns/{id}.

    Default false

Can fail with 400 · 401 · 402 · 404 · 409 · 429 · 500 — the shape is in Errors & limits.

POST
curl -X POST "https://app.attria.io/api/v1/studio/image/turns" \
  -H "Authorization: Bearer $ATTRIA_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{
    "message": "Two scroll-stopping images for a summer iced-latte promo, bright and minimal",
    "auto": true
  }'
Response200
{
  "id": "8c3e…",
  "object": "studio.turn",
  "status": "completed",
  "studio": "image",
  "artifact": {
    "id": "b1f0…",
    "type": "image",
    "name": "Untitled board",
    "url": "https://app.attria.io/studio/images/b1f0…",
    "public_url": null
  },
  "conversation_id": "57de…",
  "message": "Making two bright, minimal iced-latte promos.",
  "images": [
    {
      "id": "e9a1…",
      "url": "https://…/creative-assets/…png",
      "media_type": "image",
      "mime_type": "image/png",
      "width": 1080,
      "height": 1350,
      "duration_seconds": null,
      "prompt": "…",
      "board_id": "b1f0…",
      "created_at": "2026-09-27T18:02:40Z"
    }
  ],
  "created_at": "2026-09-27T18:02:11Z",
  "completed_at": "2026-09-27T18:02:15Z"
}

Talk to the Video director — edit a video project#

POST/v1/studio/video/turns
API key May take minutes — stream or backgroundstudio_video_turn

One message to Video Studio's director, the same turn the app runs: it edits a video project — trims, reorders, captions, titles, overlays, music placement — and the edits are applied and saved. Without artifact_id a new, empty vertical project is opened (the director can plan shots but there is no footage to edit yet). Usually 10–40 s.

Things the app would ask a person to confirm and pay for — filming an AI shot, a motion graphic, captions, finding clips — come back in video.pending_requests and are not run by this call; make them with POST /v1/studio/video/apps/{app}.

Example: { "artifact_id": "…", "message": "Tighten the intro to 3 seconds and add a title card that says 'Summer Sale'" }

The answer (also what GET /v1/turns/{id} returns):

field
idThe turn. Poll it with GET /v1/turns/{id}.
statuscompleted · needs_input (answer questions/outline with another turn, same conversation_id or artifact_id) · building (still working — poll) · failed (see error).
artifact{ id, type, name, url, public_url } — url opens it in Attria; public_url is set once it is public.
conversation_idThe director conversation this turn belongs to.
messageThe director's own words.
questions / outlineWhat it needs from you when status is needs_input.

Send an Idempotency-Key header: a retry with the same key replays the turn instead of running (and charging) it twice. Once a turn has been claimed, a failure is answered as the turn with status: "failed" and an error; refusals before that (not found, no credits) are ordinary HTTP errors.

Slow: can take several minutes. Agents should send background: true and poll GET /v1/turns/{id} (tool studio_turn_get).

auto: true lets Attria decide instead of answering with status: "needs_input" (questions or an outline to confirm).

stream: true answers with Server-Sent Events; the last event is result (the same body a waiting call returns) or error.

background: true answers 202 Accepted at once with an id; poll GET /v1/turns/{id} (tool studio_turn_get) every 5–10 s until it finishes.

Send an Idempotency-Key header: a retry with the same key replays the first result instead of doing the work twice.

Headers

  • Idempotency-Keystringoptional

    Any unique string (a UUID) per logical write. Retrying with the same key replays the original result.

Bodyapplication/json

  • messagestringrequired

    What you would type to this Studio's director, in plain words. Answers to its questions go here too.

    max length 3800
  • artifact_idstring · uuidoptional

    Work on an existing artifact of this Studio (from a previous answer's artifact.id or a list endpoint). Omit to start a new one.

  • conversation_idstring · uuidoptional

    Continue a conversation: the conversation_id of a previous answer. Needed to answer a website director's questions before the site exists; otherwise artifact_id already implies it.

  • autobooleanoptional

    "Decide for me": the director settles anything unclear itself and makes the artifact now instead of asking. Default false — the director may answer needs_input with questions or an outline, exactly as in the app.

    Default false
  • streambooleanoptional

    Answer as server-sent events: turn, plan, status, then result (the same body a waited-for call returns).

    Default false
  • backgroundbooleanoptional

    Answer 202 as soon as the turn is claimed and keep working; poll GET /v1/turns/{id}.

    Default false

Can fail with 400 · 401 · 402 · 404 · 409 · 429 · 500 — the shape is in Errors & limits.

POST
curl -X POST "https://app.attria.io/api/v1/studio/video/turns" \
  -H "Authorization: Bearer $ATTRIA_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{
    "artifact_id": "5b7e2c8e-1f0a-4c3d-9e8b-7a6f5d4c3b2a",
    "message": "Tighten the intro to 3 seconds and add a title card that says '\''Summer Sale'\''"
  }'
Response200
{
  "id": "f0e1…",
  "object": "studio.turn",
  "status": "completed",
  "studio": "video",
  "artifact": {
    "id": "2d4c…",
    "type": "video",
    "name": "Summer promo",
    "url": "https://app.attria.io/studio/video/2d4c…",
    "public_url": null
  },
  "conversation_id": "11ab…",
  "message": "Trimmed the intro to 3 seconds and added a 'Summer Sale' title card.",
  "video": {
    "operations_applied": 2,
    "operations_skipped": [],
    "pending_requests": []
  },
  "created_at": "2026-09-27T18:02:11Z",
  "completed_at": "2026-09-27T18:02:30Z"
}

Get a Studio turn#

GET/v1/turns/{id}
API keystudio_turn_get

The current state of a Studio turn — one started with background: true, or any earlier one. Same body as the turn's own answer. Poll it (every few seconds) while status is building; it ends as completed, needs_input or failed. For a new website, building lasts through the site's build (2–5 min) and job shows the stage.

Example: GET /v1/turns/5b7e2c8e-…

Path parameters

  • idstringrequired

Can fail with 400 · 401 · 404 · 429 · 500 — the shape is in Errors & limits.

GET
curl "https://app.attria.io/api/v1/turns/5b7e2c8e-1f0a-4c3d-9e8b-7a6f5d4c3b2a" \
  -H "Authorization: Bearer $ATTRIA_API_KEY"
Response200
{
  "id": "5b7e…",
  "object": "studio.turn",
  "status": "completed",
  "studio": "website",
  "artifact": {
    "id": "0c1d…",
    "type": "website",
    "name": "Harbor Dental",
    "url": "https://app.attria.io/studio/websites/0c1d…",
    "public_url": null
  },
  "conversation_id": "9f2a…",
  "message": "The website is built.",
  "job": {
    "id": "77aa…",
    "status": "succeeded",
    "stage": "complete",
    "error": null
  },
  "created_at": "2026-09-27T18:02:11Z",
  "completed_at": "2026-09-27T18:02:14Z"
}

List the Studio's Content Apps#

GET/v1/studio/apps
API keystudio_apps_list

Every Content App in the Image and Video Studios — the same catalog as the Studio's Add menu — with what each one needs and whether it can be run over the API.

Use it to discover apps before calling POST /v1/studio/{studio}/apps/{app}. For each app you get its studio, id, label, description, examples, group and kind; runnable (and not_runnable_reason when it is false); what a run returns (assets, job, motion); its typical timing; and inputs, a JSON Schema of the request body that app accepts.

Free and instant.

Query parameters

  • studiostringoptional

    Only this studio's apps.

    "image""video"

Can fail with 400 · 401 · 404 · 429 · 500 — the shape is in Errors & limits.

GET
curl "https://app.attria.io/api/v1/studio/apps" \
  -H "Authorization: Bearer $ATTRIA_API_KEY"
Response200
{
  "apps": [
    {
      "studio": "image",
      "id": "remove-background",
      "label": "Remove background",
      "short_label": "Remove background",
      "description": "Create a clean transparent version of the selected image.",
      "examples": [
        "Transparent PNG",
        "Clean edges"
      ],
      "group": "finish",
      "kind": "utility",
      "path": "/v1/studio/image/apps/remove-background",
      "runnable": true,
      "not_runnable_reason": null,
      "returns": "assets",
      "timing": "20–60 s",
      "inputs": {
        "type": "object",
        "properties": {
          "board_id": {
            "type": "string",
            "format": "uuid"
          },
          "source_asset_id": {
            "type": "string",
            "format": "uuid"
          }
        },
        "required": [
          "board_id",
          "source_asset_id"
        ]
      }
    }
  ]
}

Run a Studio Content App#

POST/v1/studio/{studio}/apps/{app}
API key May take minutes — stream or backgroundstudio_app_run

Runs one Content App — the same render, model routing, storage and credit metering as the app's form in the Studio. List the apps and each one's exact inputs with GET /v1/studio/apps; send only the fields that app takes (others are rejected).

Image apps (/v1/studio/image/apps/{app}: generate, product-photo, ad-creative, edit, compose, variations, remove-background, reframe, upscale) answer when the images are saved — usually 20–90 seconds — with assets (id, url, width, height, …). Without board_id results go to the Library; apps that start from an image need board_id, and every source or reference asset must already be on that board. count defaults to 1.

Video apps (/v1/studio/video/apps/{app}: generate, product-ad, ugc-ad, recast, remake, avatar) film inside a video project (project_id). They answer in seconds with status: "building" (HTTP 202) and a job; the shot takes about 1–3 minutes. To check on it, repeat the same request with the same Idempotency-Key: the repeat reads the job and moves it forward, never starting or charging a second one. When status is complete, asset is the video. The shot is also added to the end of the project's video. generate without project_id instead makes one 8-second Library shot from prompt and answers when it is done (1–2 minutes).

Motion (/v1/studio/video/apps/motion) generates a designed animation as an editable Remotion composition, inside the request (1–4 minutes). status may be needs_input with motion.questions when the brief is ambiguous; send a more specific prompt.

Apps with runnable: false in the list (e.g. reference, camera-path, story, clips, music, sound-effect) answer 422 with the reason. Credits are reserved before a run and only what was made is charged; not enough credits is 402. Send an Idempotency-Key so a retry is charged once.

Example — POST /v1/studio/image/apps/product-photo:

JSON
{ "board_id": "6f1c…", "product_asset_id": "9a2e…", "product": "A matte black insulated travel mug", "direction": "Dawn café, soft window light, condensation detail", "aspect": "4:5" }

Example — POST /v1/studio/video/apps/generate:

JSON
{ "project_id": "c41d…", "prompt": "A close handheld shot of a runner tying bright red shoes before sunrise", "model": "standard", "seconds": 6 }

Slow: can take several minutes; keep the connection open (the server allows up to 800 s).

Send an Idempotency-Key header: a retry with the same key replays the first result instead of doing the work twice.

Path parameters

  • studiostringrequired
    "image""video"
  • appstringrequired

Headers

  • Idempotency-Keystringoptional

    Any unique string (a UUID) per logical write. Retrying with the same key replays the original result.

Bodyapplication/json

  • board_idstring · uuidoptional

    Image board to work on. Omit it and results are saved to the Library. Required whenever the app uses a source or reference image: those images must already be on this board.

  • project_idstring · uuidoptional

    Video project (from the Video Studio) the shot belongs to. The finished shot is added to the end of that video the next time it is opened.

  • promptstringoptional

    What to make or change, in plain language.

    max length 6000
  • directionstringoptional

    Optional extra direction.

    max length 2000
  • aspectstringoptional

    Output aspect ratio.

    "4:5""1:1""16:9""9:16""4:3""3:4""21:9"
  • countintegeroptional

    How many results to make (1–4). Each result is charged.

    min 1max 4
  • stylestringoptional

    Visual style.

    "none""cinematic""anime""photorealistic""digital-art""oil-painting""watercolor""3d-render"
  • formatstringoptional

    Creative format (ad structure). auto lets Attria choose.

    "auto""product""lifestyle""testimonial""comparison""offer""problem-solution""demo""founder""listicle""native""before-after""meme""zero-star-review""notes-app""apology-letter""text-message""social-comment""receipt""statistic""press"
  • modelstringoptional

    Model. Image apps: an image model id (auto = Attria chooses). Video Generate: a shot tier.

    "auto""gemini-3-pro-image""gemini-3.1-flash-image""seedream-5-0-pro""gpt-5.4-image-2""draft""standard""cinema""seedance""kling"
  • reference_asset_idsarray of string · uuidoptional

    Up to 4 image asset ids on board_id to guide the result.

  • source_asset_idstring · uuidoptional

    The asset to work from (an image for image apps; a video clip of at most 15 seconds for Recast/Remake).

  • product_asset_idstring · uuidoptional

    A clean photo of the product.

  • subject_asset_idstring · uuidoptional

    The person or product to place.

  • scene_asset_idstring · uuidoptional

    The destination scene or second subject.

  • identity_asset_idstring · uuidoptional

    A clear image of the new person or character.

  • portrait_asset_idstring · uuidoptional

    A front-facing portrait with one clearly visible person.

  • creator_asset_idstring · uuidoptional

    Optional creator reference or opening frame.

  • start_frame_asset_idstring · uuidoptional

    Image asset the shot starts from.

  • end_frame_asset_idstring · uuidoptional

    Image asset the shot ends on (needs start_frame_asset_id).

  • productstringoptional

    The product: its name and what it does.

    max length 500
  • offerstringoptional

    The product and offer the ad is built around.

    max length 2000
  • audiencestringoptional

    Who it is for.

    max length 500
  • anglestringoptional

    The angle or offer to lead with.

    max length 500
  • hookstringoptional

    The creator's opening line.

    max length 500
  • creatorstringoptional

    Who is speaking, e.g. "a credible solo agency owner filming at their desk".

    max length 300
  • ad_formatstringoptional

    The ad's format, e.g. "cinematic demo", "tabletop showcase", "comparison".

    max length 200
  • scriptstringoptional

    Exactly what the presenter says (at most 38 words).

    max length 400
  • secondsintegeroptional

    Length in seconds.

    min 1max 60
  • soundbooleanoptional

    Generate native audio with the shot.

  • camerastringoptional

    Camera move. auto lets the model choose.

    "auto""static""push-in""pull-back""orbit""pan""tilt-up""tracking""handheld""drone""crash-zoom"
  • directbooleanoptional

    Let Attria rewrite the description as a proper shot before filming (default true).

Can fail with 400 · 401 · 402 · 404 · 409 · 429 · 500 — the shape is in Errors & limits.

POST
curl -X POST "https://app.attria.io/api/v1/studio/image/apps/generate" \
  -H "Authorization: Bearer $ATTRIA_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{
    "prompt": "A matte black insulated travel mug on a sunlit café counter",
    "aspect": "4:5",
    "count": 1
  }'
Response200
{
  "app": "generate",
  "studio": "image",
  "status": "complete",
  "board_id": null,
  "assets": [
    {
      "id": "e9a1…",
      "url": "https://…/creative-assets/…png",
      "width": 1080,
      "height": 1350,
      "mime_type": "image/png"
    }
  ]
}

List websites#

GET/v1/websites
API keywebsites_list

The websites made in Website Studio, most recently changed first.

status is the site's own state: draft (not built yet, or building), built (ready, not published), live (published at public_url), paused. For the build's progress fetch GET /v1/websites/{id}.

Request
GET /v1/websites?limit=10

Query parameters

  • limitintegeroptional

    How many items to return, 1–100. Default 25.

    Default 25min 1max 100
  • cursorstringoptional

    The next_cursor from the previous page. Omit for the first page.

Can fail with 400 · 401 · 404 · 429 · 500 — the shape is in Errors & limits.

GET
curl "https://app.attria.io/api/v1/websites?limit=10" \
  -H "Authorization: Bearer $ATTRIA_API_KEY"
Response200
{
  "object": "list",
  "data": [
    {
      "id": "0c1d…",
      "object": "website",
      "name": "Harbor Dental",
      "status": "built",
      "url": "https://app.attria.io/studio/websites/0c1d…",
      "public_url": null,
      "thumbnail_url": null,
      "created_at": "2026-09-27T18:02:14Z",
      "updated_at": "2026-09-27T18:06:40Z"
    }
  ],
  "has_more": false,
  "next_cursor": null
}

Get a website and its build#

GET/v1/websites/{id}
API keywebsites_get

One website with its build status — poll this after a website turn answered building.

  • build.status: building (queued or running; build.stage says which step), ready (built), failed (build.error says why), or not_started.
  • status: the site itself — draft, built, live or paused. public_url is set while it is live.
  • url opens it in Website Studio.

A new site usually builds in 2–5 minutes; an edit's rebuild in 1–3. Poll every 5–10 seconds.

Request
GET /v1/websites/0c1d2e3f-…

Path parameters

  • idstringrequired

Can fail with 400 · 401 · 404 · 429 · 500 — the shape is in Errors & limits.

GET
curl "https://app.attria.io/api/v1/websites/5b7e2c8e-1f0a-4c3d-9e8b-7a6f5d4c3b2a" \
  -H "Authorization: Bearer $ATTRIA_API_KEY"
Response200
{
  "id": "0c1d…",
  "object": "website",
  "name": "Harbor Dental",
  "status": "built",
  "url": "https://app.attria.io/studio/websites/0c1d…",
  "public_url": null,
  "build": {
    "status": "ready",
    "job": {
      "id": "77aa…",
      "operation": "complete",
      "stage": "complete",
      "status": "succeeded",
      "error": null,
      "updated_at": "2026-09-27T18:06:40Z",
      "completed_at": "2026-09-27T18:06:40Z"
    }
  },
  "business": {
    "name": "Harbor Dental",
    "what_you_sell": "Family dentistry in Portland",
    "who_its_for": null
  },
  "created_at": "2026-09-27T18:02:14Z",
  "updated_at": "2026-09-27T18:06:40Z"
}

List documents#

GET/v1/documents
API keydocuments_list

The decks, proposals and documents made in Documents Studio, most recently changed first. Summaries only — fetch GET /v1/documents/{id} for the content.

kind is deck, proposal or document. public_url is set while the document is shared by link.

Request
GET /v1/documents?limit=10

Query parameters

  • limitintegeroptional

    How many items to return, 1–100. Default 25.

    Default 25min 1max 100
  • cursorstringoptional

    The next_cursor from the previous page. Omit for the first page.

Can fail with 400 · 401 · 404 · 429 · 500 — the shape is in Errors & limits.

GET
curl "https://app.attria.io/api/v1/documents?limit=10" \
  -H "Authorization: Bearer $ATTRIA_API_KEY"
Response200
{
  "object": "list",
  "data": [
    {
      "id": "a3c2…",
      "object": "document",
      "title": "Q3 Investor Update",
      "kind": "deck",
      "version": 2,
      "url": "https://app.attria.io/studio/documents/a3c2…",
      "public_url": null,
      "created_at": "2026-09-27T18:02:11Z",
      "updated_at": "2026-09-27T18:03:01Z"
    }
  ],
  "has_more": false,
  "next_cursor": null
}

Get a document with its full content#

GET/v1/documents/{id}
API keydocuments_get

One document with its full structured content — what the Studio renders:

  • content.layout — slides (a deck: one section per slide) or page (a scrolling document).
  • content.theme — the look.
  • content.sections[] — each with an id, an intent (cover, narrative, pricing, stats, …) and blocks[] (headings, text, lists, images, stats, pricing tables, buttons…).

To change it, send a turn with artifact_id set to this id (POST /v1/studio/document/turns).

Request
GET /v1/documents/a3c2…

Path parameters

  • idstringrequired

Can fail with 400 · 401 · 404 · 429 · 500 — the shape is in Errors & limits.

GET
curl "https://app.attria.io/api/v1/documents/5b7e2c8e-1f0a-4c3d-9e8b-7a6f5d4c3b2a" \
  -H "Authorization: Bearer $ATTRIA_API_KEY"
Response200
{
  "id": "a3c2…",
  "object": "document",
  "title": "Q3 Investor Update",
  "kind": "deck",
  "version": 2,
  "url": "https://app.attria.io/studio/documents/a3c2…",
  "public_url": null,
  "content": {
    "schema": 1,
    "layout": "slides",
    "theme": "brand",
    "sections": [
      {
        "id": "s1",
        "intent": "cover",
        "blocks": [
          {
            "type": "heading",
            "text": "Q3 Investor Update"
          }
        ]
      }
    ]
  },
  "created_at": "2026-09-27T18:02:11Z",
  "updated_at": "2026-09-27T18:03:01Z"
}

List apps#

GET/v1/apps
API keyapps_list

The workspace apps made in Apps Studio, most recently changed first.

live is true once a version has been published (it then appears in the workspace's Apps, at public_url, for signed-in members). version ahead of published_version means a change is waiting to be published.

Request
GET /v1/apps

Query parameters

  • limitintegeroptional

    How many items to return, 1–100. Default 25.

    Default 25min 1max 100
  • cursorstringoptional

    The next_cursor from the previous page. Omit for the first page.

Can fail with 400 · 401 · 404 · 429 · 500 — the shape is in Errors & limits.

GET
curl "https://app.attria.io/api/v1/apps" \
  -H "Authorization: Bearer $ATTRIA_API_KEY"
Response200
{
  "object": "list",
  "data": [
    {
      "id": "6e2f…",
      "object": "app",
      "name": "Job Tracker",
      "description": "Open jobs by date",
      "version": 1,
      "published_version": 1,
      "live": true,
      "url": "https://app.attria.io/studio/apps/6e2f…",
      "public_url": "https://app.attria.io/apps/6e2f…",
      "created_at": "2026-09-27T18:02:11Z",
      "updated_at": "2026-09-27T18:03:20Z"
    }
  ],
  "has_more": false,
  "next_cursor": null
}

Get an app#

GET/v1/apps/{id}
API keyapps_get

One app: its summary, its manifest (the Objects it reads and writes, with access, and the Actions it calls), and the paths of its source files.

To change it, send a turn with artifact_id set to this id (POST /v1/studio/app/turns).

Request
GET /v1/apps/6e2f…

Path parameters

  • idstringrequired

Can fail with 400 · 401 · 404 · 429 · 500 — the shape is in Errors & limits.

GET
curl "https://app.attria.io/api/v1/apps/5b7e2c8e-1f0a-4c3d-9e8b-7a6f5d4c3b2a" \
  -H "Authorization: Bearer $ATTRIA_API_KEY"
Response200
{
  "id": "6e2f…",
  "object": "app",
  "name": "Job Tracker",
  "description": "Open jobs by date",
  "version": 1,
  "published_version": 1,
  "live": true,
  "url": "https://app.attria.io/studio/apps/6e2f…",
  "public_url": "https://app.attria.io/apps/6e2f…",
  "manifest": {
    "schema": 1,
    "objects": [
      {
        "key": "jobs",
        "access": [
          "read",
          "update"
        ]
      }
    ],
    "actions": []
  },
  "files": [
    "src/App.tsx"
  ],
  "created_at": "2026-09-27T18:02:11Z",
  "updated_at": "2026-09-27T18:03:20Z"
}

List image boards#

GET/v1/images/boards
API keyimages_boards_list

The boards in Images Studio, most recently changed first. A board is where a Studio image conversation happens and its images are kept; pass a board's id as artifact_id to POST /v1/studio/image/turns to keep working on it, or as board_id to GET /v1/images.

Request
GET /v1/images/boards

Query parameters

  • limitintegeroptional

    How many items to return, 1–100. Default 25.

    Default 25min 1max 100
  • cursorstringoptional

    The next_cursor from the previous page. Omit for the first page.

Can fail with 400 · 401 · 404 · 429 · 500 — the shape is in Errors & limits.

GET
curl "https://app.attria.io/api/v1/images/boards" \
  -H "Authorization: Bearer $ATTRIA_API_KEY"
Response200
{
  "object": "list",
  "data": [
    {
      "id": "b1f0…",
      "object": "image_board",
      "name": "Summer promo",
      "media_kind": "image",
      "pinned": false,
      "url": "https://app.attria.io/studio/images/b1f0…",
      "created_at": "2026-09-27T18:02:11Z",
      "updated_at": "2026-09-27T18:02:40Z"
    }
  ],
  "has_more": false,
  "next_cursor": null
}

List images#

GET/v1/images
API keyimages_list

Images in the workspace's Studio — made or uploaded — newest first, each with a URL you can download. Filter to one board with board_id (see GET /v1/images/boards).

Request
GET /v1/images?board_id=b1f0…&limit=20

Query parameters

  • board_idstringoptional

    Only images on this board.

  • limitintegeroptional

    How many items to return, 1–100. Default 25.

    Default 25min 1max 100
  • cursorstringoptional

    The next_cursor from the previous page. Omit for the first page.

Can fail with 400 · 401 · 404 · 429 · 500 — the shape is in Errors & limits.

GET
curl "https://app.attria.io/api/v1/images" \
  -H "Authorization: Bearer $ATTRIA_API_KEY"
Response200
{
  "object": "list",
  "data": [
    {
      "id": "e9a1…",
      "url": "https://…/creative-assets/…png",
      "media_type": "image",
      "mime_type": "image/png",
      "width": 1080,
      "height": 1350,
      "duration_seconds": null,
      "prompt": "…",
      "board_id": "b1f0…",
      "created_at": "2026-09-27T18:02:40Z"
    }
  ],
  "has_more": false,
  "next_cursor": null
}

List video projects#

GET/v1/videos
API keyvideos_list

The video projects in Video Studio, most recently changed first: name, aspect, duration and poster. Pass a project's id as artifact_id to POST /v1/studio/video/turns to edit it with the director.

Request
GET /v1/videos

Query parameters

  • limitintegeroptional

    How many items to return, 1–100. Default 25.

    Default 25min 1max 100
  • cursorstringoptional

    The next_cursor from the previous page. Omit for the first page.

Can fail with 400 · 401 · 404 · 429 · 500 — the shape is in Errors & limits.

GET
curl "https://app.attria.io/api/v1/videos" \
  -H "Authorization: Bearer $ATTRIA_API_KEY"
Response200
{
  "object": "list",
  "data": [
    {
      "id": "2d4c…",
      "object": "video",
      "name": "Summer promo",
      "aspect": "9:16",
      "duration_seconds": 21.5,
      "thumbnail_url": null,
      "url": "https://app.attria.io/studio/video/2d4c…",
      "created_at": "2026-09-27T18:02:11Z",
      "updated_at": "2026-09-27T18:02:30Z"
    }
  ],
  "has_more": false,
  "next_cursor": null
}