Run workflows from code and agents
Run workflows and Apps through the API and the Scenario MCP: find the input names, quote with a dry run, start the job, wait, read results and answer approvals.
- Guide
- Step 2 Repeat
The workflow built in the editor does not change: your script, pipeline or agent fills the same inputs and gets a job back.
- 1Find inputsworkflow ID and input names
- 2Uploadfiles become asset IDs
- 3Dry runa quote before running
- 4Runone workflow job
- 5Waitpoll, webhook or
jobs_wait - 6Answer reviewsapprove, reject or select
Quick version
- Copy the workflow ID (... > Copy Workflow ID) and read its input names with
GET /v1/workflows/{id}. - Upload each file input and keep its
asset_...ID. - Send
PUT /v1/workflows/{id}/runwithdryRun=trueand read the quote. - Send the same request without
dryRun, then pollGET /v1/jobs/{jobId}until it ends. - Sum the child jobs in
metadata.flowto know what the run cost.
An App is a workflow with status ready. Platform Apps are public; your own workflows and Apps are private to their project. Both run the same way.
The same five steps through the API or the Scenario MCP:
| Step | API | Scenario MCP |
|---|---|---|
1. Get the workflow ID and input names (such as image1); upload files, since file inputs take asset IDs | GET /v1/workflows/{id}, POST /v1/assets | workflow_get, upload_asset |
| 2. Quote with a dry run | PUT .../run with dryRun=true (status 269 with the quote) | workflow_run with dry_run: true |
| 3. Run with the same body | PUT /v1/workflows/{id}/run | workflow_run |
| 4. Wait until success or failure | GET /v1/jobs/{jobId} or a webhook | jobs_wait |
| 5. Answer reviews, only if the run pauses | PUT user-approval or user-selection | workflow_approve, workflow_reject |
The parent job's cuCost reads 0: the cost is the sum of the child jobs in metadata.flow.
1. Get the workflow ID and input names
- Your workflows: in the editor, open ... and choose Copy Workflow ID.
- Public workflows have IDs too. Angle Multiplier is
wflow_angle-multiplier.
Each input has a name, such as image1 or text1, which is what you send. Read them from the workflow definition:
curl -s "https://api.cloud.scenario.com/v1/workflows/wflow_angle-multiplier?projectId=$PROJECT_ID" \
-u "$SCENARIO_API_KEY:$SCENARIO_API_SECRET"
Through the Scenario MCP, ask your agent to call workflow_get; it returns the inputs definition and the editor graph. For Angle Multiplier there is one required input: image1 ("Upload Product", an image).
File inputs take an asset ID, so upload your file first (POST /v1/assets, or upload_asset in the Scenario MCP) and keep the asset_... ID.
2. Quote it with a dry run
A dry run returns a quote for the run without running it. On Enterprise, an IP Detection check requested in the same call is still charged.
curl -s -X PUT "https://api.cloud.scenario.com/v1/workflows/wflow_angle-multiplier/run?projectId=$PROJECT_ID&dryRun=true" \
-u "$SCENARIO_API_KEY:$SCENARIO_API_SECRET" \
-H "Content-Type: application/json" \
-d '{ "image1": "asset_..." }'
A dry run answers with HTTP status 269 and the cost in Compute Units: the status means "estimate", not an error, so do not treat it as a failure. dryRun=api estimates at the API tier.
Through the Scenario MCP, the same quote looked like this on October 12, 2026:
// workflow_run { "workflow_id": "wflow_angle-multiplier",
// "inputs": { "image1": "asset_SstohPMc..." }, "dry_run": true }
{ "creativeUnitsCost": 13.75, "creativeUnitsDiscount": 0, "job": {} }
The quote is in Compute Units (CU), the unit credits are metered in. Budget with it.
3. Run it
Send the same request without dryRun. Inputs go directly in the body, keyed by input name.
curl -s -X PUT "https://api.cloud.scenario.com/v1/workflows/wflow_angle-multiplier/run?projectId=$PROJECT_ID" \
-u "$SCENARIO_API_KEY:$SCENARIO_API_SECRET" \
-H "Content-Type: application/json" \
-d '{ "image1": "asset_..." }'
The response is a workflow job. Its metadata.flow lists each node with its own status and, for model nodes, its own child job. Trimmed from the real Scenario MCP run:
{ "job": { "jobId": "job_BfM1ywYj...", "jobType": "workflow",
"metadata": { "flow": [
{ "id": "imageGenerator1", "type": "custom-model", "status": "processing",
"modelId": "model_openai-gpt-image-2-5-sunburst", "jobId": "job_HEmqpWhU..." },
{ "id": "text1", "type": "transform", "status": "success",
"output": "Generate multiple viewing angles of the product shown in this image..." } ],
"input": { "image1": "asset_SstohPMc..." } } } }
4. Wait for the result
Poll GET /v1/jobs/{jobId} or use webhooks (see Jobs, polling and webhooks).
- 1pendingaccepted
- 2queuedwaiting for capacity
- 3warming-upmodel loading
- 4in-progressgenerating
- 5finalizingsaving assets
- 6successor
failure,canceled
In the Scenario MCP, jobs_wait does the polling:
// jobs_wait { "job_ids": ["job_BfM1ywYj..."] }
{ "status": "completed", "jobs": [ { "jobId": "job_BfM1ywYj...", "jobType": "workflow",
"status": "success", "assetIds": ["asset_kygugJ6u..."], "cuCost": 0 } ] }
The run took about 23 seconds. The output asset is the six-angle grid shown in Platform workflows and templates.
Through an AI agent
With the Scenario MCP connected, an agent can do all of the above from a plain request:
Run the Scenario App "Angle Multiplier" on the lantern photo I uploaded. Quote the cost
first and wait for my go. Then show me the result and tell me what it cost.
| Step | Scenario MCP tool |
|---|---|
| Find it (Apps are ready workflows) | workflows_list |
| Read the inputs | workflow_get |
| Quote | workflow_run with dry_run |
| Start | workflow_run |
| Wait | jobs_wait |
| Answer approval nodes | Catalog tools workflow_approve and workflow_reject |
| Copy a workflow into your project | workflow_copy |
The scenario-workflows skill teaches agents the run procedure; scenario-workflow-authoring covers building graphs. See Scenario MCP tools reference and Scenario's skills.
Answer review steps from code
A run that reaches an Approval node or Slice Items in Choose mode waits until someone answers.
| Node | Endpoint | Body |
|---|---|---|
| Approval | PUT /v1/workflows/{workflowId}/user-approval | workflowJobId, nodeId, action: approve (default) or reject |
| Slice Items, Choose | PUT /v1/workflows/{workflowId}/user-selection | workflowJobId, nodeId, action: select with selectedIndices (zero-based), or reject |
A rejected stand-alone node cancels the run. A rejection inside a Loop iteration cascades to the surrounding loop.
Limits
As documented for the API:
| Limit | Value |
|---|---|
| Requests | 100 per minute per project |
| Concurrent workflow jobs | 10 per project |
| Nodes | 50 per workflow |
For large batches, queue your inputs and keep at most 10 runs in flight.
the dry run quote matches the editor's badge for the same inputs; the job ends in success with the expected number of assets; the summed child-job cost is at or under the quote; outputs land in the project you passed.
you started a batch without a dry run; an input name in your body does not match the definition, so the node ran empty; your script treats the dry-run status 269 as a failure; you report the parent job's cuCost of 0 as the cost.
If it breaks
| Symptom | Cause and fix |
|---|---|
| 400 Bad Request | An input name is wrong or a required input is missing. Compare your body with the inputs from workflow_get |
| 401 or 403 | The key is missing, wrong, or lacks access to the project. See API keys and authentication |
| 404 | The workflow ID is wrong, or the workflow belongs to another project |
| The workflow cannot run | Workflows in draft status do not execute; it must be ready |
| The job waits forever | It is paused at a review node. Answer it with the endpoints above |
| Runs queue up | You hit the 10-concurrent limit. Throttle your client |