Документация 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— соединения между узлами.source→target. Для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
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())
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.
Тело запроса:
| Название | Тип | Обязательный | Описание |
|---|---|---|---|
project | integer | Да | ID проекта, к которому относится workflow. |
title | string | Да | Название workflow. |
data | object | Да | Структура workflow (узлы, рёбра, viewport) |
Ответы:
- 201: Workflow успешно создан.
- 400: Некорректные входные данные или отсутствуют обязательные параметры.
Получение списка Workflow
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())
curl -X GET "https://scriptrun.ai/api/v1/workflows/?project=307" \
-H "X-Api-Key: <Your API Key>"
GET /api/v1/workflows/
Описание: Возвращает список workflow, опционально отфильтрованный по проекту.
Параметры:
| Название | Где | Тип | Обязательный | Описание |
|---|---|---|---|---|
project | query | integer | Нет | Фильтрация workflow по ID проекта. |
title | query | string | Нет | Фильтрация по названию workflow (без учёта регистра). |
page | query | integer | Нет | Номер страницы для пагинации. |
Ответы:
- 200: Возвращает список workflow с пагинацией.
Получение конкретного Workflow
url = "https://scriptrun.ai/api/v1/workflows/6/"
headers = {"X-Api-Key": "<Your API Key>"}
response = requests.get(url, headers=headers)
print(response.json())
curl -X GET "https://scriptrun.ai/api/v1/workflows/6/" \
-H "X-Api-Key: <Your API Key>"
GET /api/v1/workflows/{id}/
Описание: Возвращает подробную информацию о конкретном workflow по его ID.
Параметры:
| Название | Где | Тип | Обязательный | Описание |
|---|---|---|---|---|
id | path | integer | Да | ID запрашиваемого workflow. |
Ответы:
- 200: Возвращает подробную информацию о workflow.
- 404: Workflow не найден.
Обновление Workflow
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())
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.
Параметры:
| Название | Где | Тип | Обязательный | Описание |
|---|---|---|---|---|
id | path | integer | Да | ID обновляемого workflow. |
Тело запроса:
| Название | Тип | Обязательный | Описание |
|---|---|---|---|
title | string | Нет | Обновлённое название workflow. |
data | object | Нет | Обновлённая структура workflow. |
Ответы:
- 200: Workflow успешно обновлён.
- 404: Workflow не найден.
Удаление Workflow
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)
curl -X DELETE "https://scriptrun.ai/api/v1/workflows/6/" \
-H "X-Api-Key: <Your API Key>"
DELETE /api/v1/workflows/{id}/
Описание: Удаляет конкретный workflow по его ID.
Параметры:
| Название | Где | Тип | Обязательный | Описание |
|---|---|---|---|---|
id | path | integer | Да | ID удаляемого workflow. |
Ответы:
- 204: Workflow успешно удалён.
- 404: Workflow не найден.
Дополнительные эндпоинты Workflow
Получение полей ввода Workflow
GET /api/v1/workflows/{id}/input-fields/
Описание: Возвращает список полей ввода, определённых в узле Trigger workflow. Используйте это, чтобы узнать, какие параметры ожидает workflow перед его запуском.
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())
curl -X GET "https://scriptrun.ai/api/v1/workflows/271/input-fields/" \
-H "X-Api-Key: <Your API Key>"
Параметры:
| Название | Где | Тип | Обязательный | Описание |
|---|---|---|---|---|
id | path | integer | Да | ID workflow. |
Ответ (200):
Возвращает массив объектов полей ввода:
| Поле | Тип | Описание |
|---|---|---|
id | string | Идентификатор поля (используется как ключ в данных ввода). |
title | string | Человекочитаемая подпись поля. |
type | string | Тип поля (например, text, select, number). |
input_requirements | boolean | Является ли поле обязательным. |
placeholder | string | Текст-подсказка для поля. |
tooltip | string | Вспомогательный текст, показываемый пользователю. |
default_value | string | Значение по умолчанию, если не задано. |
options | array | Доступные варианты для полей типа 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.
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())
curl -X GET "https://scriptrun.ai/api/v1/workflows/6/check_workflow/" \
-H "X-Api-Key: <Your API Key>"
Параметры:
| Название | Где | Тип | Обязательный | Описание |
|---|---|---|---|---|
id | path | integer | Да | ID workflow. |
Ответы:
- 200: Результат проверки возвращён.
- 404: Workflow не найден.
Получение схем узлов для фронтенда
GET /api/v1/workflows/get_nodes/
Описание: Возвращает доступные схемы узлов для рендеринга и настройки на фронтенде.
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())
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.
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())
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_url | string | Да | URL сервера MCP, к которому нужно подключиться. |
transport | string | Нет | Транспортный протокол: auto (по умолчанию), sse или streamable_http. |
headers | object | Нет | Дополнительные HTTP-заголовки для отправки серверу MCP (например, для аутентификации). |
timeout | number | Нет | Таймаут соединения в секундах (0.1–30.0, по умолчанию 10.0). |
workflow_id | integer | Нет | Существующий workflow, из которого нужно получить сохранённую конфигурацию MCP. Должен передаваться вместе с node_id. |
node_id | string | Нет | 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-интеграций.
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())
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"}'
Обычный текст также принимается:
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:
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 |
Параметры
| Название | Где | Тип | Обязательный | Описание |
|---|---|---|---|---|
id | path | integer | Да | ID запускаемого workflow. |
Ответ (200)
Эндпоинт возвращает HTTP 200 с телом JSON в следующем формате:
{
"data": {
"id": "0781b175-2135-45ec-9063-ad3e0d929adc",
"status": "in queue",
"data": null
},
"status": 201
}
| Поле | Тип | Описание |
|---|---|---|
status | integer | HTTP-статус, возвращённый сервисом выполнения. 201 = принято и запущено. |
data | object | Тело ответа сервиса выполнения. |
data.id | string (UUID) | Идентификатор WorkflowRun. Сохраните его — используется для опроса через GET /workflow_result/?id=<uuid>. |
data.status | string | Начальный статус запуска. Всегда "in queue" для только что принятого запуска. |
data.data | null | Всегда null в ответе /run/. Данные результата получаются через GET /workflow_result/. |
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)
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/.
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())
curl -X GET "https://scriptrun.ai/api/v1/workflows/workflow_result/?id=0781b175-2135-45ec-9063-ad3e0d929adc" \
-H "X-Api-Key: <Your API Key>"
Параметры:
| Название | Где | Тип | Обязательный | Описание |
|---|---|---|---|---|
id | query | string | Да | 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
}
Поля верхнего уровня:
| Поле | Тип | Описание |
|---|---|---|
status | integer | HTTP-статус от исполнителя. 200 = ответ доставлен. |
data | object | Тело ответа исполнителя. См. вложенные поля ниже. |
Поля объекта data:
| Поле | Тип | Описание |
|---|---|---|
id | string | UUID запуска workflow (совпадает с параметром запроса). |
status | string | Общий статус запуска. См. допустимые значения ниже. |
data | object | Результаты по каждому узлу, ключом служит UUID узла (не название узла). |
Допустимые значения status
| Значение | Смысл |
|---|---|
"in queue" | Запуск в очереди, выполнение ещё не началось. |
"in progress" | Выполнение активно. |
"succeed" | Выполнение успешно завершено. Результаты готовы. |
"failed" | Выполнение завершилось с ошибкой. |
"not found" | Запуск с таким UUID не найден. Возможно, истёк срок или неверный UUID. |
Терминальные статусы (остановить опрос): "succeed", "failed".
Нетерминальные статусы (продолжать опрос): "in queue", "in progress".
Объект результата по узлу (data.data.<node-uuid>)
Каждый UUID узла сопоставляется с:
| Поле | Тип | Описание |
|---|---|---|
id | string | UUID узла (совпадает с ключом). |
status | string | Статус на уровне узла. Те же значения, что и статус запуска. |
result | object | Вывод узла. Присутствует только когда статус узла succeed. |
Объект result:
| Поле | Тип | Описание |
|---|---|---|
content | string | Содержимое вывода узла. См. форматы 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. |
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 с пагинацией.
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())
curl -X GET "https://scriptrun.ai/api/v1/workflows/6/history/?page_size=10&ordering=-created_at" \
-H "X-Api-Key: <Your API Key>"
Параметры:
| Название | Где | Тип | Обязательный | Описание |
|---|---|---|---|---|
id | path | integer | Да | ID workflow. |
ordering | query | string | Нет | Поле сортировки. Варианты: created_at, -created_at, cost, -cost. |
page | query | integer | Нет | Номер страницы. |
page_size | query | integer | Нет | Количество элементов на странице. |
Ответы:
- 200: Возвращает историю запусков workflow с пагинацией.
- 404: Workflow не найден.
Повторный запуск Workflow
POST /api/v1/workflows/{id}/history/{run_id}/re-run/
Описание: Создаёт и запускает новый запуск workflow на основе предыдущего запуска. Полезно для повторных попыток неудавшихся запусков или повторного выполнения с теми же или обновлёнными входными данными.
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())
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"}'
Параметры:
| Название | Где | Тип | Обязательный | Описание |
|---|---|---|---|---|
id | path | integer | Да | ID workflow. |
run_id | path | string | Да | 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 или исходный запуск не найден.
Временная семантика: опрос после обновления статуса
Существует известное временное окно между моментом, когда сервис выполнения помечает запуск как завершённый, и моментом, когда GET /workflow_result/ возвращает полностью согласованные данные.
Что это значит:
- Статус запуска может перейти в
"succeed"или"failed"в базе данных бэкенда чуть раньше, чем данные результата будут полностью сохранены. - Если вы опрашиваете
workflow_resultсразу после обнаружения статуса"succeed",data.dataможет быть частично заполнен или пуст.
Рекомендуемая стратегия повторных попыток:
- Опрашивайте
workflow_resultкаждые 3–5 секунд, пока статус нетерминальный. - Когда статус становится
"succeed"или"failed", убедитесь, чтоdata.dataне пуст и содержит ожидаемые выходные узлы. - Если
data.dataпуст или не содержит ожидаемых узлов, несмотря на терминальный статус, подождите 2–3 секунды и повторите попытку (до 3 повторов). - Финализируйте результат только после выполнения обоих условий: терминальный статус И непустой
data.data.
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: входные данные в виде объекта
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())
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: входные данные в виде массива
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: обычный текст как входные данные
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 }}"
}
]
}
Сложный пример: вложенные структуры
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 }}→{}
Пустой ввод:
- Если входные данные не переданы, по умолчанию используется
{}
Рекомендации
- Используйте описательные названия полей:
user_nameвместоn - Валидируйте обязательные поля: используйте узел Trigger с обязательными полями ввода
- Сохраняйте единообразие структуры: используйте одну и ту же структуру данных для похожих workflow
- Тестируйте на примерах данных: убедитесь, что ваши переменные работают, прежде чем запускать в продакшене
- Обрабатывайте
result.contentзащищённо: всегда парсите его — он может быть обычным текстом, JSON или JSON, обёрнутым в markdown (см. форматы result.content) - Реализуйте повторные попытки с задержкой: при опросе используйте интервалы 3–5 секунд и учитывайте короткое окно согласованности после терминального статуса
Ответы
- 200: Выполнение workflow успешно запущено (проверьте внутреннее поле
status) - 400: Некорректные входные данные или структура workflow
- 404: Workflow не найден