Перейти к основному содержимому

Документация Workflow API

Workflow в ScriptRun — это визуальное представление процесса или автоматизации. Он состоит из связанных между собой узлов (шаги, триггеры, действия, выходы) и рёбер (соединения между узлами), что позволяет проектировать и выполнять сложную логику.

Ключевые понятия

  • Workflow: схема, состоящая из узлов и рёбер, определяющая последовательность действий.
  • Node (узел): шаг процесса (например, триггер, запрос к LLM, обработка данных, вывод). Каждый узел имеет уникальный идентификатор UUID.
  • Edge (ребро): соединяет два узла, определяя направление потока.
  • Data (данные): структура, описывающая все узлы, рёбра, начальный узел и параметры viewport.
  • WorkflowRun: отдельный экземпляр выполнения workflow. Имеет собственный UUID, статус и результат.

Пример структуры данных Workflow

Пример ниже основан на реальном workflow: Триггер → If/Else → две ветки LLM.

{
"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"
}
}

Как читать этот пример:

  • start_node — UUID первого узла для выполнения (Trigger).
  • edges — соединения между узлами. sourcetarget. Для if-else-node поле sourceHandle указывает, какая ветка используется (condition-true / condition-false).
  • nodes[].type — тип узла на фронтенде, используемый для рендеринга: trigger-node, if-else-node, basic-node, http-node и т.д. Примечание: это отличается от поля node_type, возвращаемого GET /api/v1/workflows/get_nodes/, которое использует имена классов схемы исполнителя (например, "TriggerNode", "HTTPNodeInput").
  • nodes[].data.input_fields — поля, объявленные в узле Trigger. Они сопоставляются с переменными {{ input.<field_id> }} по всему workflow.
  • nodes[].data.condition — для if-else-node: сравнивает left и right с помощью operator. Поддерживаются ==, !=, >, <, >=, <=.
  • nodes[].data.messages — для узлов LLM: массив сообщений промпта (роли system + user).
  • nodes[].data.next_nodes — список UUID последующих узлов.

Эндпоинты API

Создание 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/

Описание: Создаёт новый workflow.

Тело запроса:

НазваниеТипОбязательныйОписание
projectintegerДаID проекта, к которому относится workflow.
titlestringДаНазвание workflow.
dataobjectДаСтруктура workflow (узлы, рёбра, viewport)

Ответы:

  • 201: Workflow успешно создан.
  • 400: Некорректные входные данные или отсутствуют обязательные параметры.

Получение списка Workflow

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/

Описание: Возвращает список workflow, опционально отфильтрованный по проекту.

Параметры:

НазваниеГдеТипОбязательныйОписание
projectqueryintegerНетФильтрация workflow по ID проекта.
titlequerystringНетФильтрация по названию workflow (без учёта регистра).
pagequeryintegerНетНомер страницы для пагинации.

Ответы:

  • 200: Возвращает список workflow с пагинацией.

Получение конкретного 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}/

Описание: Возвращает подробную информацию о конкретном workflow по его ID.

Параметры:

НазваниеГдеТипОбязательныйОписание
idpathintegerДаID запрашиваемого workflow.

Ответы:

  • 200: Возвращает подробную информацию о workflow.
  • 404: Workflow не найден.

Обновление 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}/

Описание: Обновляет существующий workflow.

Параметры:

НазваниеГдеТипОбязательныйОписание
idpathintegerДаID обновляемого workflow.

Тело запроса:

НазваниеТипОбязательныйОписание
titlestringНетОбновлённое название workflow.
dataobjectНетОбновлённая структура workflow.

Ответы:

  • 200: Workflow успешно обновлён.
  • 404: Workflow не найден.

Удаление 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}/

Описание: Удаляет конкретный workflow по его ID.

Параметры:

НазваниеГдеТипОбязательныйОписание
idpathintegerДаID удаляемого workflow.

Ответы:

  • 204: Workflow успешно удалён.
  • 404: Workflow не найден.

