Skip to content

Get started

Run your first local workflow

Install the engine, define a sequence, schedule a task. No JVM, no Cassandra, no Elasticsearch. One binary, one database.

0

Install

Pick one:

Bash
curl -fsSL https://orch8.io/start.sh | sh
Bash
brew tap orch8-io/orch8 && brew install orch8-server
Bash
docker run -d -p 8080:8080 ghcr.io/orch8-io/engine:0.7.0 --insecure

The Docker image uses SQLite by default — no external database needed for local development.

1

Start the engine

By default the engine requires an API key for authentication. For local development, run with --insecure to skip auth:

Local development (no auth)
orch8-server --insecure

For production, set an API key via environment variable:

Production (with auth)
export ORCH8_API_KEY="your-secret-key"
orch8-server

SQLite initializes its embedded schema automatically and the engine starts listening on port 8080. PostgreSQL migrations are opt-in.

Note: If the command is not found, make sure the install directory (usually ~/.local/bin) is in your PATH.

For production with Postgres:

Docker with Postgres
docker run -d \
  -e ORCH8_STORAGE_BACKEND=postgres \
  -e ORCH8_DATABASE_URL=postgres://user:pass@host:5432/orch8 \
  -e ORCH8_RUN_MIGRATIONS=true \
  -e ORCH8_ENCRYPTION_KEY=<64-hex-chars> \
  -e ORCH8_API_KEY=<your-api-key> \
  -p 8080:8080 \
  ghcr.io/orch8-io/engine:0.7.0
2

Define a sequence

A sequence is a series of steps the engine will execute durably. Create one with a POST request:

Bash
curl -X POST http://localhost:8080/api/v1/sequences \
  -H "Content-Type: application/json" \
  -d '{
    "tenant_id": "demo",
    "namespace": "default",
    "name": "welcome-flow",
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "version": 1,
    "created_at": "2026-07-28T00:00:00Z",
    "blocks": [
        {
          "type": "step",
          "id": "send_welcome",
          "handler": "http_request",
          "params": {
            "url": "https://httpbin.org/post",
            "method": "POST",
            "body": {
              "to": "{{context.data.email}}",
              "message": "Welcome, {{context.data.name}}!"
            }
          }
        },
        {
          "type": "step",
          "id": "wait_then_followup",
          "handler": "log",
          "delay": { "duration": 10000 },
          "params": {
            "message": "Following up with {{context.data.name}}"
          }
        }
    ]
  }'

The response returns a sequence ID. Copy it for the next step.

3

Schedule a task instance

Bash
curl -X POST http://localhost:8080/api/v1/instances \
  -H "Content-Type: application/json" \
  -d '{
    "sequence_id": "<sequence-id-from-step-2>",
    "tenant_id": "demo",
    "namespace": "default",
    "priority": "Normal",
    "context": {
      "data": {
        "email": "jane@example.com",
        "name": "Jane"
      }
    }
  }'

The engine picks up the instance, executes the first step immediately, waits 10 seconds, then runs the follow-up. If the engine crashes and restarts, it resumes from the last completed step.

4

Check the status

Bash
# Get instance state
curl http://localhost:8080/api/v1/instances/<instance-id>

# See step outputs
curl http://localhost:8080/api/v1/instances/<instance-id>/outputs
5

Control it

Bash
# Pause
curl -X POST http://localhost:8080/api/v1/instances/<instance-id>/signals \
  -H "Content-Type: application/json" \
  -d '{ "signal_type": "Pause" }'

# Resume
curl -X POST http://localhost:8080/api/v1/instances/<instance-id>/signals \
  -H "Content-Type: application/json" \
  -d '{ "signal_type": "Resume" }'

# Cancel
curl -X POST http://localhost:8080/api/v1/instances/<instance-id>/signals \
  -H "Content-Type: application/json" \
  -d '{ "signal_type": "Cancel" }'

Use an SDK instead of curl

Install an official SDK and manage everything from code:

Node.js / TypeScript

Bash
npm install @orch8.io/sdk
TypeScript
import { Orch8Client } from "@orch8.io/sdk";

const client = new Orch8Client({ baseUrl: "http://localhost:8080/api/v1" });

// Create a sequence
const seq = await client.createSequence({
  tenant_id: "demo",
  namespace: "default",
  name: "welcome-flow",
  blocks: [{
    type: "step",
    id: "greet",
    handler: "log",
    params: { message: "Hello, {{context.data.name}}!" },
  }],
});

// Schedule an instance
const instance = await client.createInstance({
  sequence_id: seq.id,
  tenant_id: "demo",
  namespace: "default",
  context: { data: { name: "Jane" } },
});

console.log("Instance:", instance.id);

Python

Bash
pip install orch8-io-sdk
Python
import asyncio
from orch8 import Orch8Client

async def main():
    client = Orch8Client(base_url="http://localhost:8080/api/v1")
    seq = await client.create_sequence({
        "tenant_id": "demo",
        "namespace": "default",
        "name": "welcome-flow",
        "blocks": [{
            "type": "step",
            "id": "greet",
            "handler": "log",
            "params": {"message": "Hello, {{context.data.name}}!"},
        }],
    })
    instance = await client.create_instance({
        "sequence_id": seq.id,
        "tenant_id": "demo",
        "namespace": "default",
        "context": {"data": {"name": "Jane"}},
    })
    print(f"Instance: {instance.id}")

asyncio.run(main())

Go

Bash
go get github.com/orch8-io/sdk-go
Go
package main

import (
    "context"
    "fmt"
    orch8 "github.com/orch8-io/sdk-go"
)

func main() {
    client := orch8.NewClient(orch8.ClientConfig{
        BaseURL: "http://localhost:8080/api/v1",
    })
    ctx := context.Background()

    seq, _ := client.CreateSequence(ctx, map[string]any{
        "tenant_id": "demo",
        "namespace": "default",
        "name": "welcome-flow",
        "blocks": []map[string]any{{
                "type":    "step",
                "id":      "greet",
                "handler": "log",
                "params":  map[string]any{"message": "Hello!"},
        }},
    })

    inst, _ := client.CreateInstance(ctx, map[string]any{
        "sequence_id": seq.ID,
        "tenant_id": "demo",
        "namespace": "default",
    })

    fmt.Println("Instance:", inst.ID)
}