Webhook API
How to call a flow's webhook URL to start a run. To set up the trigger, see Start a flow from a webhook.
URL
https://<organization ID>.<domain>/triggers/<webhook ID>Each Webhook trigger has its own URL, shown as Hook URL in the trigger's settings. Copy it from there. Duplicating or importing a flow gives the copy a new URL.
The URL only starts runs while the flow is published and turned on.
Authentication
Send the trigger's Hook API Key as a Bearer token:
Authorization: Bearer <Hook API Key>X-Authorization: Bearer <Hook API Key> works too, for callers that use Authorization for something else.
Methods
| Method | Body |
|---|---|
POST | A JSON object in the request body. Use this one. |
GET | A JSON object in the body or payload query parameter, URL-encoded. The key can go in a token query parameter instead of a header. |
Prefer POST with the key in a header. Query parameters, including a key in token, can end up in server and proxy logs.
Request body
Send a JSON object with Content-Type: application/json. An empty body is allowed.
curl -X POST 'https://<organization ID>.<domain>/triggers/<webhook ID>' \
-H 'Authorization: Bearer <Hook API Key>' \
-H 'Content-Type: application/json' \
-d '{"orderId": "A-1001", "total": 4200}'The object becomes the trigger's output, so a later step reads orderId as $trigger.output.orderId.
| You send | Trigger output |
|---|---|
{"orderId": "A-1001"} | {"orderId": "A-1001", …} |
{"data": {"orderId": "A-1001"}} | {"orderId": "A-1001", …}. A top-level data field is unwrapped. |
| No body | {…} with only the fields below. |
The output always gets two more fields, which replace any you send with the same names:
| Field | Value |
|---|---|
triggerType | webhook |
timestamp | When the trigger ran, in milliseconds since 1970. |
The body must be a JSON object. A list, such as [1, 2], is rejected. To send a list, wrap it: {"items": [1, 2]}.
Response
The webhook responds as soon as it has accepted the request. The run starts after that, so the response never contains the flow's result.
200 OK:
{
"result": "ok",
"details": {
"message": "Workflow executed successfully",
"organizationId": "01HAXD218S50F6YY4JF2F92FZF",
"webhookId": "…",
"runId": "…",
"messageId": "…",
"timestamp": 1744702070657,
"requestId": "…"
}
}A 200 means the request was received and queued. It doesn't check whether the flow is published or turned on. If it isn't, you still get 200 but no run starts. Check Executions to confirm a run.
To get a result back, have the flow call your system at the end, for example with an HTTP step.
Errors
Errors return a JSON body with an error and a details.message:
{
"error": "Unauthorized",
"details": {
"message": "Invalid authorization token",
"type": "Authentication Error"
}
}| Status | error | Cause |
|---|---|---|
400 | Invalid request | The URL is missing its organization or webhook ID. |
400 | Invalid request body | The body isn't a JSON object, for example a list. details.errors says what's wrong. |
401 | Unauthorized | No key was sent, or the key is wrong. |
500 | Internal server error | The body isn't valid JSON, or the request couldn't be processed. Check the body, then retry. |