Дополнительные эндпоинты Workflow

Получение полей ввода Workflow

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

Описание: Возвращает список полей ввода, определённых в узле Trigger workflow. Используйте это, чтобы узнать, какие параметры ожидает workflow перед его запуском.

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>"

Параметры:

НазваниеГдеТипОбязательныйОписание
idpathintegerДаID workflow.

Ответ (200):

Возвращает массив объектов полей ввода:

ПолеТипОписание
idstringИдентификатор поля (используется как ключ в данных ввода).
titlestringЧеловекочитаемая подпись поля.
typestringТип поля (например, text, select, number).
input_requirementsbooleanЯвляется ли поле обязательным.
placeholderstringТекст-подсказка для поля.
tooltipstringВспомогательный текст, показываемый пользователю.
default_valuestringЗначение по умолчанию, если не задано.
optionsarrayДоступные варианты для полей типа select.

Пример ответа:

[
{
"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}
]
}
]

Проверка структуры Workflow

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

Описание: Проверяет структуру сохранённого 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>"

Параметры:

НазваниеГдеТипОбязательныйОписание
idpathintegerДаID workflow.

Ответы:

  • 200: Результат проверки возвращён.
  • 404: Workflow не найден.

Получение схем узлов для фронтенда

GET /api/v1/workflows/get_nodes/

Описание: Возвращает доступные схемы узлов для рендеринга и настройки на фронтенде.

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>"

Обнаружение MCP-инструментов

POST /api/v1/workflows/mcp-tools/

Описание: Подключается к серверу MCP (Model Context Protocol) и возвращает список инструментов, которые он предоставляет. Используйте это, чтобы узнать доступные инструменты перед настройкой узла MCP в workflow.

Python
import requests

url = "https://scriptrun.ai/api/v1/workflows/mcp-tools/"
headers = {"X-Api-Key": "<Your API Key>", "Content-Type": "application/json"}
data = {
"endpoint_url": "https://mcp.example.com/sse",
"transport": "auto"
}

response = requests.post(url, headers=headers, json=data)
print(response.json())
Shell
curl -X POST "https://scriptrun.ai/api/v1/workflows/mcp-tools/" \
-H "X-Api-Key: <Your API Key>" \
-H "Content-Type: application/json" \
-d '{
"endpoint_url": "https://mcp.example.com/sse",
"transport": "auto"
}'

Тело запроса:

НазваниеТипОбязательныйОписание
endpoint_urlstringДаURL сервера MCP, к которому нужно подключиться.
transportstringНетТранспортный протокол: auto (по умолчанию), sse или streamable_http.
headersobjectНетДополнительные HTTP-заголовки для отправки серверу MCP (например, для аутентификации).
timeoutnumberНетТаймаут соединения в секундах (0.130.0, по умолчанию 10.0).
workflow_idintegerНетСуществующий workflow, из которого нужно получить сохранённую конфигурацию MCP. Должен передаваться вместе с node_id.
node_idstringНетUUID узла в рамках workflow_id, из которого нужно получить сохранённую конфигурацию MCP.

Ответы:

  • 200: Возвращает список инструментов, предоставляемых сервером MCP.
  • 400: Ошибка валидации (например, workflow_id и node_id должны передаваться вместе).

Запуск Workflow

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

Описание: Запускает выполнение конкретного workflow. Опционально можно передать входные данные для параметризации запуска.


Формат запроса: два режима

Эндпоинт /run/ ведёт себя по-разному в зависимости от используемого метода аутентификации. Оба режима официально поддерживаются. Отказ от поддержки ни одного из форматов не планируется.

Режим 1 — API-ключ (заголовок X-Api-Key): плоское тело (канонический вариант для API-интеграций)

При аутентификации по API-ключу отправляйте входные данные напрямую как тело запроса — в виде сырой JSON-строки или обычного текста. Не оборачивайте в input_data.

Это рекомендуемый формат для всех API-интеграций.

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"}'

