Docs

Workflows

Build and run DAG-based processing pipelines. Define workflows in YAML or JSON, manage them via SDK or REST API, and execute with a single call.

Choose Your Format

Schift workflows accept both YAML and JSON. Pick the one that fits your workflow:

FormatBest forHow to use
YAMLVersion control, human editing, code reviewSDK push_yaml() / importYaml() or REST POST /v1/workflows/import
JSONProgrammatic generation, API-first workflowsSDK create() or REST POST /v1/workflows with graph body
TemplateQuick start with a pre-built pipelineSDK create(template="BASIC_RAG") or REST with template field

TL;DR

If you are defining a pipeline by hand, use YAML. If your app generates pipelines dynamically, use JSON. Both produce the same workflow on the server.

YAML Schema Reference

A workflow YAML file has four top-level keys: version, name, blocks, and edges.

yamlversion: 1                    # Required. Always 1.
name: "Legal Document QA"      # Required. Display name.
description: "RAG pipeline with reranking for legal docs"

blocks:
  - id: start                  # Unique ID (referenced by edges)
    type: start                # Block type (see table below)

  - id: retriever
    type: retriever
    title: "Search Legal Docs"  # Optional display name
    config:                     # Block-specific parameters
      collection: "legal-kr"
      top_k: 10
      rerank: true
      rerank_top_k: 3

  - id: prompt
    type: prompt_template
    config:
      template: |
        Context:
        {{results}}

        Question: {{query}}
        Answer in the same language as the question.

  - id: llm
    type: llm
    config:
      model: "openai/gpt-4.1-nano"
      temperature: 0.3
      max_tokens: 1024

  - id: answer
    type: answer

  - id: end
    type: end

edges:
  - source: start
    target: retriever
  - source: retriever
    target: prompt
  - source: prompt
    target: llm
  - source: llm
    target: answer
  - source: answer
    target: end

Block Types

Use GET /v1/workflows/meta/block-types to list all available types. Full reference:

CategoryTypeDescription
ControlstartEntry point. Forwards all inputs to downstream blocks.
ControlendTerminal node. Marks workflow completion.
Documentdocument_loaderLoad PDF, DOCX, HWP, PPT, images, or URLs.
Documentdocument_parserOCR and table/chart extraction.
DocumentchunkerSplit text. Strategies: recursive, semantic, sentence, fixed.
EmbeddingembedderEmbed via Schift API with automatic canonical projection.
Embeddingmodel_selectorAuto-select the best embedding model for the task.
Storagevector_storeUpsert vectors to a collection.
StoragecollectionReference an existing collection by name.
RetrievalretrieverVector search with optional metadata filters and reranking.
RetrievalrerankerCross-encoder rerank on retrieved results.
LLMllmLLM generation. Prefix-routed: openai/, anthropic/, google/.
LLMprompt_templateJinja2 template for prompt construction.
LogicconditionIf/else branching.
LogicrouterMulti-path routing (question classifier).
Logicai_routerLLM-powered dynamic routing.
LogicloopIterate over a list of items.
TransformcodePython sandbox for custom logic.
TransformmergeMerge multiple branch outputs.
TransformvariableSet/get workflow variables.
Transformfield_selectorPick columns from tables or paths from JSON.
Integrationhttp_requestCall an external API.
IntegrationwebhookIncoming webhook trigger.
Ingestwebhook_sourceInbound webhook to ingest pipeline.
Ingestingest_bridgeDedup + download + document creation.
Ingestfeed_pollPeriodic RSS/API polling.
IngestnotifyOutbound webhook on job completion.
OutputanswerChat-style response output.
Outputmetadata_extractorExtract structured metadata from text.

SDK Quickstart

Both SDKs support the full lifecycle: create, YAML import/export, run, and manage.

pythonfrom schift import Schift

client = Schift(api_key="sch_xxx")

# Option 1: Create from YAML file
wf = client.workflows.push_yaml("pipeline.yaml")

# Option 2: Create from template
wf = client.workflows.create("My RAG", template="BASIC_RAG")

# Option 3: Build step by step
wf = client.workflows.create("Custom Pipeline")
client.workflows.add_block(wf.id, "retriever", config={"collection": "docs", "top_k": 5})
client.workflows.add_block(wf.id, "llm", config={"model": "openai/gpt-4.1-nano"})
client.workflows.add_edge(wf.id, source="retriever", target="llm")

# Run
result = client.workflows.run(wf.id, inputs={"query": "What is the refund policy?"})
print(result.outputs)

# Export to YAML for version control
yaml_str = client.workflows.to_yaml(wf.id, path="pipeline.yaml")
typescriptimport { Schift } from "@schift-io/sdk";

const schift = new Schift({ apiKey: "sch_xxx" });

