
Core Plugins and tasks Webhook
CertifiedTrigger a Flow via an authenticated webhook URL.
Core Plugins and tasks Webhook
Trigger a Flow via an authenticated webhook URL.
Exposes a signed endpoint .../executions/webhook/{Namespace}/{flowId}/{key} that accepts GET/POST/PUT to start a Flow. Secured by the required key; keep it secret.
Request data is available as trigger.body, trigger.headers, and trigger.parameters. A binary body is base64-encoded on trigger.body, unless fetchType is set to STORE to stream it into Kestra's internal storage and expose it as trigger.uri instead. A multipart/form-data body is available as trigger.parts (files, always stored in Kestra's internal storage) and trigger.formFields. Supports wait/returnOutputs to block and return Flow outputs, and optional responseContentType. Conditions are allowed except MultipleCondition.
Responses: 404 (not found), 200 (triggered), 204 (conditions not met), 422 (inputs could not be rendered).
type: io.kestra.plugin.core.trigger.WebhookExamples
Add a webhook trigger to the current flow with the key 4wjtkzwVGBM9yKnjm3yv8r; the webhook will be available at the URI /api/v1/{tenant}/executions/webhook/{namespace}/{flowId}/4wjtkzwVGBM9yKnjm3yv8r.
id: webhook_flow
namespace: company.team
tasks:
- id: log_hello_world
type: io.kestra.plugin.core.log.Log
message: Hello World! 🚀
triggers:
- id: webhook
type: io.kestra.plugin.core.trigger.Webhook
key: 4wjtkzwVGBM9yKnjm3yv8r
Add a trigger matching specific webhook event condition. The flow will be executed only if the condition is met.
id: condition_based_webhook_flow
namespace: company.team
tasks:
- id: log_hello_world
type: io.kestra.plugin.core.log.Log
message: Hello World! 🚀
triggers:
- id: webhook
type: io.kestra.plugin.core.trigger.Webhook
key: 4wjtkzwVGBM9yKnjm3yv8r
when: "{{ trigger.body.hello == 'world' }}"
Webhook with text/plain response for Microsoft Graph validation handshakes. When a service like Microsoft Graph validates the webhook endpoint, it sends a validationToken that must be echoed back as plain text.
id: microsoft_graph_webhook
namespace: company.team
tasks:
- id: handle_request
type: io.kestra.plugin.core.debug.Return
format: "{{ trigger.parameters.validationToken[0] ?? 'notification processed' }}"
outputs:
- id: response
type: STRING
value: "{{ outputs.handle_request.value }}"
triggers:
- id: webhook
type: io.kestra.plugin.core.trigger.Webhook
key: 4wjtkzwVGBM9yKnjm3yv8r
wait: true
returnOutputs: true
responseContentType: "text/plain"
Receive a file uploaded as multipart/form-data. Each file part is available under trigger.parts,
its content stored in Kestra's internal storage and reachable through its uri, and the parts that are
not files under trigger.formFields.
id: upload_webhook
namespace: company.team
tasks:
- id: log_upload
type: io.kestra.plugin.core.log.Log
message: "Received {{ trigger.parts[0].filename }} ({{ trigger.parts[0].size }} bytes, {{ trigger.parts[0].contentType }}), note: {{ trigger.formFields.note[0] }}"
- id: measure_upload
type: io.kestra.plugin.core.storage.Size
uri: "{{ trigger.parts[0].uri }}"
triggers:
- id: webhook
type: io.kestra.plugin.core.trigger.Webhook
key: 4wjtkzwVGBM9yKnjm3yv8r
Receive a payload that is not a form - a large JSON export, or a binary file sent as the request body -
without carrying it through the execution. fetchType: STORE streams the body into Kestra's internal
storage and exposes its URI as trigger.uri instead of its content as trigger.body. Note that a
condition on the trigger can no longer read the body.
id: stored_body_webhook
namespace: company.team
tasks:
- id: measure_body
type: io.kestra.plugin.core.storage.Size
uri: "{{ trigger.uri }}"
triggers:
- id: webhook
type: io.kestra.plugin.core.trigger.Webhook
key: 4wjtkzwVGBM9yKnjm3yv8r
fetchType: STORE
Properties
key *Requiredstring
1256The unique key that will be part of the URL.
The key is used for generating the webhook URL.
::alert{type="warning"} Make sure to keep the webhook key secure. It's the only security mechanism to protect your endpoint from bad actors, and must be considered as a secret. You can use a random key generator to create the key. ::
allowConcurrent Non-dynamicboolean
falseSpecifies whether a trigger is allowed to start a new execution even if a previous run is still in progress.
fetchType Non-dynamicstring
FETCHNONEFETCHSTOREWhat the trigger does with the body of the webhook request.
FETCH: the body reaches the flow on thebodyoutput. A JSON body is deserialized, a binary one is base64-encoded. This is the default, and how a webhook has always behaved.STORE: the body is streamed into Kestra's internal storage as it is received, and the flow reaches it through theurioutput. Nothing of it travels through the execution, so this is the option to use for a large or binary payload - but note that a condition on the trigger can no longer read the body.NONE: the body is read off the connection and dropped. Use it for a caller whose payload the flow does not need.
This only concerns the body of a request. The file parts of a multipart/form-data request are always stored in the internal storage and exposed on parts, whatever this property is set to, as a file part has no meaningful representation inside an execution.
inputs object
The inputs to pass to the triggered flow
responseCode integerstring
Custom response code.
If set, the webhook response code will use this response code instead of the default 200.
Requires wait and returnOutputs to be true.
responseContentType Non-dynamicstring
application/jsontext/plainCustom response content type.
If set, the webhook response will use this content type instead of the default application/json.
Requires wait and returnOutputs to be true.
This is useful for webhook validation handshakes that require specific content types (e.g., Microsoft Graph Change Notifications require text/plain responses).
returnOutputs Non-dynamicboolean
falseSend outputs of the flows as response for webhook caller.
Requires wait to be true.
stopAfter Non-dynamicarray
CREATEDSUBMITTEDRUNNINGPAUSEDRESTARTEDKILLINGSUCCESSWARNINGFAILEDKILLEDCANCELLEDQUEUEDRETRYINGRETRIEDSKIPPEDBREAKPOINTRESUBMITTEDList of execution states after which a trigger should be stopped (a.k.a. disabled).
wait Non-dynamicboolean
falseWait for the flow to finish.
If set to true the webhook call will wait for the flow to finish and return the flow outputs as response.
If set to false the webhook call will return immediately after the execution is created.
when string
trueA condition that determines whether the trigger should run.
A Pebble expression evaluated at trigger time. The trigger fires only when the expression evaluates to a truthy value (true, a non-empty string, a non-zero number). Use this to gate trigger execution on dynamic runtime values such as execution labels, flow variables, or environment conditions.
Outputs
body *Requiredobject
The full body for the webhook request
We try to deserialize the incoming request as JSON (array or object).
If we can't deserialize, the full body will be available as a string.
A binary body - one whose content type is neither text, JSON, XML, form-urlencoded, YAML nor CSV - is base64-encoded, as base64 is how bytes travel through the text-based trigger variables. Use the content-type request header to tell a base64-encoded body apart from a plain text one.
Only set for a trigger whose fetchType is FETCH, and not for a multipart/form-data request, which is available as parts and formFields.
headers *Requiredobject
The headers for the webhook request
parameters *Requiredobject
The parameters for the webhook request
formFields object
The form fields of a multipart/form-data webhook request
Only set for a multipart/form-data request; holds the parts that are not files.
parts array
The file parts of a multipart/form-data webhook request
Only set for a multipart/form-data request. The content of each part is stored in Kestra's internal storage, and the part carries its URI.
A file part of a `multipart/form-data` webhook request
The content type of the part
Not set if the caller did not send one for this part.
The name of the uploaded file
The form field name of the part
The size of the part content in bytes
The URI of the part content in Kestra's internal storage
The content of the part is streamed to the internal storage as it is received, so that a file of any size reaches the flow intact and without travelling through the execution. It is stored under the execution the webhook call creates, and purged with it.
uri string
The URI of the body of the webhook request in Kestra's internal storage
Only set for a trigger whose fetchType is STORE. The body is streamed to the internal storage as it is received, so that a payload of any size reaches the flow intact and without travelling through the execution. It is stored under the execution the webhook call creates, and purged with it.