Running a Workflow
Once you’ve published a Workflow, you run it by calling POST /v1/workflows/{id} with the version ID (the Endpoint ID in the Developer Portal). The request starts an invocation and returns its ID. Then poll GET /v1/workflow_invocations/{id}, or use the SDK’s wait helper, until the invocation finishes. GET /v1/tasks/{id} doesn’t return invocations.
Find the input node IDs
Section titled “Find the input node IDs”A request sets an input by its node ID and the output key on that node: prompt for text inputs, and image, video, or audio for media inputs.
The version’s page in the Developer Portal lists each exposed input’s node ID. You can also read them from GET /v1/workflows/{id}, which returns the published graph. An input is exposed unless it’s marked exposedToApp: false, and the key is the name under the node’s nodeOutputs:
{ "id": "4f0c9a52-8a3e-4c5b-9d1e-2b7a6c3e9f10", "nodeType": "constant-node", "constantNodeType": "prompt", "nodeOutputs": { "prompt": { "type": "string", "label": "Scene", "description": "Describe the scene in one sentence.", "exposedToApp": true, "value": "A ceramic mug on a marble counter, soft daylight" } }}Run a Workflow
Section titled “Run a Workflow”Pass your values in nodeOutputs. Inputs you leave out run with the value saved in the graph.
| Value | Shape | Use for |
|---|---|---|
| Primitive | { "type": "primitive", "value": … } | Text inputs |
| Media | { "type": "image" | "video" | "audio", "uri": … } | Images, video, and audio. uri accepts an HTTPS URL, a Runway upload URI, or a base64 data URI of up to 5 MB. |
The API doesn’t reject a node ID or key that doesn’t match an input; the run uses the saved value instead. Copy IDs from the version page.
import RunwayML, { WorkflowInvocationFailedError } from '@runwayml/sdk';
const client = new RunwayML();
try { // Start the published version with your own inputs const { id } = await client.workflows.run('YOUR_WORKFLOW_ID', { nodeOutputs: { // Replace with the node IDs from the Developer Portal 'TEXT_NODE_ID': { prompt: { type: 'primitive', value: 'A timelapse on a sunny day with clouds flying by' }, }, 'IMAGE_NODE_ID': { image: { type: 'image', uri: 'https://upload.wikimedia.org/wikipedia/commons/8/85/Tour_Eiffel_Wikimedia_Commons_(cropped).jpg', }, }, }, });
// Wait up to 30 minutes for the whole graph to finish const invocation = await client.workflowInvocations .retrieve(id) .waitForTaskOutput({ timeout: 30 * 60 * 1000 });
console.log('Outputs:', invocation.output); console.log('Node errors:', invocation.nodeErrors);} catch (error) { if (error instanceof WorkflowInvocationFailedError) { console.error('The workflow failed.'); console.error(error.invocationDetails); } else { console.error(error); }}from runwayml import RunwayML, WorkflowInvocationFailedError
client = RunwayML()
try: # Start the published version with your own inputs run = client.workflows.run( 'YOUR_WORKFLOW_ID', node_outputs={ # Replace with the node IDs from the Developer Portal 'TEXT_NODE_ID': { 'prompt': {'type': 'primitive', 'value': 'A timelapse on a sunny day with clouds flying by'}, }, 'IMAGE_NODE_ID': { 'image': { 'type': 'image', 'uri': 'https://upload.wikimedia.org/wikipedia/commons/8/85/Tour_Eiffel_Wikimedia_Commons_(cropped).jpg', }, }, }, )
# Wait up to 30 minutes for the whole graph to finish invocation = client.workflow_invocations.retrieve(id=run.id).wait_for_task_output(timeout=1800)
print('Outputs:', invocation.output) print('Node errors:', invocation.node_errors)except WorkflowInvocationFailedError as e: print('The workflow failed.') print(e.invocation_details)# Start the published version with your own inputscurl -X POST https://api.dev.runwayml.com/v1/workflows/YOUR_WORKFLOW_ID \ -d '{ "nodeOutputs": { "TEXT_NODE_ID": { "prompt": { "type": "primitive", "value": "A timelapse on a sunny day with clouds flying by" } }, "IMAGE_NODE_ID": { "image": { "type": "image", "uri": "https://upload.wikimedia.org/wikipedia/commons/8/85/Tour_Eiffel_Wikimedia_Commons_(cropped).jpg" } } } }' \ -H "Content-Type: application/json" \ -H "Authorization: Bearer $RUNWAYML_API_SECRET" \ -H "X-Runway-Version: 2024-11-06"
# The response is { "id": "..." }. Poll the invocation with that ID:curl https://api.dev.runwayml.com/v1/workflow_invocations/INVOCATION_ID \ -H "Authorization: Bearer $RUNWAYML_API_SECRET" \ -H "X-Runway-Version: 2024-11-06"The wait helpers give up after 10 minutes by default. A graph with several video steps can take longer, so pass a longer timeout: milliseconds in Node, seconds in Python. On timeout they throw WorkflowInvocationTimedOutError in Node and WorkflowInvocationTimeoutError in Python; the invocation keeps running, so you can keep polling.
Invocation status
Section titled “Invocation status”| Status | Meaning |
|---|---|
PENDING | The invocation is queued. |
THROTTLED | The invocation is queued and hasn’t started. Treat it like PENDING. |
RUNNING | The graph is running. progress rises from 0 to 1. |
SUCCEEDED | No more nodes can run. Individual nodes can still have failed or been skipped; see Partial runs. |
FAILED | The invocation stopped as a whole, usually because the graph couldn’t start. Read failure and, when present, failureCode. |
Poll no more often than once every five seconds. The SDK wait helpers return when the invocation succeeds and throw WorkflowInvocationFailedError when it fails.
Partial runs
Section titled “Partial runs”An invocation succeeds once no more nodes can run, so a node can fail, for example on a moderated prompt or a provider outage, while the invocation as a whole succeeds. Nodes downstream of a failed node don’t run, and neither does a node missing a required input. Don’t rely on status alone: check nodeErrors, and check that output has every node you expect.
{ "id": "f1a2b3c4-2c4d-4c6d-9e57-2d2e8ff97903", "status": "SUCCEEDED", "createdAt": "2024-06-27T19:49:32.335Z", "output": { "a1b2c3d4-e5f6-7890-abcd-ef1234567890": ["https://example.com/output1.jpg"] }, "nodeErrors": { "b2c3d4e5-f6a7-8901-bcde-f12345678901": { "nodeName": "Generate image", "message": "Image generation failed. Please try again later.", "failureCode": "THIRD_PARTY.UNAVAILABLE" } }, "cost": { "credits": 45 }}nodeErrors lists only the nodes that failed, not the nodes skipped after them. failureCode uses the same codes as task failures, and can be absent.
Read the outputs
Section titled “Read the outputs”output maps node IDs to arrays of URLs for the outputs you exposed when you published. While the invocation is running, it includes exposed nodes that have already finished.
These URLs expire within 24–48 hours. Fetch the invocation again for fresh URLs, and download the files to your own storage rather than exposing the URLs in your product. See Outputs.
A run uses your Runway Dev credits, not your Runway app workspace’s. It’s billed for each node that runs, at that node’s own price, with no separate charge for the Workflow. When every node has finished, cost.credits reports the total on a SUCCEEDED or FAILED invocation. It’s omitted until then, so fetch the invocation again if it’s missing. See Pricing for model rates.
Cancel an invocation
Section titled “Cancel an invocation”To stop a RUNNING invocation, call DELETE /v1/tasks/{id} with the invocation ID, or client.tasks.delete() in the SDKs. No new nodes start, but nodes that have already started or are queued still run and are billed.
Errors
Section titled “Errors”POST /v1/workflows/{id}returns404if the version doesn’t exist, was deleted, or was published to a different project than your API key’s.POST /v1/workflows/{id}returns400if a node in the published graph uses a model that is no longer available. Replace the node in the Runway app and publish a new version.POST /v1/workflows/{id}returns400if a media input can’t be fetched or is over the input limits.GET /v1/workflow_invocations/{id}returns404if the invocation doesn’t exist or was cancelled or deleted. There is noCANCELLEDstatus to poll for.
See HTTP errors for the codes every endpoint can return.