// Option 1: Import from YAML string (requires js-yaml)
const wf = await schift.workflows.importYaml(yamlString);

// Option 2: Create from template
const wf2 = await schift.workflows.create({ name: "My RAG", template: "BASIC_RAG" });

// Option 3: Build step by step
const wf3 = await schift.workflows.create({ name: "Custom" });
await schift.workflows.addBlock(wf3.id, { type: "retriever", config: { collection: "docs" } });
await schift.workflows.addBlock(wf3.id, { type: "llm", config: { model: "openai/gpt-4.1-nano" } });
await schift.workflows.addEdge(wf3.id, { source: "retriever", target: "llm" });

// Run
const run = await schift.workflows.run(wf3.id, { query: "What is the refund policy?" });

// Export to YAML
const yaml = await schift.workflows.exportYaml(wf3.id);

REST API Reference

MethodEndpointDescription
POST/v1/workflowsCreate a workflow (blank, from template, or with full graph)
GET/v1/workflowsList all workflows
GET/v1/workflows/{id}Get a single workflow with full graph
PATCH/v1/workflows/{id}Update name, description, status, or graph
DELETE/v1/workflows/{id}Delete a workflow
POST/v1/workflows/importImport from YAML string
GET/v1/workflows/{id}/export?format=yamlExport as YAML (or format=json)
POST/v1/workflows/{id}/blocksAdd a block
DELETE/v1/workflows/{id}/blocks/{block_id}Remove a block
POST/v1/workflows/{id}/edgesAdd an edge
DELETE/v1/workflows/{id}/edges/{edge_id}Remove an edge
POST/v1/workflows/{id}/validateValidate the graph (cycles, missing connections)
POST/v1/workflows/{id}/runExecute with inputs
GET/v1/workflows/{id}/runsList past runs
GET/v1/workflows/{id}/runs/{run_id}Get a specific run result
POST/v1/workflows/{id}/webhook/{path}Trigger via external webhook
POST/v1/workflows/generateAI-generate a workflow from natural language (paid)
bash# Import a YAML file via REST
curl -X POST https://api.schift.io/v1/workflows/import \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer $SCHIFT_API_KEY" \
  -d '{"yaml": "version: 1\nname: My Pipeline\nblocks:\n  - id: start\n    type: start\n  - id: end\n    type: end\nedges:\n  - source: start\n    target: end"}'

# Export as YAML
curl https://api.schift.io/v1/workflows/{id}/export?format=yaml \
  -H "Authorization: Bearer $SCHIFT_API_KEY"

# Export as JSON
curl https://api.schift.io/v1/workflows/{id}/export?format=json \
  -H "Authorization: Bearer $SCHIFT_API_KEY"

LLM Provider Routing

The llm block routes to different providers based on the model prefix:

Model formatProviderExample
openai/model-nameOpenAIopenai/gpt-4.1-nano
anthropic/model-nameAnthropicanthropic/claude-sonnet-4-6
google/model-name or gemini-*Google (Gemini)gemini-2.5-flash

API keys are resolved from org settings first, then from environment variables (OPENAI_API_KEY, ANTHROPIC_API_KEY, GOOGLE_API_KEY).

Templates

Use GET /v1/workflows/meta/templates to list available templates.

TemplatePipeline
BASIC_RAGStart -> Retriever -> Reranker -> Prompt -> LLM -> Answer -> End
DOCUMENT_QADocument QA with source attribution
CONVERSATIONAL_RAGMulti-turn conversational RAG with context
CHAT_RAGChat-optimized RAG
IMAGE_OCR_INGESTOCR -> Chunk -> Embed ingestion pipeline

Execution

Pass any number of input variables. The start node forwards all of them to downstream blocks.

bash# Validate before running
curl -X POST https://api.schift.io/v1/workflows/{id}/validate \
  -H "Authorization: Bearer $SCHIFT_API_KEY"

# Run with inputs
curl -X POST https://api.schift.io/v1/workflows/{id}/run \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer $SCHIFT_API_KEY" \
  -d '{"inputs": {"query": "maternity leave policy", "language": "ko"}}'

# List past runs
curl https://api.schift.io/v1/workflows/{id}/runs \
  -H "Authorization: Bearer $SCHIFT_API_KEY"

The run response includes status, outputs, per-block block_states with timing, and error if any step failed.

Webhook Triggers

Workflows can be triggered by external systems. POST to /v1/workflows/{id}/webhook/{path} and the payload is forwarded as workflow inputs (body, headers, query_params).

AI Generation (Paid)

POST /v1/workflows/generate creates a workflow graph from a natural language description. The generated graph is returned for review and is not saved automatically.

bashcurl -X POST https://api.schift.io/v1/workflows/generate \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer $SCHIFT_API_KEY" \
  -d '{"prompt": "Search my docs, rerank results, and summarize with GPT-4o"}'