Обычный текст также принимается:

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"

Режим 2 — JWT (фронтенд / сессия): обёртка input_data

При аутентификации через JWT (пользовательские сессии) оборачивайте входные данные в 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())

Сводка формата запроса по методу аутентификации:

Метод аутентификацииФормат тела запросаContent-Type
Заголовок X-Api-KeyСырая JSON-строка или обычный текст (плоский формат)application/json или text/plain
JWT Bearer token{"input_data": { ... }}application/json

Параметры

НазваниеГдеТипОбязательныйОписание
idpathintegerДаID запускаемого workflow.

Ответ (200)

Эндпоинт возвращает HTTP 200 с телом JSON в следующем формате:

{
"data": {
"id": "0781b175-2135-45ec-9063-ad3e0d929adc",
"status": "in queue",
"data": null
},
"status": 201
}
ПолеТипОписание
statusintegerHTTP-статус, возвращённый сервисом выполнения. 201 = принято и запущено.
dataobjectТело ответа сервиса выполнения.
data.idstring (UUID)Идентификатор WorkflowRun. Сохраните его — используется для опроса через GET /workflow_result/?id=<uuid>.
data.statusstringНачальный статус запуска. Всегда "in queue" для только что принятого запуска.
data.datanullВсегда null в ответе /run/. Данные результата получаются через GET /workflow_result/.
important

data.id — это строка UUID (например, "0781b175-2135-45ec-9063-ad3e0d929adc"), не целое число. Не сравнивайте с ID workflow.

Ответ с ошибкой (ошибка валидации узла):

Когда узел workflow не проходит валидацию (например, отсутствует обязательное поле), эндпоинт возвращает HTTP 200 с внутренним status: 422 и структурой ошибок по каждому узлу:

{
"data": {
"id": "0781b175-2135-45ec-9063-ad3e0d929adc",
"status": "failed",
"data": {
"9919a3fd-7e59-439c-b918-3ee5977654b5": {
"id": "9919a3fd-7e59-439c-b918-3ee5977654b5",
"status": "failed",
"result": [
{"messages.0.message": "String should have at least 1 character"}
]
}
}
},
"status": 422
}

Проверяйте response["status"] (не HTTP-статус), чтобы отличить успех от ошибки:

  • status == 201 — запуск workflow принят и выполняется
  • status == 422 — ошибка валидации узла, запуск не был начат (data.data содержит ошибки по каждому узлу)
  • status == 400 — структурная ошибка (некорректный JSON workflow)

Паттерн опроса (polling)

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")

Получение результата запуска Workflow

GET /api/v1/workflows/workflow_result/

Описание: Возвращает текущий статус и результат запуска workflow по его UUID. Используйте этот эндпоинт для опроса после вызова /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>"

Параметры:

НазваниеГдеТипОбязательныйОписание
idquerystringДаUUID запуска workflow (из поля data.id ответа /run/).

Полная схема ответа

Эндпоинт возвращает HTTP 200 со следующей структурой:

{
"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\"}"
}
}
}
},
"status": 200
}

Поля верхнего уровня:

ПолеТипОписание
statusintegerHTTP-статус от исполнителя. 200 = ответ доставлен.
dataobjectТело ответа исполнителя. См. вложенные поля ниже.

Поля объекта data:

ПолеТипОписание
idstringUUID запуска workflow (совпадает с параметром запроса).
statusstringОбщий статус запуска. См. допустимые значения ниже.
dataobjectРезультаты по каждому узлу, ключом служит UUID узла (не название узла).

Допустимые значения status

ЗначениеСмысл
"in queue"Запуск в очереди, выполнение ещё не началось.
"in progress"Выполнение активно.
"succeed"Выполнение успешно завершено. Результаты готовы.
"failed"Выполнение завершилось с ошибкой.
"not found"Запуск с таким UUID не найден. Возможно, истёк срок или неверный UUID.

