Quickstart

Zero to running workflow

This guide takes you from an empty namespace to a running workflow instance using plain HTTP. All you need is your admin token and runtime token.

Getting your tokens — Tokens are provisioned when your ChannelOS account is set up. If you do not have them yet, contact us. Each token is scoped to one environment (e.g. prod or staging).

Base URL: https://channelos.dev  —  All request bodies are application/json.

Platform:
1

Save a workflow definition

Send a workflow definition JSON to create a new draft. The definition describes the graph of steps and connections. Pass workflowId: null to create a new workflow.

# ConvertTo-Json handles all escaping — no curl argument issues
$def = '{"kind":"channelos.workflow","schemaVersion":"1.0","workflowId":"","name":"hello_world","graph":{"nodes":{"start":{"id":"start","label":"Start","actionType":"flow.start","config":{}},"end":{"id":"end","label":"End","actionType":"flow.end","config":{}}},"edges":{"e1":{"id":"e1","source":{"nodeId":"start","portId":"out"},"target":{"nodeId":"end","portId":"in"}}}}}'
$body = ConvertTo-Json @{ workflowId = $null; name = 'hello_world'; definitionJson = $def } -Compress
Invoke-RestMethod -Method POST https://channelos.dev/api/v1/admin/definitions `
  -Headers @{ Authorization = 'Bearer <admin-token>' } `
  -ContentType application/json `
  -Body $body
curl -X POST https://channelos.dev/api/v1/admin/definitions \
  -H "Authorization: Bearer <admin-token>" \
  -H "Content-Type: application/json" \
  -d '{
    "workflowId": null,
    "name": "hello_world",
    "definitionJson": "{\"kind\":\"channelos.workflow\",\"schemaVersion\":\"1.0\",\"workflowId\":\"\",\"name\":\"hello_world\",\"graph\":{\"nodes\":{\"start\":{\"id\":\"start\",\"label\":\"Start\",\"actionType\":\"flow.start\",\"config\":{}},\"end\":{\"id\":\"end\",\"label\":\"End\",\"actionType\":\"flow.end\",\"config\":{}}},\"edges\":{\"e1\":{\"id\":\"e1\",\"source\":{\"nodeId\":\"start\",\"portId\":\"out\"},\"target\":{\"nodeId\":\"end\",\"portId\":\"in\"}}}}}"
  }'
Response 200
{
  "requestId": "b4a3c2d1-e5f6-7890-abcd-ef1234567890",
  "ok": true,
  "workflowId": "1",
  "state": "draft",
  "hasUnpublishedChanges": true,
  "publishedVersion": null,
  "savedAt": "2026-05-17T10:00:00.000Z"
}

Save the workflowId — you will need it in every following step.

2

Publish

Publishing creates an immutable version snapshot from the current draft. You can publish as many times as you like — each publish increments the version number.

curl.exe -X POST https://channelos.dev/api/v1/admin/definitions/1/publish `
  -H "Authorization: Bearer <admin-token>"
curl -X POST https://channelos.dev/api/v1/admin/definitions/1/publish \
  -H "Authorization: Bearer <admin-token>"
Response 200
{
  "requestId": "c5d4e3f2-a1b2-4567-cdef-ab0123456789",
  "ok": true,
  "workflowId": "1",
  "state": "published",
  "publishedVersion": 1,
  "publishedAt": "2026-05-17T10:00:01.000Z"
}

Save the publishedVersion number for the next step.

3

Deploy

Deploying a version makes it the active version — new instances will use it. Running instances are not affected.

curl.exe -X POST https://channelos.dev/api/v1/admin/definitions/1/deploy/1 `
  -H "Authorization: Bearer <admin-token>"
curl -X POST https://channelos.dev/api/v1/admin/definitions/1/deploy/1 \
  -H "Authorization: Bearer <admin-token>"
Response 200
{
  "requestId": "d6e5f4a3-b2c3-5678-def0-bc1234567890",
  "ok": true,
  "workflowId": "1",
  "version": "1",
  "state": "deployed",
  "deployedVersion": "1"
}

Your workflow is now live and ready to accept instances.

4

Start an instance

Start an instance using your runtime token. The inputJson field is a JSON-encoded string — it becomes the input object available inside your workflow steps.

# ConvertTo-Json handles all escaping — no curl argument issues
$body = ConvertTo-Json @{ workflowId = '1'; inputJson = '{"name":"Alice","event":"signup"}' } -Compress
Invoke-RestMethod -Method POST https://channelos.dev/api/v1/runtime/start `
  -Headers @{ Authorization = 'Bearer <runtime-token>' } `
  -ContentType application/json `
  -Body $body
curl -X POST https://channelos.dev/api/v1/runtime/start \
  -H "Authorization: Bearer <runtime-token>" \
  -H "Content-Type: application/json" \
  -d '{
    "workflowId": "1",
    "inputJson": "{\"name\":\"Alice\",\"event\":\"signup\"}"
  }'
Response 200
{
  "requestId": "e7f6a5b4-c3d4-6789-ef01-cd2345678901",
  "instanceId": "42"
}

The instance starts executing immediately. Save the instanceId.

5

Check state

Poll the state of an instance to see if it has completed, is still running, or has failed.

Invoke-RestMethod -Method POST https://channelos.dev/api/v1/runtime/state `
  -Headers @{ Authorization = 'Bearer <runtime-token>' } `
  -ContentType application/json `
  -Body '{"instanceId":"42"}'
curl -X POST https://channelos.dev/api/v1/runtime/state \
  -H "Authorization: Bearer <runtime-token>" \
  -H "Content-Type: application/json" \
  -d '{ "instanceId": "42" }'
Response 200
{
  "requestId": "f8a7b6c5-d4e5-7890-f012-de3456789012",
  "state": "completed"
}

Possible state values: running, completed, failed, suspended, cancelled.

6

List instances

Retrieve a list of instances, optionally filtered by workflow or state.

$body = ConvertTo-Json @{ workflowId = '1'; stateFilter = 'all' } -Compress
Invoke-RestMethod -Method POST https://channelos.dev/api/v1/runtime/list `
  -Headers @{ Authorization = 'Bearer <runtime-token>' } `
  -ContentType application/json `
  -Body $body
curl -X POST https://channelos.dev/api/v1/runtime/list \
  -H "Authorization: Bearer <runtime-token>" \
  -H "Content-Type: application/json" \
  -d '{ "workflowId": "1", "stateFilter": "all" }'
Response 200
{
  "requestId": "a1b2c3d4-e5f6-7890-ab12-ef3456789012",
  "stateFilter": "all",
  "instances": [
    { "id": "42", "state": "completed" }
  ]
}

Next steps

You have a working workflow. Here is what to explore next: