Skip to main content

Workflow API Documentation

A Workflow in ScriptRun is a visual representation of a process or automation. It consists of interconnected nodes (steps, triggers, actions, outputs) and edges (connections between nodes), allowing you to design and execute complex logic flows.

Key Concepts

  • Workflow: A schema consisting of nodes and edges that defines the sequence of actions.
  • Node: A step in the process (e.g., trigger, LLM request, data processing, output). Each node has a unique UUID identifier.
  • Edge: Connects two nodes, defining the direction of the flow.
  • Data: The structure describing all nodes, edges, the start node, and viewport parameters.
  • WorkflowRun: A single execution instance of a workflow. Has its own UUID, status, and result.

Workflow Data Structure Example

The example below is based on a real workflow: Trigger → If/Else → two LLM branches.

{
"id": 65,
"project": 12,
"title": "Text Classification Workflow",
"data": {
"edges": [
{
"id": "xy-edge__052af1cb-86fd-443a-bc25-626c365025db-0a4c9bdb-0378-4426-9e4d-0ba5c6e3e5a8",
"type": "custom-edge",
"style": { "stroke": "#76A9FA", "strokeWidth": 2 },
"source": "052af1cb-86fd-443a-bc25-626c365025db",
"target": "0a4c9bdb-0378-4426-9e4d-0ba5c6e3e5a8",
"animated": false,
"markerEnd": "edge-target",
"markerStart": "edge-source"
},
{
"id": "xy-edge__0a4c9bdb-0378-4426-9e4d-0ba5c6e3e5a8condition-true-58a35684-7d25-4dff-b012-609eab065751",
"type": "custom-edge",
"style": { "stroke": "#76A9FA", "strokeWidth": 2 },
"source": "0a4c9bdb-0378-4426-9e4d-0ba5c6e3e5a8",
"target": "58a35684-7d25-4dff-b012-609eab065751",
"animated": false,
"markerEnd": "edge-target",
"markerStart": "edge-source",
"sourceHandle": "condition-true"
},
{
"id": "xy-edge__0a4c9bdb-0378-4426-9e4d-0ba5c6e3e5a8condition-false-8f6bd336-3d7c-41fe-b94c-d47974c1e056",
"type": "custom-edge",
"style": { "stroke": "#76A9FA", "strokeWidth": 2 },
"source": "0a4c9bdb-0378-4426-9e4d-0ba5c6e3e5a8",
"target": "8f6bd336-3d7c-41fe-b94c-d47974c1e056",
"animated": false,
"markerEnd": "edge-target",
"markerStart": "edge-source",
"sourceHandle": "condition-false"
}
],
"nodes": [
{
"id": "052af1cb-86fd-443a-bc25-626c365025db",
"type": "trigger-node",
"position": { "x": 250, "y": 0 },
"data": {
"id": "052af1cb-86fd-443a-bc25-626c365025db",
"name": "Trigger",
"label": "Trigger",
"version": "0.1",
"input_fields": [
{
"id": "category",
"title": "Category",
"type": "text",
"input_requirements": true,
"placeholder": "Enter category",
"tooltip": "",
"default_value": "",
"options": []
}
],
"next_nodes": ["0a4c9bdb-0378-4426-9e4d-0ba5c6e3e5a8"]
}
},
{
"id": "0a4c9bdb-0378-4426-9e4d-0ba5c6e3e5a8",
"type": "if-else-node",
"position": { "x": 550, "y": 0 },
"data": {
"id": "0a4c9bdb-0378-4426-9e4d-0ba5c6e3e5a8",
"name": "If",
"label": "If",
"version": "0.1",
"condition": {
"left": "{{ input.category }}",
"right": "positive",
"operator": "=="
},
"true_node": "58a35684-7d25-4dff-b012-609eab065751",
"false_node": "8f6bd336-3d7c-41fe-b94c-d47974c1e056",
"next_nodes": [
"58a35684-7d25-4dff-b012-609eab065751",
"8f6bd336-3d7c-41fe-b94c-d47974c1e056"
]
}
},
{
"id": "58a35684-7d25-4dff-b012-609eab065751",
"type": "basic-node",
"position": { "x": 850, "y": -160 },
"data": {
"id": "58a35684-7d25-4dff-b012-609eab065751",
"name": "LLM OpenAI",
"label": "LLMOpenAI",
"version": "0.1",
"messages": [
{
"role": "system",
"message": "You are a helpful assistant. Reply briefly."
},
{
"role": "user",
"message": "The sentiment is positive. Provide a short encouraging response."
}
],
"settings": {
"model_name": "gpt-4o",
"temperature": 0.7
},
"next_nodes": []
}
},
{
"id": "8f6bd336-3d7c-41fe-b94c-d47974c1e056",
"type": "basic-node",
"position": { "x": 850, "y": 136 },
"data": {
"id": "8f6bd336-3d7c-41fe-b94c-d47974c1e056",
"name": "LLM OpenAI",
"label": "LLMOpenAI 1",
"version": "0.1",
"messages": [
{
"role": "system",
"message": "You are a helpful assistant. Reply briefly."
},
{
"role": "user",
"message": "The sentiment is negative. Provide a short empathetic response."
}
],
"settings": {
"model_name": "gpt-4o",
"temperature": 0.7
},
"next_nodes": []
}
}
],
"viewport": { "x": 434, "y": 557, "zoom": 1.0 },
"start_node": "052af1cb-86fd-443a-bc25-626c365025db"
}
}