Терминальные статусы (остановить опрос): "succeed", "failed".

Нетерминальные статусы (продолжать опрос): "in queue", "in progress".


Объект результата по узлу (data.data.<node-uuid>)

Каждый UUID узла сопоставляется с:

ПолеТипОписание
idstringUUID узла (совпадает с ключом).
statusstringСтатус на уровне узла. Те же значения, что и статус запуска.
resultobjectВывод узла. Присутствует только когда статус узла succeed.

Объект result:

ПолеТипОписание
contentstringСодержимое вывода узла. См. форматы result.content ниже.

Порядок узлов

data.data — это JSON-объект с ключом по UUID узла, а не массив. Порядок узлов не гарантирован — не полагайтесь на порядок вставки. Чтобы идентифицировать конкретные узлы, используйте их UUID (можно получить через GET /api/v1/workflows/{id}/data.nodes[].id).


Определение итогового результата

Убедитесь, что общий data.status == "succeed", прежде чем читать результаты. Только тогда результаты узлов в data.data являются финальными.

Не предполагайте, что последний ключ в data.data — это выходной узел — порядок итерации нестабилен. Используйте UUID узлов из определения workflow (GET /api/v1/workflows/{id}/), чтобы идентифицировать конкретные узлы.


Ответы с ошибками

HTTP-статусЗначение
400Отсутствует параметр id, или запуск не найден в базе данных / нет доступа.
401Не предоставлены учётные данные аутентификации.
примечание

Если запуск существует в базе данных, но у исполнителя нет для него результата (истёк срок или ещё не сохранён), эндпоинт возвращает HTTP 200 с data.status: "not found" и data.data: null — это не HTTP-ошибка. Рассматривайте "not found" как нетерминальный статус и повторяйте запрос после небольшой задержки.


Форматы result.content

Поле result.content всегда является строкой, но его смысловое содержимое может отличаться:

ФорматПримерКак обрабатывать
Обычный текст"Hello, world!"Использовать напрямую.
JSON-строка"{\"key\": \"value\"}"Распарсить с помощью json.loads().
Markdown JSON code fence```json\n{"key": "value"}\n```Убрать обрамление, затем распарсить 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
примечание

Обрамление markdown-блоком кода (```json ... ```) — известная особенность, встречающаяся у некоторых узлов LLM. В настоящее время API не нормализует это на стороне сервера. Используйте приведённый выше парсер на стороне клиента.


История запусков Workflow

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

Описание: Возвращает историю запусков конкретного 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>"

Параметры:

НазваниеГдеТипОбязательныйОписание
idpathintegerДаID workflow.
orderingquerystringНетПоле сортировки. Варианты: created_at, -created_at, cost, -cost.
pagequeryintegerНетНомер страницы.
page_sizequeryintegerНетКоличество элементов на странице.

Ответы:

  • 200: Возвращает историю запусков workflow с пагинацией.
  • 404: Workflow не найден.

Повторный запуск Workflow

POST /api/v1/workflows/{id}/history/{run_id}/re-run/

Описание: Создаёт и запускает новый запуск workflow на основе предыдущего запуска. Полезно для повторных попыток неудавшихся запусков или повторного выполнения с теми же или обновлёнными входными данными.

Python (API Key — re-run with new input)
import requests

url = "https://scriptrun.ai/api/v1/workflows/6/history/11122222-4444-4444-8888-a2134dc8854f/re-run/"
headers = {
"X-Api-Key": "<Your API Key>",
"Content-Type": "application/json",
}
# Optionally provide new input data; omit body to reuse the original input
body = '{"user_name": "Jane Doe"}'

response = requests.post(url, headers=headers, data=body)
print(response.json())
Shell
curl -X POST "https://scriptrun.ai/api/v1/workflows/6/history/d2d20381-85c5-4a2d-8680-a2134dc8854f/re-run/" \
-H "X-Api-Key: <Your API Key>" \
-H "Content-Type: application/json" \
-d '{"user_name": "Jane Doe"}'

