Skip to content

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 with workflow_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 ​

MethodPathPurpose
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_secret from GET /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)

FieldTypeRequiredDescription
webhook_idstringyes
webhook_secretstringyes
payloadobjectnoInput for the run (webhook_payload accepted as an alias).
is_branchbooleannoWorkflow credential only — run a branch instead of the whole workflow.
start_node_idstringnoWith is_branch on a workflow credential — the spec node to start at.
run_to_the_endbooleannoDefault: 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.

FieldTypeDescription
messagestring
request_idstring (uuid)
queuedboolean
queue_positioninteger0 when started immediately.
workflow_idstring (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

FieldTypeRequiredDescription
webhook_idstringyes
webhook_secretstringyes
include_outputbooleannoDefault: false.

Response 200 — Status.

FieldTypeDescription
workflow_idstring
workflow_namestring
statusstring ("IDLE", "PENDING", "RUNNING", "COMPLETED", "FAILED", "STOPPED")
current_run_versioninteger, nullable
updated_atstring (date-time)
nodesobject[]
nodes[].node_idstring
nodes[].kindstring
nodes[].statusstring
nodes[].attempt_countinteger
nodes[].started_atstring (date-time), nullable
nodes[].finished_atstring (date-time), nullable
nodes[].outputobjectOnly 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

FieldTypeRequiredDescription
idstring (uuid)yes
node_idstringyesSpec node id.

Response 200 — Credential.

FieldTypeDescription
workflow_idstring
node_idstring
webhook_idstring
webhook_secretstring
is_branchboolean
createdboolean
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

FieldTypeRequiredDescription
idstring (uuid)yes

Query parameters

FieldTypeRequiredDescription
limitintegernoDefault: 50.

Response 200 — Queue.

FieldTypeDescription
workflow_idstring
workflow_statusstring
countsobject
counts.pendinginteger
counts.runninginteger
counts.doneinteger
counts.failedinteger
counts.cancelledinteger
waitinginteger
requestsobject[]
requests[].idstring
requests[].file_namestring
requests[].file_urlsstring[]
requests[].statusstring ("pending", "running", "done", "failed", "cancelled")
requests[].queue_positioninteger, nullable
requests[].run_versioninteger, nullable
requests[].queued_atstring (date-time)
requests[].started_atstring (date-time), nullable
requests[].finished_atstring (date-time), nullable
requests[].duration_secondsnumber, nullable
requests[].detailstring
requests[].is_branchboolean
requests[].filesany[]
requests[].processedinteger, nullable
requests[].failedinteger, nullable
requests[].skippedinteger, 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

FieldTypeRequiredDescription
idstring (uuid)yes
request_idstring (uuid)yes

Request body (application/json)

FieldTypeRequiredDescription
actionstring ("retry", "cancel")yes

Response 200 — New state.

FieldTypeDescription
idstring
statusstring
actionstring

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"

Finblade documentation