How to read this example:

  • start_node — UUID of the first node to execute (Trigger).
  • edges — connections between nodes. sourcetarget. For if-else-node, the sourceHandle field indicates which branch (condition-true / condition-false).
  • nodes[].type — node type: trigger-node, if-else-node, basic-node, output-node.
  • nodes[].data.input_fields — fields declared in the Trigger node. These map to {{ input.<field_id> }} variables throughout the workflow.
  • nodes[].data.condition — for if-else-node: compares left and right using operator. Supports ==, !=, >, <, >=, <=.
  • nodes[].data.messages — for LLM nodes: the prompt messages array (system + user roles).
  • nodes[].data.next_nodes — list of downstream node UUIDs.

API Endpoints

Create a Workflow

Python
import requests

url = "https://scriptrun.ai/api/v1/workflows/"
headers = {"X-Api-Key": "<Your API Key>"}
data = {
"project": 307,
"title": "New workflow",
"data": {} # see structure above
}

response = requests.post(url, headers=headers, json=data)
print(response.json())
Shell
curl -X POST "https://scriptrun.ai/api/v1/workflows/" \
-H "X-Api-Key: <Your API Key>" \
-H "Content-Type: application/json" \
-d '{
"project": 307,
"title": "New workflow",
"data": {}
}'

POST /api/v1/workflows/

Summary: Creates a new workflow.

Request Body:

NameTypeRequiredDescription
projectintegerYesProject ID to which the workflow belongs.
titlestringYesName/title of the workflow.
dataobjectYesWorkflow structure (nodes, edges, viewport)

Responses:

  • 201: Workflow successfully created.
  • 400: Invalid input or missing required parameters.

Retrieve Workflows

Python
url = "https://scriptrun.ai/api/v1/workflows/"
headers = {"X-Api-Key": "<Your API Key>"}
params = {"project": 307}

response = requests.get(url, headers=headers, params=params)
print(response.json())
Shell
curl -X GET "https://scriptrun.ai/api/v1/workflows/?project=307" \
-H "X-Api-Key: <Your API Key>"

GET /api/v1/workflows/

Summary: Retrieves a list of workflows, optionally filtered by project.

Parameters:

NameInTypeRequiredDescription
projectqueryintegerNoFilter workflows by project ID.
titlequerystringNoFilter by workflow title (case-insensitive).
pagequeryintegerNoPage number for pagination.

Responses:

  • 200: Returns a paginated list of workflows.

Retrieve a Specific Workflow

Python
url = "https://scriptrun.ai/api/v1/workflows/6/"
headers = {"X-Api-Key": "<Your API Key>"}

response = requests.get(url, headers=headers)
print(response.json())
Shell
curl -X GET "https://scriptrun.ai/api/v1/workflows/6/" \
-H "X-Api-Key: <Your API Key>"

GET /api/v1/workflows/{id}/

Summary: Retrieves the details of a specific workflow by its ID.

Parameters:

NameInTypeRequiredDescription
idpathintegerYesID of the workflow to fetch.

Responses:

  • 200: Returns the workflow details.
  • 404: Workflow not found.

Update a Workflow

Python
url = "https://scriptrun.ai/api/v1/workflows/6/"
headers = {"X-Api-Key": "<Your API Key>"}
data = {
"title": "Updated Workflow Title",
"data": {}
}

response = requests.patch(url, headers=headers, json=data)
print(response.json())
Shell
curl -X PATCH "https://scriptrun.ai/api/v1/workflows/6/" \
-H "X-Api-Key: <Your API Key>" \
-H "Content-Type: application/json" \
-d '{
"title": "Updated Workflow Title",
"data": {}
}'

PATCH /api/v1/workflows/{id}/

Summary: Updates an existing workflow.

Parameters:

NameInTypeRequiredDescription
idpathintegerYesID of the workflow to update.

Request Body:

NameTypeRequiredDescription
titlestringNoUpdated workflow title.
dataobjectNoUpdated workflow structure.

Responses:

  • 200: Workflow successfully updated.
  • 404: Workflow not found.

Delete a Workflow

Python
url = "https://scriptrun.ai/api/v1/workflows/6/"
headers = {"X-Api-Key": "<Your API Key>"}

response = requests.delete(url, headers=headers)
print(response.status_code)
Shell
curl -X DELETE "https://scriptrun.ai/api/v1/workflows/6/" \
-H "X-Api-Key: <Your API Key>"

DELETE /api/v1/workflows/{id}/

Summary: Deletes a specific workflow by its ID.

Parameters:

NameInTypeRequiredDescription
idpathintegerYesID of the workflow to delete.

Responses:

  • 204: Workflow successfully deleted.
  • 404: Workflow not found.

Additional Workflow Endpoints

Get Workflow Input Fields

GET /api/v1/workflows/{id}/input-fields/

Summary: Returns the list of input fields defined in the workflow's Trigger node. Use this to discover what parameters the workflow expects before running it.

Python
import requests

url = "https://scriptrun.ai/api/v1/workflows/271/input-fields/"
headers = {"X-Api-Key": "<Your API Key>"}

response = requests.get(url, headers=headers)
print(response.json())
Shell
curl -X GET "https://scriptrun.ai/api/v1/workflows/271/input-fields/" \
-H "X-Api-Key: <Your API Key>"

Parameters:

NameInTypeRequiredDescription
idpathintegerYesID of the workflow.

Response (200):

Returns an array of input field objects:

FieldTypeDescription
idstringField identifier (used as key in input data).
titlestringHuman-readable field label.
typestringField type (e.g., text, select, number).
input_requirementsbooleanWhether the field is required.
placeholderstringPlaceholder text for the field.
tooltipstringHelper text shown to the user.
default_valuestringDefault value if none is provided.
optionsarrayAvailable options for select type fields.

Example Response:

[
{
"id": "user_name",
"title": "User Name",
"type": "text",
"input_requirements": true,
"placeholder": "Enter your name",
"tooltip": "Full name of the user",
"default_value": "",
"options": []
},
{
"id": "language",
"title": "Language",
"type": "select",
"input_requirements": false,
"placeholder": "",
"tooltip": "Output language",
"default_value": "en",
"options": [
{"title": "English", "value": "en", "is_default": true},
{"title": "Russian", "value": "ru", "is_default": false}
]
}
]

Check Workflow Structure

GET /api/v1/workflows/{id}/check_workflow/

Summary: Validates the structure of a saved workflow.

Python
import requests

url = "https://scriptrun.ai/api/v1/workflows/6/check_workflow/"
headers = {"X-Api-Key": "<Your API Key>"}

response = requests.get(url, headers=headers)
print(response.json())
Shell
curl -X GET "https://scriptrun.ai/api/v1/workflows/6/check_workflow/" \
-H "X-Api-Key: <Your API Key>"

Parameters:

NameInTypeRequiredDescription
idpathintegerYesID of the workflow.

Responses:

  • 200: Validation result returned.
  • 404: Workflow not found.

Get Node Schemas for Frontend

GET /api/v1/workflows/get_nodes/

Summary: Retrieves the available node schemas for rendering and configuration in the frontend.

