Skip to content

Workflows

Show:

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.

Every request must include a Bearer API key:

Terminal window
curl -H "Authorization: Bearer $SCHIFT_API_KEY" \
https://api.schift.io/v1/workflows

All workflow endpoints are hosted under:

https://api.schift.io/v1/workflows

A workflow is a directed acyclic graph (DAG) made of blocks and edges.

FieldTypeDescription
idstringWorkflow identifier.
namestringHuman-readable name.
descriptionstringOptional description.
statusstringdraft, published, or archived.
graph.nodesarrayBlocks in the workflow.
graph.edgesarrayConnections between blocks.
created_atstringISO 8601 timestamp.
updated_atstringISO 8601 timestamp.

Create a new workflow. You can start from a blank graph or from a built-in template.

ParameterTypeRequiredDescription
namestringYesWorkflow name.
descriptionstringNoOptional description.
templatestringNoOne of the built-in template IDs. Mutually exclusive with graph.
graphobjectNoInitial 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.

Terminal window
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"
}'
{
"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"
}
// 400
{
"detail": "Code blocks are disabled in hosted workflows"
}

List all workflows for the authenticated organization.

[
{
"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 a single workflow definition, including its full graph.

NameTypeDescription
workflow_idstringWorkflow identifier.
// 404
{
"detail": "Workflow not found"
}

Update a workflow’s metadata or graph. Changing the graph triggers validation.

ParameterTypeRequiredDescription
namestringNoNew workflow name.
descriptionstringNoNew description.
statusstringNodraft, published, or archived.
graphobjectNoReplacement DAG with nodes and edges.

Note: A workflow must be in published status before it can be run.

// 400 invalid_graph
{
"error": "invalid_graph",
"errors": ["Missing required input on block chunk_001"]
}
// 400
{
"detail": "Code blocks are disabled in hosted workflows"
}

Delete a workflow and its definition. Returns 204 No Content on success.

// 404
{
"detail": "Workflow not found"
}

Add a block to an existing workflow.

ParameterTypeRequiredDescription
typestringYesBlock type. See GET /v1/workflows/meta/block-types.
titlestringNoDisplay title. Defaults to the block type label.
positionobjectNo{"x": number, "y": number}. Defaults to {"x": 0, "y": 0}.
configobjectNoBlock-specific configuration.
Terminal window
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
}
}'
{
"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}
}
// 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.

NameTypeDescription
workflow_idstringWorkflow identifier.
block_idstringBlock identifier.

Returns 204 No Content on success.

Add an edge between two blocks.

ParameterTypeRequiredDescription
sourcestringYesSource block ID.
targetstringYesTarget block ID.
source_handlestringNoOutput port. Defaults to output.
target_handlestringNoInput port. Defaults to input.
Terminal window
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"
}'
{
"id": "edge_a1b2c3d4",
"source": "retriever_001",
"target": "llm_7a8b9c0d",
"source_handle": "results",
"target_handle": "vars"
}
// 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.

Execute a workflow.

NameTypeRequiredDescription
modestringNoasync (default) or sync.
ParameterTypeRequiredDescription
inputsobjectNoKey-value inputs passed to the workflow.

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\}.

Terminal window
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?"}
}'
{
"id": "run_9f8e7d6c",
"workflow_id": "wf_abc123def456",
"status": "pending"
}

Sync execution waits for the workflow to finish and returns the final run state.

Terminal window
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?"}
}'
{
"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"
}
// 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.

NameTypeDescription
workflow_idstringWorkflow identifier.
pathstringRemaining webhook path.
Terminal window
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"}'
{
"id": "run_a1b2c3d4",
"workflow_id": "wf_abc123def456",
"status": "pending"
}
// 413
{
"detail": "Workflow webhook body exceeds 1MB cap"
}
// 400
{
"detail": "Invalid JSON body: Expecting value"
}

List runs for a workflow.

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

// 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.

NameTypeRequiredDescription
after_seqintegerNoReturn logs after this sequence number. Defaults to 0.
{
"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"}
]
}

Validate a workflow graph without modifying it.

{
"valid": true,
"errors": []
}
{
"valid": false,
"errors": ["Block llm_7a8b9c0d has unconnected required input"]
}

Import a workflow from YAML.

ParameterTypeRequiredDescription
yamlstringYesYAML workflow definition.

The YAML must contain version: 1, name, and at least one block. code blocks are rejected during import.

Terminal window
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: []"
}'
{
"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"
}
// 400
{
"detail": "Missing required field: 'version'"
}
// 400
{
"detail": "Code blocks are disabled in hosted workflows"
}

Export a workflow definition as YAML or JSON.

NameTypeRequiredDescription
formatstringNoyaml (default) or json.

For yaml, the response is text/yaml. For json, the response is JSON.

Generate a workflow from a natural-language prompt. This is a premium feature.

ParameterTypeRequiredDescription
promptstringYesDescription of the workflow to generate.
modelstringNoModel to use. Defaults to gemini-2.5-flash-lite.
// 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"
}

List all available block types, their categories, input/output ports, and default configurations.

List node descriptors, optionally filtered by category or search query.

NameTypeRequiredDescription
categorystringNoFilter by block category.
qstringNoSearch 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.

// 404
{
"detail": "No descriptor for block type 'unknown_block'"
}

List built-in workflow templates.

[
{"id": "basic_rag", "label": "Basic Rag"},
{"id": "document_qa", "label": "Document Qa"},
{"id": "conversational_rag", "label": "Conversational Rag"}
]
LimitValueNotes
Blocks per workflow100Hard limit.
Edges per workflow200Hard limit (2× block limit).
Webhook body size1 MBRejected with HTTP 413.
Sync execution timeout60 sTotal workflow timeout.
Per-block timeout30 sIndividual block timeout.
Execution context size10 MBTotal variables and outputs.
Subworkflow depth5Maximum nested subworkflow calls.

Default execution spend caps:

CapValue
external_calls_total60
llm_calls20
web_search_calls10

A run can be in one of the following states:

StatusDescription
pendingQueued but not started.
runningCurrently executing.
completedFinished successfully.
failedStopped because of an error.
cancelledCancelled before completion.
VersionStatusNotes
v1CurrentAll /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.