Appearance
Webhooks
Trigger a workflow from an external system and read the results back.
Triggering a run
A workflow that starts with a Webhook node can be launched by an HTTP request instead of a click on the canvas:
POST /microservices/workflow/webhook/— the generic trigger. Identify the workflow withworkflow_id(or the webhook node's own key) and pass the inputs in the body. Returns a run id you can poll.GET /microservices/workflow/{workflow_id}/node-webhook/{node_id}/— the per-node trigger URL shown on the canvas.
The approval queue
Workflows can require a human to approve each incoming webhook request before it runs. Pending requests sit in the workflow's queue (webhook-queue/) until an owner approves or rejects them, from the app or through the API.
Authentication
Webhook trigger requests authenticate with the same session token as any other call. Callers that cannot hold a session should be given a dedicated service account.
Endpoints
| Method | Path | Purpose |
|---|---|---|
| POST | /microservices/workflow/webhook/ | Trigger a workflow run |
| GET | /microservices/workflow/webhook/status/ | Poll a run with the webhook credential |
| GET | /microservices/workflow/{id}/node-webhook/{node_id}/ | Credential for a trigger node |
| GET | /microservices/workflow/{id}/webhook-queue/ | The webhook run queue |
| POST | /microservices/workflow/{id}/webhook-queue/{request_id}/ | Retry or cancel a queued request |
POST /microservices/workflow/webhook/
Trigger a workflow run
Starts a run using a webhook credential instead of a session:
- the workflow's own credential (
webhook_id+webhook_secretfromGET /microservices/workflow/{id}/) runs the whole workflow; - a node credential (
GET …/node-webhook/{node_id}/) runs the branch that starts at that node (or the whole workflow when the node is an entry node).
Calls are queued and replayed one at a time per workflow, so a burst of calls is safe: each returns 202 with a request_id and its queue position. Poll GET /microservices/workflow/webhook/status/ with the same credential to follow the run, or watch the queue in the app.
The optional payload (max 64 KB, JSON object) reaches the triggered node as the _webhook_payload parameter. File-reference keys (file_path, file_uids and similar) are stripped — a webhook may start a run, not point it at the owner's files; file_urls is allowed for remote ingestion.
Auth: Webhook credential in the body (no session) · Rate limit: none (exempt from the anonymous limit) · In the app: Canvas → Webhook node → copy URL
Request body (application/json)
| Field | Type | Required | Description |
|---|---|---|---|
webhook_id | string | yes | |
webhook_secret | string | yes | |
payload | object | no | Input for the run (webhook_payload accepted as an alias). |
is_branch | boolean | no | Workflow credential only — run a branch instead of the whole workflow. |
start_node_id | string | no | With is_branch on a workflow credential — the spec node to start at. |
run_to_the_end | boolean | no | Default: true. |
json
{
"webhook_id": "k3Jf9Qz2p",
"webhook_secret": "6f1e2d3c4b5a6c7d8e9f0a1b2c3d4e5f",
"payload": {
"file_urls": [
"https://files.acme.com/inbox/invoice-1042.pdf"
],
"file_name": "invoice-1042.pdf"
}
}Response 202 — Accepted — started now, or queued behind another run.
| Field | Type | Description |
|---|---|---|
message | string | |
request_id | string (uuid) | |
queued | boolean | |
queue_position | integer | 0 when started immediately. |
workflow_id | string (uuid) |
json
{
"message": "Workflow run started.",
"request_id": "9e8d7c6b-…",
"queued": false,
"queue_position": 0,
"workflow_id": "7d4c2b1a-…"
}Response 400 — Missing credential, invalid payload, or is_branch without start_node_id.
json
{
"error": "Invalid payload: payload is 70000 bytes, over the 65536 byte limit"
}Response 401 — Unknown webhook id or wrong secret (indistinguishable by design).
json
{
"error": "Invalid webhook credentials"
}Example
bash
curl -X POST "https://api.example.com/microservices/workflow/webhook/" \
-H "Content-Type: application/json" \
-d '{
"webhook_id": "k3Jf9Qz2p",
"webhook_secret": "6f1e2d3c4b5a6c7d8e9f0a1b2c3d4e5f",
"payload": {"file_urls": ["https://files.acme.com/inbox/invoice-1042.pdf"]}
}'GET /microservices/workflow/webhook/status/
Poll a run with the webhook credential
Status of the workflow and its nodes, authenticated with the same credential used to trigger it. Add include_output=true to get each node's output — for example the result of the last node.
Auth: Webhook credential in the query string (no session) · Rate limit: none (meant to be polled)
Query parameters
| Field | Type | Required | Description |
|---|---|---|---|
webhook_id | string | yes | |
webhook_secret | string | yes | |
include_output | boolean | no | Default: false. |
Response 200 — Status.
| Field | Type | Description |
|---|---|---|
workflow_id | string | |
workflow_name | string | |
status | string ("IDLE", "PENDING", "RUNNING", "COMPLETED", "FAILED", "STOPPED") | |
current_run_version | integer, nullable | |
updated_at | string (date-time) | |
nodes | object[] | |
nodes[].node_id | string | |
nodes[].kind | string | |
nodes[].status | string | |
nodes[].attempt_count | integer | |
nodes[].started_at | string (date-time), nullable | |
nodes[].finished_at | string (date-time), nullable | |
nodes[].output | object | Only with include_output=true. |
json
{
"workflow_id": "7d4c2b1a-0e9f-4a3b-8c7d-6e5f4a3b2c1d",
"workflow_name": "Invoice intake",
"status": "COMPLETED",
"current_run_version": null,
"updated_at": "2026-09-22T08:05:41Z",
"nodes": [
{
"node_id": "step1",
"kind": "webhook_trigger",
"status": "COMPLETED",
"attempt_count": 1,
"started_at": "2026-09-22T08:05:02Z",
"finished_at": "2026-09-22T08:05:02Z"
},
{
"node_id": "step2",
"kind": "data_extractor",
"status": "COMPLETED",
"attempt_count": 1,
"started_at": "2026-09-22T08:05:03Z",
"finished_at": "2026-09-22T08:05:41Z"
}
]
}Response 401 — Bad credential.
json
{
"error": "path is required"
}Example
bash
curl "https://api.example.com/microservices/workflow/webhook/status/?webhook_id=k3Jf9Qz2p&webhook_secret=6f1e…&include_output=true"GET /microservices/workflow/{id}/node-webhook/{node_id}/
Credential for a trigger node
Returns (creating on first read) the stable webhook credential of one node. Owner only. is_branch tells you whether a call runs just that node's branch or the whole workflow.
Auth: Session token · In the app: Canvas → Webhook node panel
Path parameters
| Field | Type | Required | Description |
|---|---|---|---|
id | string (uuid) | yes | |
node_id | string | yes | Spec node id. |
Response 200 — Credential.
| Field | Type | Description |
|---|---|---|
workflow_id | string | |
node_id | string | |
webhook_id | string | |
webhook_secret | string | |
is_branch | boolean | |
created | boolean |
json
{
"workflow_id": "7d4c2b1a-0e9f-4a3b-8c7d-6e5f4a3b2c1d",
"node_id": "step1",
"webhook_id": "Xp2Lm8Qa4",
"webhook_secret": "0a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d",
"is_branch": false,
"created": true
}Response 404 — Node not in the spec, or not your workflow.
json
{
"error": "path is required"
}Example
bash
curl -X GET "https://api.example.com/microservices/workflow/<id>/node-webhook/step1/" \
-H "Authorization: Token $FINBLADE_TOKEN"GET /microservices/workflow/{id}/webhook-queue/
The webhook run queue
Pending and running requests in order, then the most recent finished ones (limit, max 200), with per-request file lists and outcomes.
Auth: Session token · In the app: Canvas → Queue panel
Path parameters
| Field | Type | Required | Description |
|---|---|---|---|
id | string (uuid) | yes |
Query parameters
| Field | Type | Required | Description |
|---|---|---|---|
limit | integer | no | Default: 50. |
Response 200 — Queue.
| Field | Type | Description |
|---|---|---|
workflow_id | string | |
workflow_status | string | |
counts | object | |
counts.pending | integer | |
counts.running | integer | |
counts.done | integer | |
counts.failed | integer | |
counts.cancelled | integer | |
waiting | integer | |
requests | object[] | |
requests[].id | string | |
requests[].file_name | string | |
requests[].file_urls | string[] | |
requests[].status | string ("pending", "running", "done", "failed", "cancelled") | |
requests[].queue_position | integer, nullable | |
requests[].run_version | integer, nullable | |
requests[].queued_at | string (date-time) | |
requests[].started_at | string (date-time), nullable | |
requests[].finished_at | string (date-time), nullable | |
requests[].duration_seconds | number, nullable | |
requests[].detail | string | |
requests[].is_branch | boolean | |
requests[].files | any[] | |
requests[].processed | integer, nullable | |
requests[].failed | integer, nullable | |
requests[].skipped | integer, nullable |
Example
bash
curl -X GET "https://api.example.com/microservices/workflow/<id>/webhook-queue/" \
-H "Authorization: Token $FINBLADE_TOKEN"POST /microservices/workflow/{id}/webhook-queue/{request_id}/
Retry or cancel a queued request
Auth: Session token · In the app: Queue panel → Retry / Cancel
Path parameters
| Field | Type | Required | Description |
|---|---|---|---|
id | string (uuid) | yes | |
request_id | string (uuid) | yes |
Request body (application/json)
| Field | Type | Required | Description |
|---|---|---|---|
action | string ("retry", "cancel") | yes |
Response 200 — New state.
| Field | Type | Description |
|---|---|---|
id | string | |
status | string | |
action | string |
Response 400 — Action not applicable to the request's state.
json
{
"error": "path is required"
}Example
bash
curl -X POST "https://api.example.com/microservices/workflow/<id>/webhook-queue/<request_id>/" \
-H "Authorization: Token $FINBLADE_TOKEN"