Python
import requests

url = "https://scriptrun.ai/api/v1/workflows/get_nodes/"
headers = {"X-Api-Key": "<Your API Key>"}

response = requests.get(url, headers=headers)
print(response.json())
Shell
curl -X GET "https://scriptrun.ai/api/v1/workflows/get_nodes/" \
-H "X-Api-Key: <Your API Key>"

Running a Workflow

POST /api/v1/workflows/{id}/run/

Summary: Starts the execution of a specific workflow. Optionally pass input data to parameterize the run.


Request Format: Two Modes

The /run/ endpoint behaves differently depending on the authentication method used. Both modes are officially supported. There is no planned deprecation of either format.

Mode 1 — API Key (X-Api-Key header): flat body (canonical for API integrations)

When authenticating with an API key, send the input data directly as the request body — either as a raw JSON string or plain text. Do not wrap in input_data.

This is the recommended format for all API integrations.

Python (API Key — flat body)
import requests

url = "https://scriptrun.ai/api/v1/workflows/6/run/"
headers = {
"X-Api-Key": "<Your API Key>",
"Content-Type": "application/json",
}
# Send input fields directly as JSON body
body = '{"user_name": "John Doe", "email": "john@example.com"}'

response = requests.post(url, headers=headers, data=body)
print(response.json())
Shell (API Key — flat body)
curl -X POST "https://scriptrun.ai/api/v1/workflows/6/run/" \
-H "X-Api-Key: <Your API Key>" \
-H "Content-Type: application/json" \
-d '{"user_name": "John Doe", "email": "john@example.com"}'

Plain text is also accepted:

Shell (API Key — plain text body)
curl -X POST "https://scriptrun.ai/api/v1/workflows/6/run/" \
-H "X-Api-Key: <Your API Key>" \
-H "Content-Type: text/plain" \
-d "Hello, process this text"

Mode 2 — JWT (frontend / session): input_data wrapper

When authenticating with JWT (frontend sessions), wrap the input inside input_data:

Python (JWT — input_data wrapper)
import requests

url = "https://scriptrun.ai/api/v1/workflows/6/run/"
headers = {"Authorization": "Bearer <JWT Token>"}
data = {
"input_data": {
"user_name": "John Doe",
"email": "john@example.com"
}
}

response = requests.post(url, headers=headers, json=data)
print(response.json())

Summary of request format by auth mode:

Auth methodRequest body formatContent-Type
X-Api-Key headerRaw JSON string or plain text (flat)application/json or text/plain
JWT Bearer token{"input_data": { ... }}application/json

Parameters

NameInTypeRequiredDescription
idpathintegerYesID of the workflow to run.

Response (200)

The endpoint returns HTTP 200 with a JSON body in the following format:

{
"data": {
"id": "0781b175-2135-45ec-9063-ad3e0d929adc",
"status": "created"
},
"status": 201
}
FieldTypeDescription
statusintegerHTTP status code returned by the execution service. 201 = accepted and started.
dataobjectExecution service response body. Contains data.id — the WorkflowRun UUID needed for polling.
important

data.id (UUID string) is the WorkflowRun identifier. Save it immediately — you will use it to poll for the result via GET /api/v1/workflows/workflow_result/?id=<uuid>.

The id field is a UUID string (e.g., "0781b175-2135-45ec-9063-ad3e0d929adc"), not an integer. Do not treat it as an integer or compare with workflow IDs.

Error response (workflow structure invalid):

When the workflow has structural errors, the endpoint still returns HTTP 200 but with an error payload:

{
"data": { "errors": ["Node X is missing required field Y"] },
"status": 400
}

Check response["status"] (not HTTP status) to distinguish success from error:

  • status == 201 — workflow run was accepted and is executing
  • status == 400 or status == 422 — workflow structure error, run was not started

Polling pattern

Python — full run + poll
import time
import requests

API_KEY = "<Your API Key>"
WORKFLOW_ID = 6

# 1. Start the run
run_resp = requests.post(
f"https://scriptrun.ai/api/v1/workflows/{WORKFLOW_ID}/run/",
headers={"X-Api-Key": API_KEY, "Content-Type": "application/json"},
data='{"user_name": "John Doe"}',
)
run_body = run_resp.json()

