Prerequisites:
- Authentication configured (see Authentication guide)
Define the graph
Save blocks (processing steps) and edges (connections between them) as a complete graph. The block registry recognizes these canonical types:
starter, agent, code, condition, general_api, platform_api, response, split, webhook, orchestration (function and api_call are accepted as back-compat aliases for code and general_api). The example below wires a starter that injects workflow variables, runs an agent block to produce a summary, and returns the agent’s output through a response block.Endpoint: PUT /api/workflows/{id}/graphUnknown block types are rejected with
400 Unknown block type. See the Workflows concept page for what each block does.Execute the workflow
Run the workflow with input data. Returns execution results.Endpoint:
POST /api/workflows/{id}/executeDeploy with webhook
Two activation modes:
- Deploy (
POST /api/workflows/{id}/deploy) — setsstate = "deployed". The webhook accepts unlimited calls until youundeploy. - Arm (
POST /api/workflows/{id}/arm) — leavesstate = "internal"but opens a 10-minute window during which the webhook accepts exactly one call. After it fires (or expires), you must arm again.
webhook_id and webhook_secret are properties of the webhook block itself, stored in block.config. The studio editor mints them client-side when you drag in a webhook block. To retrieve them programmatically, fetch the workflow and pull them from the block’s config.If you create the webhook block via API instead of the UI (
PUT /api/workflows/{id}/graph), you must mint both webhook_id and webhook_secret yourself and include them in the block’s config. The server does not generate them. webhook_id MUST be a valid UUID — the trigger endpoint validates it and returns 400 otherwise. webhook_secret can be any non-empty string (the studio editor uses crypto.randomUUID() for both). A webhook block with no secret is silently un-triggerable (the trigger endpoint will return 401).The deploy endpoint returns
{"ok": true, "state": "deployed"} and arm returns {"ok": true, "armed_until": "<iso-timestamp>"} — neither response contains the webhook credentials.Trigger externally
Call the webhook endpoint from any external system. No platform API key is needed — auth is per-webhook via the secret, sent either as a Bearer header (preferred) or a Endpoint:
?token= query param. The request body becomes the workflow’s input variables directly.Use one auth mechanism or the other, not both. The server checks the header with
auth_header.lower().startswith("bearer ") (note the trailing space). If your Authorization header is exactly Bearer (trailing space, no token) — what Bearer ${secret || ""} produces when secret is falsy — the server reads an empty token and 401s without consulting ?token=. The ?token= fallback only fires when the header doesn’t start with Bearer .POST /api/webhooks/{webhook_id}If the workflow is
deployed, the webhook accepts unlimited calls. If only armed, the webhook accepts exactly one call within the 10-minute window — re-arm to fire it again.What’s Next
Workflows (Copilot)
Build workflows with natural language.
Workflows
Understand block types and graph execution.
Workflows API Reference
Full endpoint documentation.