Docs · Workflows API

Workflows API

GraphQL stores the process. This API runs it.

A workflow is still a DataObject (schemaRef: "schema:workflow") — you can list it via GraphQL. Starting a run, collecting fields, invoking agents, pausing for humans, and sealing to a system of record happen here.

Ships today in Closure (session auth; public embed routes where enabled).


Lifecycle

POST /api/runs  →  collect / agent / human / gateway / wait …
                →  POST /api/runs/{id}/advance  (repeat)
                →  end (+ Events audit)

Hybrid graphs (parallel gateways, waits, orchestration teams) use the same advance loop — see Orchestration.


Try it here

This is the wf-lead-capture workflow from the sample DataObject below, running live — the same graph JSON rendered as an executable form. Submit it and you've driven the collect → advance loop this page documents.


Lead capture

live demo · wf-lead-capture

FORM

Lead capture

Preview only — install the pack in Closure to run against your org.

Routes

RouteRole
GET/POST /api/workflowsList / register graphs
GET /api/workflows/[id]Fetch graph JSON
POST /api/runsStart a run
POST /api/runs/submitStart with collect fields
POST /api/runs/[id]/advanceAdvance one step
GET /api/runs/[id]Inspect run status + data
GET /api/public/workflows/[id]Published graph for embeds
POST /api/public/runs/submitPublic collect (when enabled)

Marketing demos may proxy under /api/closure/* — prefer Closure origin or your BFF in production.


Sample workflow DataObject

Same universe as GraphQL — process as data:

{
  "@id": "urn:uuid:bbbbbbbb-bbbb-5bbb-8bbb-bbbbbbbbbbbb",
  "schemaRef": "schema:workflow",
  "name": "Lead capture",
  "orgId": "org_demo",
  "data": {
    "workflowId": "wf-lead-capture",
    "entryNodeId": "start",
    "nodes": [
      { "id": "start", "kind": "start", "label": "Start" },
      {
        "id": "collect",
        "kind": "collect",
        "label": "Contact",
        "meta": {
          "fields": [
            { "name": "email", "type": "email", "required": true },
            { "name": "name", "type": "text", "required": true }
          ]
        }
      },
      {
        "id": "notify",
        "kind": "integration",
        "label": "Notify",
        "meta": { "adapterId": "email.notify" }
      },
      { "id": "end", "kind": "end", "label": "Done" }
    ],
    "edges": [
      { "id": "e1", "from": "start", "to": "collect" },
      { "id": "e2", "from": "collect", "to": "notify" },
      { "id": "e3", "from": "notify", "to": "end" }
    ]
  }
}

Forms, chat, and agents are projections of this graph — not three products.


Start a run

curl -sS https://closureapps.com/console/api/runs/submit \
  -H "Content-Type: application/json" \
  -H "Cookie: <session>" \
  -d '{
    "workflowId": "wf-lead-capture",
    "fields": { "email": "you@example.com", "name": "Ada" },
    "policyPack": "open"
  }'

Typical response shape:

{
  "runId": "run_…",
  "status": "running",
  "cursor": "notify",
  "data": { "email": "you@example.com", "name": "Ada" }
}

Advance

curl -sS https://closureapps.com/console/api/runs/run_…/advance \
  -H "Content-Type: application/json" \
  -H "Cookie: <session>" \
  -d '{ "actor": "ops@acme.com" }'

Useful body fields by node kind:

SituationBody
Collect{ "fields": { … } }
Decision / loop{ "branch": "pass" } or { "autoLoop": true }
Human / policy{ "actor": "user@org" }
Wait resume{ "resumeWait": true, "signal": "docs.received" }
Boundary timeout{ "fireBoundary": "timeout" }
Cancel + compensate{ "cancel": true }

Public embeds

GET  /api/public/workflows/wf-lead-capture
POST /api/public/runs/submit

Thin hosts and Experience Packs use these for collect → seal without console chrome. Package with @closure-platform/clientSDK.


Read vs run

NeedAPI
List / edit workflow graphs as DataObjectsGraphQL objects(schemaRef: "schema:workflow")
Execute a journeyThis page/api/runs*
Author hybrid BPM × agentsOrchestration · Closure canvas

Roadmap

  • Scoped public API keys
  • Webhook trigger catalog parity per connector