if run_body.get("status") != 201:
raise RuntimeError(f"Workflow failed to start: {run_body}")

run_id = run_body["data"]["id"] # UUID string

# 2. Poll until complete
TERMINAL_STATUSES = {"succeed", "failed"}
for _ in range(60):
result_resp = requests.get(
"https://scriptrun.ai/api/v1/workflows/workflow_result/",
headers={"X-Api-Key": API_KEY},
params={"id": run_id},
)
result = result_resp.json()
executor_data = result.get("data", {})
current_status = executor_data.get("status")

if current_status in TERMINAL_STATUSES:
print("Done:", executor_data)
break

time.sleep(3)
else:
print("Timed out")

Get Workflow Run Result

GET /api/v1/workflows/workflow_result/

Summary: Retrieves the current status and result of a workflow run by its UUID. Use this endpoint for polling after calling /run/.

Python
import requests

url = "https://scriptrun.ai/api/v1/workflows/workflow_result/"
headers = {"X-Api-Key": "<Your API Key>"}
params = {"id": "0781b175-2135-45ec-9063-ad3e0d929adc"}

response = requests.get(url, headers=headers, params=params)
print(response.json())
Shell
curl -X GET "https://scriptrun.ai/api/v1/workflows/workflow_result/?id=0781b175-2135-45ec-9063-ad3e0d929adc" \
-H "X-Api-Key: <Your API Key>"

Parameters:

NameInTypeRequiredDescription
idquerystringYesUUID of the workflow run (from /run/ response data.id).

Full Response Schema

The endpoint returns HTTP 200 with the following structure:

{
"data": {
"id": "0781b175-2135-45ec-9063-ad3e0d929adc",
"status": "succeed",
"data": {
"93e9822b-63a4-4553-adb4-79029db3c09b": {
"id": "93e9822b-63a4-4553-adb4-79029db3c09b",
"status": "succeed",
"result": {
"content": "Hi! How can I help you today?"
}
},
"a7bf1234-0000-0000-0000-000000000001": {
"id": "a7bf1234-0000-0000-0000-000000000001",
"status": "succeed",
"result": {
"content": "{\"key\": \"value\"}"
}
}
},
"metrics": {
"total_cost": 0.0032
}
},
"status": 200
}

Top-level fields:

FieldTypeDescription
statusintegerHTTP status from executor. 200 = response delivered.
dataobjectExecutor response body. See nested fields below.

data object fields:

FieldTypeDescription
idstringUUID of the workflow run (same as the query parameter).
statusstringOverall run status. See allowed values below.
dataobjectPer-node results, keyed by node UUID (not node name).
metricsobjectOptional. Contains total_cost (float, USD) if available.

Allowed status Values

ValueMeaning
"in queue"Run is queued, execution has not started yet.
"in progress"Execution is active.
"succeed"Execution completed successfully. Results are ready.
"failed"Execution completed with an error.
"not found"No run found for this UUID. May be expired or invalid.

Terminal statuses (stop polling): "succeed", "failed".

Non-terminal statuses (continue polling): "in queue", "in progress".


Per-Node Result Object (data.data.<node-uuid>)

Each node UUID maps to:

FieldTypeDescription
idstringNode UUID (same as the key).
statusstringNode-level status. Same values as run-level status.
resultobjectNode output. Present only when node status is succeed.

result object:

FieldTypeDescription
contentstringNode output content. See result.content formats below.

Node Order

data.data is a JSON object keyed by node UUID, not an array. Node order is not guaranteed — do not rely on insertion order. To identify specific nodes, use their UUID (obtainable from GET /api/v1/workflows/{id}/data.nodes[].id).


Determining the Final Result

To reliably find the workflow's final output:

  1. Check that overall data.status == "succeed".
  2. Identify the output node(s) by type ("output-node") from the workflow's data.nodes array.
  3. Look up those node UUIDs in data.data and read their result.content.

Do not assume the last node in data.data is the output — iteration order is not stable.


Error Responses

HTTP StatusMeaning
400Missing id parameter, or workflow run not found / no access.
401Authentication credentials not provided.

result.content Formats

The result.content field is always a string, but its semantic content varies:

FormatExampleHow to handle
Plain text"Hello, world!"Use directly.
JSON string"{\"key\": \"value\"}"Parse with json.loads().
Markdown JSON code fence```json\n{"key": "value"}\n```Strip the fence, then parse JSON.
Python — robust content parser
import json
import re

def parse_content(content: str):
"""Parse result.content regardless of format."""
# Strip markdown code fence if present
fence_match = re.match(r"```(?:json)?\s*([\s\S]*?)\s*```", content.strip())
if fence_match:
content = fence_match.group(1)

try:
return json.loads(content)
except (json.JSONDecodeError, ValueError):
return content # plain text
note

The markdown code fence wrapping (```json ... ```) is a known quirk produced by certain LLM nodes. The API does not currently normalize this on the server side. Use the parser above on the client side.


Workflow Run History

GET /api/v1/workflows/{id}/history/

Summary: Retrieves the paginated run history for a specific workflow.

Python
import requests

url = "https://scriptrun.ai/api/v1/workflows/6/history/"
headers = {"X-Api-Key": "<Your API Key>"}
params = {"page_size": 10, "ordering": "-created_at"}

response = requests.get(url, headers=headers, params=params)
print(response.json())
Shell
curl -X GET "https://scriptrun.ai/api/v1/workflows/6/history/?page_size=10&ordering=-created_at" \
-H "X-Api-Key: <Your API Key>"

Parameters:

NameInTypeRequiredDescription
idpathintegerYesID of the workflow.
orderingquerystringNoSort field. Options: created_at, -created_at, cost, -cost.
pagequeryintegerNoPage number.
page_sizequeryintegerNoNumber of items per page.

Responses:

  • 200: Returns a paginated list of workflow run history items.
  • 404: Workflow not found.

Execution Update Webhook (internal)

POST /api/v1/workflows/execution-update/{workflow_run_id}/

This endpoint is called by the ScriptRun execution service — not by external API clients. It delivers live status updates and the final result of a workflow run to the Django backend.

Understanding this endpoint helps explain the temporal behavior described below.

Authentication: This endpoint uses an internal service API key (X-Service-Api-Key header). Requests from unauthorized sources are rejected with 403.

Path Parameter:

NameTypeDescription
workflow_run_idstringUUID of the workflow run.

Request Body:

{
"type": "workflow_execution_progress_change",
"payload": {
"id": "0781b175-2135-45ec-9063-ad3e0d929adc",
"status": "succeed",
"data": {
"93e9822b-63a4-4553-adb4-79029db3c09b": {
"id": "93e9822b-63a4-4553-adb4-79029db3c09b",
"status": "succeed",
"result": {
"content": "Hi! How can I help you today?"
}
}
}
}
}

Guaranteed fields in payload:

FieldTypeDescription
idstringWorkflow run UUID.
statusstringOverall run status: "succeed", "failed", "in progress", "in queue".
dataobjectPer-node results, keyed by node UUID.

Response:

{ "status": "created", "detail": { "msg": "ok" } }

Temporal Semantics: Polling After Status Update

Critical for client implementations

There is a known timing window between when the execution service marks a run as complete and when GET /workflow_result/ returns fully consistent data.

What this means:

  • The run status may transition to "succeed" or "failed" in the backend database slightly before the result data is fully persisted.
  • If you poll workflow_result immediately after detecting a "succeed" status, data.data may be partially populated or empty.

Recommended retry strategy:

  1. Poll workflow_result every 3–5 seconds while status is non-terminal.
  2. When status becomes "succeed" or "failed", verify that data.data is non-empty and contains the expected output nodes.
  3. If data.data is empty or missing expected nodes despite a terminal status, wait 2–3 seconds and retry (up to 3 retries).
  4. Only finalize your result after both conditions are true: terminal status AND non-empty data.data.
Python — robust polling with consistency check
import time
import requests

def poll_workflow_result(run_id: str, api_key: str, timeout_seconds: int = 180):
headers = {"X-Api-Key": api_key}
url = "https://scriptrun.ai/api/v1/workflows/workflow_result/"
terminal = {"succeed", "failed"}
deadline = time.time() + timeout_seconds

while time.time() < deadline:
resp = requests.get(url, headers=headers, params={"id": run_id})
body = resp.json()
data = body.get("data", {})
status = data.get("status")

