Create runs
Starts a run: name exactly one of template, flow or graph, with the input its inputs schema asks for.
POST /v1/studio/runs
| Address | https://api.hanzo.ai/v1/studio/runs |
| Method | POST |
| Operation | post_studio_runs |
| Auth | Authorization: Bearer $HANZO_API_KEY |
Starts a run: name exactly one of template, flow or graph, with the input its inputs schema asks for. The run is checked, priced and its estimate reserved against your org's wallet, then queued; the answer is the run at queued. Follow it on GET /v1/studio/runs/{id}/events.
parent makes this run the next version of that run: it takes the parent's graph and input, overlaid by what this request states. Send Idempotency-Key to make a retried request start one run, not two. 402 when the wallet cannot cover the estimate; 422 when the graph or input does not validate.
Request
17 fields, body application/json (required).
| Field | In | Type | Required | Description |
|---|---|---|---|---|
Idempotency-Key | header | string | — | |
brand | body | string | — | Brand is a brand id; its tokens are brand.* in the graph. |
flow | body | string | — | Flow is a flow id. |
graph | body | studio.Graph | — | |
graph.steps | body | studio.Spec[] | — | Steps are the graph's steps, 1 to 64 of them. |
graph.steps[].each | body | string | — | Each fans the step out: a {{path}} naming an array, run once per item (at most 64), its outputs the items' outputs in order. |
graph.steps[].id | body | string | — | ID names the step within its graph: a lowercase letter, then up to 31 lowercase letters, digits or underscores. |
graph.steps[].op | body | string | — | Op is what the step does: chat, image.generate, image.edit, voice.speak, music.generate, video.generate, model.generate, studio.render, render.html, render.document, render.slides, render.composition or video.edit. |
graph.steps[].title | body | string | — | Title is what a person sees for the step. |
graph.steps[].with | body | object | — | With are the op's parameters. |
graph.steps[].with.* | body | any | — | |
input | body | object | — | Input are the values the inputs schema asks for. |
input.* | body | any | — | |
parent | body | string | — | Parent makes this run the next version of that run. |
shared | body | boolean | — | |
template | body | string | — | Template is a template id. |
title | body | string | — |
Response
| Status | Body | Meaning |
|---|---|---|
201 | studio.Run | created |
default | problem-details | refused |
201 body — 77 fields.
| Field | In | Type | Always | Description |
|---|---|---|---|---|
brand | body | string | — | |
charged_cents | body | integer (int64) | — | ChargedCents is what the finished steps cost; final once the run ends. |
created | body | string | — | |
creator | body | string | — | |
error | body | studio.Problem | — | |
error.code | body | string | — | |
error.detail | body | string | — | |
error.status | body | integer (int64) | — | |
error.title | body | string | — | |
error.type | body | string | — | |
estimate_cents | body | integer (int64) | — | EstimateCents is what was reserved when the run started. |
finished | body | string | — | |
flow | body | string | — | |
graph | body | studio.Graph | — | |
graph.steps | body | studio.Spec[] | — | Steps are the graph's steps, 1 to 64 of them. |
graph.steps[].each | body | string | — | Each fans the step out: a {{path}} naming an array, run once per item (at most 64), its outputs the items' outputs in order. |
graph.steps[].id | body | string | — | ID names the step within its graph: a lowercase letter, then up to 31 lowercase letters, digits or underscores. |
graph.steps[].op | body | string | — | Op is what the step does: chat, image.generate, image.edit, voice.speak, music.generate, video.generate, model.generate, studio.render, render.html, render.document, render.slides, render.composition or video.edit. |
graph.steps[].title | body | string | — | Title is what a person sees for the step. |
graph.steps[].with | body | object | — | With are the op's parameters. |
graph.steps[].with.* | body | any | — | |
id | body | string | — | |
input | body | object | — | Input is what the run was given, as its inputs schema reads it. |
input.* | body | any | — | |
kind | body | string | — | |
org | body | string | — | |
outputs | body | studio.Item[] | — | Outputs are the Library items the run made, the final steps' first. |
outputs[].bytes | body | integer (int64) | — | |
outputs[].created | body | string | — | |
outputs[].download | body | string | — | |
outputs[].expires | body | string | — | |
outputs[].height | body | integer (int64) | — | |
outputs[].id | body | string | — | |
outputs[].kind | body | string | — | |
outputs[].mime | body | string | — | |
outputs[].mine | body | boolean | — | |
outputs[].name | body | string | — | |
outputs[].origin | body | string | — | |
outputs[].owner | body | string | — | |
outputs[].pages | body | integer (int64) | — | |
outputs[].preview | body | string | — | |
outputs[].ref | body | string | — | |
outputs[].seconds | body | number (double) | — | |
outputs[].shared | body | boolean | — | |
outputs[].source | body | string | — | |
outputs[].url | body | string | — | URL opens the file inline; Download saves it; Preview is its still. |
outputs[].width | body | integer (int64) | — | |
parent | body | string | — | |
root | body | string | — | Root is the first version's id; equal to id on version 1. |
shared | body | boolean | — | |
started | body | string | — | |
status | body | string | — | |
steps | body | studio.Step[] | — | |
steps[].attempt | body | integer (int64) | — | Attempt is how many times the step has started. |
steps[].cost_cents | body | integer (int64) | — | |
steps[].error | body | studio.Problem | — | |
steps[].error.code | body | string | — | |
steps[].error.detail | body | string | — | |
steps[].error.status | body | integer (int64) | — | |
steps[].error.title | body | string | — | |
steps[].error.type | body | string | — | |
steps[].executor | body | string | — | Executor is where the step runs: gateway, studio.render, render or flow.run. |
steps[].finished | body | string | — | |
steps[].id | body | string | — | |
steps[].items | body | integer (int64) | — | Items is how many items a step with each fanned out to. |
steps[].message | body | string | — | Message is what the step is doing now, for a person. |
steps[].op | body | string | — | |
steps[].outputs | body | string[] | — | Outputs are the Library item ids the step made. |
steps[].progress | body | number (double) | — | |
steps[].started | body | string | — | |
steps[].status | body | string | — | Status is pending, queued, running, succeeded, failed, canceled or skipped. |
steps[].text | body | string | — | |
steps[].title | body | string | — | |
template | body | string | — | |
text | body | string | — | Text is the last chat step's text, when the run's product is words. |
title | body | string | — | |
version | body | integer (int64) | — |
Failure carries the platform error shape — see Errors.
Examples
hanzo studio runs createimport { Configuration, StudioApi } from 'hanzoai';
const api = new StudioApi(new Configuration({ accessToken: process.env.HANZO_API_KEY }));
const { data } = await api.postStudioRuns({ brand: "<brand>", flow: "<flow>" });from hanzoai.cloud import ApiClient, Configuration
from hanzoai.cloud.api import StudioApi
client = ApiClient(Configuration(access_token=os.environ["HANZO_API_KEY"]))
result = StudioApi(client).post_studio_runs(brand="<brand>", flow="<flow>")cfg := hanzoai.NewConfiguration()
cfg.AddDefaultHeader("Authorization", "Bearer "+os.Getenv("HANZO_API_KEY"))
client := hanzoai.NewAPIClient(cfg)
resp, _, err := client.StudioAPI.PostStudioRuns(context.Background()).Execute()
if err != nil {
return err
}use hanzo_client::apis::{configuration::Configuration, studio_api};
let mut cfg = Configuration::new();
cfg.bearer_access_token = std::env::var("HANZO_API_KEY").ok();
let result = studio_api::post_studio_runs(&cfg, Default::default()).await?;import ai.hanzo.cloud.ApiClient;
import ai.hanzo.cloud.api.StudioApi;
ApiClient client = new ApiClient();
client.setBearerToken(System.getenv("HANZO_API_KEY"));
var result = new StudioApi(client).postStudioRuns();curl -X POST https://api.hanzo.ai/v1/studio/runs \
-H "Authorization: Bearer $HANZO_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"brand": "<brand>",
"flow": "<flow>"
}'MCP reaches studio through the studio tool, which names its 32 operations with its own verbs — this one among them, under a name only MCP declares. describe explains any of them:
curl -X POST https://api.hanzo.ai/v1/mcp \
-H "Content-Type: application/json" \
-d '{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "describe",
"arguments": {
"op": "list_studio_brands"
}
}
}'