Параметры:

НазваниеГдеТипОбязательныйОписание
idpathintegerДаID workflow.
run_idpathstringДаUUID существующего запуска workflow.

Тело запроса: тот же формат, что и POST /run/ — плоское тело JSON (API-ключ) или {"input_data": {...}} (JWT). Если не указано, используются входные данные исходного запуска.

Ответ (201):

Та же структура, что и POST /run/:

{
"data": {
"id": "new-run-uuid-here",
"status": "in queue",
"data": null
},
"status": 201
}

Используйте data.id для опроса результатов через GET /workflow_result/.

Ответы:

  • 201: Новый запуск workflow создан и отправлен.
  • 400: Ошибка валидации.
  • 404: Workflow или исходный запуск не найден.

Временная семантика: опрос после обновления статуса

Critical for client implementations

Существует известное временное окно между моментом, когда сервис выполнения помечает запуск как завершённый, и моментом, когда GET /workflow_result/ возвращает полностью согласованные данные.

Что это значит:

  • Статус запуска может перейти в "succeed" или "failed" в базе данных бэкенда чуть раньше, чем данные результата будут полностью сохранены.
  • Если вы опрашиваете workflow_result сразу после обнаружения статуса "succeed", data.data может быть частично заполнен или пуст.

Рекомендуемая стратегия повторных попыток:

  1. Опрашивайте workflow_result каждые 3–5 секунд, пока статус нетерминальный.
  2. Когда статус становится "succeed" или "failed", убедитесь, что data.data не пуст и содержит ожидаемые выходные узлы.
  3. Если data.data пуст или не содержит ожидаемых узлов, несмотря на терминальный статус, подождите 2–3 секунды и повторите попытку (до 3 повторов).
  4. Финализируйте результат только после выполнения обоих условий: терминальный статус И непустой 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

  • nodes: список узлов, каждый из которых содержит:
    • id: уникальная строка UUID узла (например, "3d63f846-0f6a-478c-b91c-5921259429c1").
    • type: тип узла на фронтенде (например, "trigger-node", "basic-node", "if-else-node", "http-node"). Это типы для рендеринга UI — они не совпадают с именами схем исполнителя ("TriggerNode", "HTTPNodeInput" и т.д.), возвращаемыми GET /api/v1/workflows/get_nodes/.
    • data: параметры узла (название, настройки, схема, сообщения и т.д.).
    • position, measured, selected и т.д. — параметры визуализации.
  • edges: список соединений между узлами, каждое из которых содержит:
    • id: уникальный идентификатор ребра.
    • source: UUID исходного узла.
    • target: UUID целевого узла.
    • type, style, markerEnd, markerStart и т.д. — параметры визуализации.
  • viewport: параметры viewport (x, y, zoom).
  • start_node: UUID начального узла (обычно первое действие или триггер).

Резюме

  • Workflow — это визуальная схема процесса, состоящая из узлов и рёбер.
  • API позволяет создавать, получать, обновлять и удалять workflow.
  • Используйте GET /api/v1/workflows/{id}/input-fields/, чтобы узнать, какие входные данные ожидает workflow.
  • Используйте POST /api/v1/workflows/{id}/run/ для выполнения workflow. Сохраните response["data"]["id"] — это UUID для опроса.
  • Используйте GET /api/v1/workflows/workflow_result/?id=<run_uuid> для опроса результатов. Опрашивайте, пока data.status не станет "succeed" или "failed".
  • Используйте GET /api/v1/workflows/{id}/history/, чтобы просмотреть прошлые запуски.

Работа с входными данными

Обзор

При запуске workflow через API-ключ отправляйте входные данные напрямую в теле запроса (плоский формат). Обращайтесь к ним в узлах с помощью переменных {{ input.* }}.