if status in terminal:
node_results = data.get("data", {})
if node_results:
return data # fully consistent result
# Terminal but data not yet available — brief consistency window
time.sleep(2)
continue

time.sleep(3)

raise TimeoutError(f"Workflow run {run_id} did not complete within {timeout_seconds}s")

Workflow Data Structure

  • nodes: List of nodes, each containing:
    • id: Unique node UUID string (e.g. "3d63f846-0f6a-478c-b91c-5921259429c1").
    • type: Node type (e.g., "trigger-node", "basic-node", "output-node").
    • data: Node parameters (name, settings, schema, messages, etc.).
    • position, measured, selected, etc. — visualization parameters.
  • edges: List of connections between nodes, each containing:
    • id: Unique edge identifier.
    • source: Source node UUID.
    • target: Target node UUID.
    • type, style, markerEnd, markerStart, etc. — visualization parameters.
  • viewport: Viewport parameters (x, y, zoom).
  • start_node: UUID of the start node (usually the first action or trigger).

Summary

  • A Workflow is a visual process schema consisting of nodes and edges.
  • The API allows you to create, retrieve, update, and delete workflows.
  • Use GET /api/v1/workflows/{id}/input-fields/ to discover what inputs a workflow expects.
  • Use POST /api/v1/workflows/{id}/run/ to execute a workflow. Save response["data"]["id"] — this is the UUID for polling.
  • Use GET /api/v1/workflows/workflow_result/?id=<run_uuid> to poll for results. Poll until data.status is "succeed" or "failed".
  • Use GET /api/v1/workflows/{id}/history/ to view past runs.

Working with Input Data

Overview

When running a workflow via API key, send input data directly in the request body (flat format). Access it in nodes using {{ input.* }} variables.

Key Features:

  • ✅ Supports valid JSON objects (flat or nested)
  • ✅ Supports JSON arrays
  • ✅ Supports plain text (automatically wrapped)
  • ✅ Access data in nodes using {{ input.field_name }} syntax
  • ✅ Supports nested objects and arrays

Example 1: Object Input Data

Python
import requests

url = "https://scriptrun.ai/api/v1/workflows/6/run/"
headers = {"X-Api-Key": "<Your API Key>", "Content-Type": "application/json"}

import json
body = json.dumps({
"user_name": "John Doe",
"email": "john@example.com",
"age": 30,
"preferences": {
"theme": "dark",
"notifications": True
},
"tags": ["admin", "developer"]
})

response = requests.post(url, headers=headers, data=body)
print(response.json())
Shell
curl -X POST "https://scriptrun.ai/api/v1/workflows/6/run/" \
-H "X-Api-Key: <Your API Key>" \
-H "Content-Type: application/json" \
-d '{
"user_name": "John Doe",
"email": "john@example.com",
"age": 30,
"preferences": {
"theme": "dark",
"notifications": true
},
"tags": ["admin", "developer"]
}'

Accessing in nodes:

{{ input.user_name }}              → "John Doe"
{{ input.email }} → "john@example.com"
{{ input.age }} → 30
{{ input.preferences.theme }} → "dark"
{{ input.tags[0] }} → "admin"
{{ input.tags[1] }} → "developer"

Example 2: Array Input Data

Shell
curl -X POST "https://scriptrun.ai/api/v1/workflows/6/run/" \
-H "X-Api-Key: <Your API Key>" \
-H "Content-Type: application/json" \
-d '{
"data": [
{"id": 1, "name": "Alice", "role": "admin"},
{"id": 2, "name": "Bob", "role": "user"}
]
}'

Accessing in nodes:

{{ input.data[0].name }}     → "Alice"
{{ input.data[1].role }} → "user"
{{ input.data[0].id }} → 1

Example 3: Plain Text Input

Shell
curl -X POST "https://scriptrun.ai/api/v1/workflows/6/run/" \
-H "X-Api-Key: <Your API Key>" \
-H "Content-Type: text/plain" \
-d "Hello, this is a simple text input"

Accessing in nodes:

{{ input.__raw_input__ }}    → "Hello, this is a simple text input"

