Workflows
The Workflows API lets you build deterministic, DAG-based pipelines from blocks and edges. You can create workflows programmatically, run them synchronously or asynchronously, inspect runs and logs, and import or export workflow definitions as YAML.
All workflow routes are API-key authenticated and scoped to the organization that owns the key.
Note: Dashboard users can also manage workflows through the organization-scoped routes at
/v1/organizations/\{org_id\}/workflows. The routes below are the public API-key surface.
Authentication
Section titled “Authentication”Every request must include a Bearer API key:
curl -H "Authorization: Bearer $SCHIFT_API_KEY" \ https://api.schift.io/v1/workflowsBase URL
Section titled “Base URL”All workflow endpoints are hosted under:
https://api.schift.io/v1/workflowsWorkflow model
Section titled “Workflow model”A workflow is a directed acyclic graph (DAG) made of blocks and edges.
| Field | Type | Description |
|---|---|---|
id | string | Workflow identifier. |
name | string | Human-readable name. |
description | string | Optional description. |
status | string | draft, published, or archived. |
graph.nodes | array | Blocks in the workflow. |
graph.edges | array | Connections between blocks. |
created_at | string | ISO 8601 timestamp. |
updated_at | string | ISO 8601 timestamp. |
POST /v1/workflows
Section titled “POST /v1/workflows”Create a new workflow. You can start from a blank graph or from a built-in template.
Request body
Section titled “Request body”| Parameter | Type | Required | Description |
|---|---|---|---|
name | string | Yes | Workflow name. |
description | string | No | Optional description. |
template | string | No | One of the built-in template IDs. Mutually exclusive with graph. |
graph | object | No | Initial DAG with nodes and edges. |
Built-in templates: basic_rag, document_qa, conversational_rag, multi_source_rag, agentic_rag, image_ocr_ingest, chat_rag, chatroom_memory_search.
Example request
Section titled “Example request”curl -X POST https://api.schift.io/v1/workflows \ -H "Authorization: Bearer $SCHIFT_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "name": "Document QA", "description": "Upload, parse, chunk, embed, and store documents.", "template": "document_qa" }'Example response
Section titled “Example response”{ "id": "wf_abc123def456", "name": "Document QA", "description": "Upload, parse, chunk, embed, and store documents.", "status": "draft", "graph": { "nodes": [ { "id": "start_001", "type": "start", "title": "Start", "position": {"x": 100, "y": 100}, "config": {} } ], "edges": [] }, "created_at": "2026-06-19T05:00:00+00:00", "updated_at": "2026-06-19T05:00:00+00:00"}Error examples
Section titled “Error examples”// 400{ "detail": "Code blocks are disabled in hosted workflows"}GET /v1/workflows
Section titled “GET /v1/workflows”List all workflows for the authenticated organization.
Example response
Section titled “Example response”[ { "id": "wf_abc123def456", "name": "Document QA", "description": "Upload, parse, chunk, embed, and store documents.", "status": "draft", "block_count": 1, "updated_at": "2026-06-19T05:00:00+00:00" }]GET /v1/workflows/{workflow_id}
Section titled “GET /v1/workflows/{workflow_id}”Get a single workflow definition, including its full graph.
Path parameters
Section titled “Path parameters”| Name | Type | Description |
|---|---|---|
workflow_id | string | Workflow identifier. |
Error examples
Section titled “Error examples”// 404{ "detail": "Workflow not found"}PATCH /v1/workflows/{workflow_id}
Section titled “PATCH /v1/workflows/{workflow_id}”Update a workflow’s metadata or graph. Changing the graph triggers validation.
Request body
Section titled “Request body”| Parameter | Type | Required | Description |
|---|---|---|---|
name | string | No | New workflow name. |
description | string | No | New description. |
status | string | No | draft, published, or archived. |
graph | object | No | Replacement DAG with nodes and edges. |
Note: A workflow must be in
publishedstatus before it can be run.
Error examples
Section titled “Error examples”// 400 invalid_graph{ "error": "invalid_graph", "errors": ["Missing required input on block chunk_001"]}// 400{ "detail": "Code blocks are disabled in hosted workflows"}DELETE /v1/workflows/{workflow_id}
Section titled “DELETE /v1/workflows/{workflow_id}”Delete a workflow and its definition. Returns 204 No Content on success.
Error examples
Section titled “Error examples”// 404{ "detail": "Workflow not found"}POST /v1/workflows/{workflow_id}/blocks
Section titled “POST /v1/workflows/{workflow_id}/blocks”Add a block to an existing workflow.
Request body
Section titled “Request body”| Parameter | Type | Required | Description |
|---|---|---|---|
type | string | Yes | Block type. See GET /v1/workflows/meta/block-types. |
title | string | No | Display title. Defaults to the block type label. |
position | object | No | {"x": number, "y": number}. Defaults to {"x": 0, "y": 0}. |
config | object | No | Block-specific configuration. |
Example request
Section titled “Example request”curl -X POST https://api.schift.io/v1/workflows/wf_abc123def456/blocks \ -H "Authorization: Bearer $SCHIFT_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "type": "llm", "title": "Answer generator", "position": {"x": 400, "y": 200}, "config": { "model": "gemini-2.5-flash-lite", "temperature": 0.7, "max_tokens": 1024 } }'Example response
Section titled “Example response”{ "id": "llm_7a8b9c0d", "type": "llm", "title": "Answer generator", "config": { "model": "gemini-2.5-flash-lite", "temperature": 0.7, "max_tokens": 1024 }, "position": {"x": 400, "y": 200}}Error examples
Section titled “Error examples”// 400{ "detail": "Code blocks are disabled in hosted workflows"}DELETE /v1/workflows/{workflow_id}/blocks/{block_id}
Section titled “DELETE /v1/workflows/{workflow_id}/blocks/{block_id}”Remove a block from a workflow. Connected edges are removed automatically.
Path parameters
Section titled “Path parameters”| Name | Type | Description |
|---|---|---|
workflow_id | string | Workflow identifier. |
block_id | string | Block identifier. |
Returns 204 No Content on success.
POST /v1/workflows/{workflow_id}/edges
Section titled “POST /v1/workflows/{workflow_id}/edges”Add an edge between two blocks.
Request body
Section titled “Request body”| Parameter | Type | Required | Description |
|---|---|---|---|
source | string | Yes | Source block ID. |
target | string | Yes | Target block ID. |
source_handle | string | No | Output port. Defaults to output. |
target_handle | string | No | Input port. Defaults to input. |
Example request
Section titled “Example request”curl -X POST https://api.schift.io/v1/workflows/wf_abc123def456/edges \ -H "Authorization: Bearer $SCHIFT_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "source": "retriever_001", "target": "llm_7a8b9c0d", "source_handle": "results", "target_handle": "vars" }'Example response
Section titled “Example response”{ "id": "edge_a1b2c3d4", "source": "retriever_001", "target": "llm_7a8b9c0d", "source_handle": "results", "target_handle": "vars"}Error examples
Section titled “Error examples”// 400{ "detail": "Source block not found: retriever_001"}DELETE /v1/workflows/{workflow_id}/edges/{edge_id}
Section titled “DELETE /v1/workflows/{workflow_id}/edges/{edge_id}”Remove an edge from a workflow. Returns 204 No Content on success.
POST /v1/workflows/{workflow_id}/run
Section titled “POST /v1/workflows/{workflow_id}/run”Execute a workflow.
Query parameters
Section titled “Query parameters”| Name | Type | Required | Description |
|---|---|---|---|
mode | string | No | async (default) or sync. |
Request body
Section titled “Request body”| Parameter | Type | Required | Description |
|---|---|---|---|
inputs | object | No | Key-value inputs passed to the workflow. |
Async execution (default)
Section titled “Async execution (default)”Async runs are queued as background jobs. The response contains a run ID that you can poll with GET /v1/workflows/\{workflow_id\}/runs/\{run_id\}.
Example request
Section titled “Example request”curl -X POST "https://api.schift.io/v1/workflows/wf_abc123def456/run?mode=async" \ -H "Authorization: Bearer $SCHIFT_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "inputs": {"query": "What is vector search?"} }'Example response
Section titled “Example response”{ "id": "run_9f8e7d6c", "workflow_id": "wf_abc123def456", "status": "pending"}Sync execution
Section titled “Sync execution”Sync execution waits for the workflow to finish and returns the final run state.
Example request
Section titled “Example request”curl -X POST "https://api.schift.io/v1/workflows/wf_abc123def456/run?mode=sync" \ -H "Authorization: Bearer $SCHIFT_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "inputs": {"query": "What is vector search?"} }'Example response
Section titled “Example response”{ "id": "run_9f8e7d6c", "workflow_id": "wf_abc123def456", "status": "completed", "inputs": {"query": "What is vector search?"}, "outputs": {"answer": "Vector search finds similar vectors in a database."}, "block_states": { "llm_7a8b9c0d": { "block_id": "llm_7a8b9c0d", "status": "completed", "inputs": {"vars": {"query": "What is vector search?"}}, "outputs": {"response": "Vector search finds similar vectors in a database."}, "error": null, "started_at": "2026-06-19T05:05:00+00:00", "finished_at": "2026-06-19T05:05:01+00:00", "duration_ms": 1200 } }, "error": null, "started_at": "2026-06-19T05:05:00+00:00", "finished_at": "2026-06-19T05:05:02+00:00"}Error examples
Section titled “Error examples”// 409 workflow_not_published{ "error": "workflow_not_published", "message": "Publish workflow before running", "status": "draft"}// 403{ "detail": "Upgrade your plan to continue"}// 402{ "allowed": false, "reason": "quota_exceeded"}// 400{ "detail": "Workflow exceeds maximum of 100 blocks (has 120)"}POST /v1/workflows/{workflow_id}/webhook/{path}
Section titled “POST /v1/workflows/{workflow_id}/webhook/{path}”Trigger a workflow run from an incoming webhook. The request body, headers, query parameters, method, and path are passed into the workflow as inputs.
Path parameters
Section titled “Path parameters”| Name | Type | Description |
|---|---|---|
workflow_id | string | Workflow identifier. |
path | string | Remaining webhook path. |
Example request
Section titled “Example request”curl -X POST https://api.schift.io/v1/workflows/wf_abc123def456/webhook/incoming \ -H "Authorization: Bearer $SCHIFT_API_KEY" \ -H "Content-Type: application/json" \ -d '{"event": "document.uploaded"}'Example response
Section titled “Example response”{ "id": "run_a1b2c3d4", "workflow_id": "wf_abc123def456", "status": "pending"}Error examples
Section titled “Error examples”// 413{ "detail": "Workflow webhook body exceeds 1MB cap"}// 400{ "detail": "Invalid JSON body: Expecting value"}GET /v1/workflows/{workflow_id}/runs
Section titled “GET /v1/workflows/{workflow_id}/runs”List runs for a workflow.
Example response
Section titled “Example response”[ { "id": "run_9f8e7d6c", "workflow_id": "wf_abc123def456", "status": "completed", "inputs": {"query": "What is vector search?"}, "outputs": {"answer": "Vector search finds similar vectors in a database."}, "started_at": "2026-06-19T05:05:00+00:00", "finished_at": "2026-06-19T05:05:02+00:00" }]GET /v1/workflows/{workflow_id}/runs/{run_id}
Section titled “GET /v1/workflows/{workflow_id}/runs/{run_id}”Get a single run, including block-level states.
Error examples
Section titled “Error examples”// 404{ "detail": "Workflow run not found"}GET /v1/workflows/{workflow_id}/runs/{run_id}/logs
Section titled “GET /v1/workflows/{workflow_id}/runs/{run_id}/logs”Poll execution logs for a run.
Query parameters
Section titled “Query parameters”| Name | Type | Required | Description |
|---|---|---|---|
after_seq | integer | No | Return logs after this sequence number. Defaults to 0. |
Example response
Section titled “Example response”{ "run_id": "run_9f8e7d6c", "status": "completed", "logs": [ {"seq": 1, "level": "info", "message": "Run started", "timestamp": "2026-06-19T05:05:00+00:00"}, {"seq": 2, "level": "info", "message": "Block llm_7a8b9c0d completed", "timestamp": "2026-06-19T05:05:01+00:00"} ]}POST /v1/workflows/{workflow_id}/validate
Section titled “POST /v1/workflows/{workflow_id}/validate”Validate a workflow graph without modifying it.
Example response
Section titled “Example response”{ "valid": true, "errors": []}Error examples
Section titled “Error examples”{ "valid": false, "errors": ["Block llm_7a8b9c0d has unconnected required input"]}POST /v1/workflows/import
Section titled “POST /v1/workflows/import”Import a workflow from YAML.
Request body
Section titled “Request body”| Parameter | Type | Required | Description |
|---|---|---|---|
yaml | string | Yes | YAML workflow definition. |
The YAML must contain version: 1, name, and at least one block. code blocks are rejected during import.
Example request
Section titled “Example request”curl -X POST https://api.schift.io/v1/workflows/import \ -H "Authorization: Bearer $SCHIFT_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "yaml": "version: 1\nname: Simple RAG\nblocks:\n - id: start\n type: start\nedges: []" }'Example response
Section titled “Example response”{ "id": "wf_imported123", "name": "Simple RAG", "status": "draft", "graph": { "nodes": [{"id": "start", "type": "start", "title": "Start", "position": {"x": 0, "y": 0}, "config": {}}], "edges": [] }, "created_at": "2026-06-19T05:10:00+00:00", "updated_at": "2026-06-19T05:10:00+00:00"}Error examples
Section titled “Error examples”// 400{ "detail": "Missing required field: 'version'"}// 400{ "detail": "Code blocks are disabled in hosted workflows"}GET /v1/workflows/{workflow_id}/export
Section titled “GET /v1/workflows/{workflow_id}/export”Export a workflow definition as YAML or JSON.
Query parameters
Section titled “Query parameters”| Name | Type | Required | Description |
|---|---|---|---|
format | string | No | yaml (default) or json. |
For yaml, the response is text/yaml. For json, the response is JSON.
POST /v1/workflows/generate
Section titled “POST /v1/workflows/generate”Generate a workflow from a natural-language prompt. This is a premium feature.
Request body
Section titled “Request body”| Parameter | Type | Required | Description |
|---|---|---|---|
prompt | string | Yes | Description of the workflow to generate. |
model | string | No | Model to use. Defaults to gemini-2.5-flash-lite. |
Error examples
Section titled “Error examples”// 403{ "error": "upgrade_required", "message": "Agentic workflow generation is a premium feature. Upgrade your plan to use it."}// 502{ "error": "upstream_error", "message": "Workflow execution failed"}GET /v1/workflows/meta/block-types
Section titled “GET /v1/workflows/meta/block-types”List all available block types, their categories, input/output ports, and default configurations.
GET /v1/workflows/meta/descriptors
Section titled “GET /v1/workflows/meta/descriptors”List node descriptors, optionally filtered by category or search query.
Query parameters
Section titled “Query parameters”| Name | Type | Required | Description |
|---|---|---|---|
category | string | No | Filter by block category. |
q | string | No | Search term. |
GET /v1/workflows/meta/descriptors/grouped
Section titled “GET /v1/workflows/meta/descriptors/grouped”List node descriptors grouped by category.
GET /v1/workflows/meta/descriptors/{block_type}
Section titled “GET /v1/workflows/meta/descriptors/{block_type}”Get the descriptor for a single block type.
Error examples
Section titled “Error examples”// 404{ "detail": "No descriptor for block type 'unknown_block'"}GET /v1/workflows/meta/templates
Section titled “GET /v1/workflows/meta/templates”List built-in workflow templates.
Example response
Section titled “Example response”[ {"id": "basic_rag", "label": "Basic Rag"}, {"id": "document_qa", "label": "Document Qa"}, {"id": "conversational_rag", "label": "Conversational Rag"}]Limits
Section titled “Limits”| Limit | Value | Notes |
|---|---|---|
| Blocks per workflow | 100 | Hard limit. |
| Edges per workflow | 200 | Hard limit (2× block limit). |
| Webhook body size | 1 MB | Rejected with HTTP 413. |
| Sync execution timeout | 60 s | Total workflow timeout. |
| Per-block timeout | 30 s | Individual block timeout. |
| Execution context size | 10 MB | Total variables and outputs. |
| Subworkflow depth | 5 | Maximum nested subworkflow calls. |
Default execution spend caps:
| Cap | Value |
|---|---|
external_calls_total | 60 |
llm_calls | 20 |
web_search_calls | 10 |
Run statuses
Section titled “Run statuses”A run can be in one of the following states:
| Status | Description |
|---|---|
pending | Queued but not started. |
running | Currently executing. |
completed | Finished successfully. |
failed | Stopped because of an error. |
cancelled | Cancelled before completion. |
API versions
Section titled “API versions”| Version | Status | Notes |
|---|---|---|
v1 | Current | All /v1/workflows/* routes documented here are the current public surface. |
There is no v2 Workflows API at this time. New integrations should use the /v1/workflows/* routes.