Ключевые возможности:

  • ✅ Поддержка валидных JSON-объектов (плоских или вложенных)
  • ✅ Поддержка JSON-массивов
  • ✅ Поддержка обычного текста (автоматически оборачивается)
  • ✅ Доступ к данным в узлах через синтаксис {{ input.field_name }}
  • ✅ Поддержка вложенных объектов и массивов

Пример 1: входные данные в виде объекта

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"]
}'

Доступ в узлах:

{{ 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"

Пример 2: входные данные в виде массива

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"}
]
}'

Доступ в узлах:

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

Пример 3: обычный текст как входные данные

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"

Доступ в узлах:

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

Обычный текст автоматически оборачивается в {"__raw_input__": "..."}. Доступ через {{ input.__raw_input__ }}.

Добавление переменных в интерфейсе

Чтобы добавить переменную в редакторе узлов workflow в интерфейсе ScriptRun, используйте двойные фигурные скобки {{ }}:

Переменные входных данных (значения, передаваемые при запуске workflow через API):

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

Переменные вывода узлов (результаты от других узлов):

Каждый узел имеет UUID (виден в data.nodes[].id workflow). Обращайтесь к выводу другого узла с помощью:

{{ nodeId.result.content }}

Где nodeId — это UUID вышестоящего узла. Например:

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

Структура переменных вывода узла:

Когда входные данные для узла поступают от другого узла через API (например, при построении динамических цепочек), выходные данные каждого узла доступны по адресу:

{{ <nodeId>.result.content }}      → строковый вывод этого узла
{{ <nodeId>.result.<field> }} → другие поля в результате узла

Это та же структура, что появляется в ответе workflow_result в data.data.<nodeId>.result.

Использование входных данных в узлах

В узле HTTP

{
"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 }}"
}
}

В узле LLM

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

Сложный пример: вложенные структуры

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,
)

Доступ к вложенным данным в узлах:

{{ 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"

Синтаксис переменных

ScriptRun поддерживает гибкий синтаксис переменных для доступа к входным данным:

СинтаксисОписаниеПример
{{ input.field }}Доступ к полю объекта{{ input.user_name }}
{{ input.nested.field }}Доступ к вложенному полю{{ input.preferences.theme }}
{{ input[0] }}Доступ к элементу массива по индексу{{ input[0] }}
{{ input.users[0].name }}Доступ к полю в элементе массива{{ input.users[0].name }}
{{ input.tags[1] }}Доступ к вложенному элементу массива{{ input.tags[1] }}
{{ nodeId.result.content }}Доступ к выводу другого узла{{ 93e9822b-....result.content }}

Обе записи для массивов эквивалентны:

  • Через точку: {{ input.tags.0 }}
  • Через скобки: {{ input.tags[0] }}

Обработка ошибок

Некорректный JSON (режим API-ключа):

  • Обычный текст или некорректный JSON автоматически оборачивается в {"__raw_input__": "text"}
  • Доступ через {{ input.__raw_input__ }}

Отсутствующие поля:

  • Если поле не существует, возвращается пустое значение
  • Пример: {{ input.nonexistent_field }}{}

Пустой ввод:

  • Если входные данные не переданы, по умолчанию используется {}

Рекомендации

  1. Используйте описательные названия полей: user_name вместо n
  2. Валидируйте обязательные поля: используйте узел Trigger с обязательными полями ввода
  3. Сохраняйте единообразие структуры: используйте одну и ту же структуру данных для похожих workflow
  4. Тестируйте на примерах данных: убедитесь, что ваши переменные работают, прежде чем запускать в продакшене
  5. Обрабатывайте result.content защищённо: всегда парсите его — он может быть обычным текстом, JSON или JSON, обёрнутым в markdown (см. форматы result.content)
  6. Реализуйте повторные попытки с задержкой: при опросе используйте интервалы 3–5 секунд и учитывайте короткое окно согласованности после терминального статуса

Ответы

  • 200: Выполнение workflow успешно запущено (проверьте внутреннее поле status)
  • 400: Некорректные входные данные или структура workflow
  • 404: Workflow не найден