Plain text input is automatically wrapped as {"__raw_input__": "..."}. Access via {{ input.__raw_input__ }}.

Adding Variables in the Interface

To add a variable in the workflow node editor in the ScriptRun interface, use double curly braces {{ }}:

Input data variables (values passed when running the workflow via API):

{{ input.field_name }}
{{ input.nested.field }}
{{ input.array[0].field }}
{{ input.__raw_input__ }}

Node output variables (results from other nodes):

Each node has a UUID (visible in the workflow data.nodes[].id). Reference another node's output using:

{{ nodeId.result.content }}

Where nodeId is the UUID of the upstream node. For example:

{{ 93e9822b-63a4-4553-adb4-79029db3c09b.result.content }}

Structure of node output variables:

When the input for a node comes from another node via the API (e.g., when building dynamic chains), the output data from each node is available at:

{{ <nodeId>.result.content }}      → string output of that node
{{ <nodeId>.result.<field> }} → other fields in the node result

This is the same structure that appears in workflow_result response under data.data.<nodeId>.result.

Using Input Data in Nodes

In HTTP Node

{
"url": "https://api.example.com/users",
"method": "POST",
"headers": {
"Authorization": "Bearer {{ input.api_token }}",
"Content-Type": "application/json"
},
"body": {
"name": "{{ input.user_name }}",
"email": "{{ input.email }}",
"age": "{{ input.age }}"
}
}

In LLM Node

{
"messages": [
{
"role": "system",
"message": "You are a helpful assistant"
},
{
"role": "user",
"message": "Create a welcome message for {{ input.user_name }} with email {{ input.email }}"
}
]
}

Complex Example: Nested Structures

Python
import json
import requests

body = json.dumps({
"company": {
"name": "Acme Inc",
"departments": [
{
"name": "IT",
"employees": [
{"name": "Alice", "role": "Developer"},
{"name": "Bob", "role": "DevOps"}
]
},
{
"name": "HR",
"employees": [
{"name": "Charlie", "role": "Manager"}
]
}
]
}
})

response = requests.post(
"https://scriptrun.ai/api/v1/workflows/6/run/",
headers={"X-Api-Key": "<Your API Key>", "Content-Type": "application/json"},
data=body,
)

Accessing nested data in nodes:

{{ input.company.name }}                             → "Acme Inc"
{{ input.company.departments[0].name }} → "IT"
{{ input.company.departments[0].employees[0].name }} → "Alice"
{{ input.company.departments[0].employees[1].role }} → "DevOps"
{{ input.company.departments[1].employees[0].name }} → "Charlie"

Variable Syntax

ScriptRun supports flexible variable syntax for accessing input data:

SyntaxDescriptionExample
{{ input.field }}Access object field{{ input.user_name }}
{{ input.nested.field }}Access nested field{{ input.preferences.theme }}
{{ input[0] }}Access array element by index{{ input[0] }}
{{ input.users[0].name }}Access field in array element{{ input.users[0].name }}
{{ input.tags[1] }}Access nested array element{{ input.tags[1] }}
{{ nodeId.result.content }}Access another node's output{{ 93e9822b-....result.content }}

Both array notations are equivalent:

  • Dot notation: {{ input.tags.0 }}
  • Bracket notation: {{ input.tags[0] }}

Error Handling

Invalid JSON (API key mode):

  • Plain text or invalid JSON is automatically wrapped in {"__raw_input__": "text"}
  • Access it via {{ input.__raw_input__ }}

Missing Fields:

  • If a field doesn't exist, it returns an empty value
  • Example: {{ input.nonexistent_field }}{}

Empty Input:

  • If no input is provided, it defaults to {}

Best Practices

  1. Use descriptive field names: user_name instead of n
  2. Validate required fields: Use Trigger node with required input fields
  3. Keep structure consistent: Use the same data structure for similar workflows
  4. Test with sample data: Verify your variables work before running in production
  5. Handle result.content defensively: Always parse it — it may be plain text, JSON, or markdown-wrapped JSON (see result.content formats)
  6. Implement retry with backoff: When polling, use 3–5 second intervals and handle the brief consistency window after terminal status

Responses

  • 200: Workflow execution started successfully (check inner status field)
  • 400: Invalid input data or workflow structure
  • 404: Workflow not found