New to Kestra?
Use blueprints to kickstart your first workflows.
Build a Kestra webhook that runs Python and returns XML output, perfect for legacy integrations, SOAP partners, and on-demand API endpoints.
Expose a synchronous HTTP webhook in Kestra that accepts a POST request, runs a Python script to build a structured XML document, and returns the serialized XML payload to the caller in the same request. This blueprint shows how to turn a Kestra flow into an on-demand API endpoint that bridges modern orchestration with legacy systems and partners that still consume XML rather than JSON.
io.kestra.plugin.core.trigger.Webhook trigger publishes a unique URL secured by a webhook key loaded from {{ secret('WEBHOOK_SECRET_KEY') }}. The trigger has wait: true so the HTTP caller is held open until the flow finishes, and returnOutputs: true so the task outputs are returned in the response body.build_xml task (io.kestra.plugin.scripts.python.Script) uses Python's standard xml.etree.ElementTree to construct a root element with child fields, serializes it to a string, and emits it via Kestra.outputs({"xml": xml_string}).outputs.build_xml.vars.xml field. Callers read that field and treat it as XML. For pure application/xml responses, front the flow with an API gateway that rewrites the content type.A raw web framework can return XML, but it cannot natively retry the upstream data fetch, version the response logic, replay a failed call, or give you lineage across the pipeline that produced the payload. Kestra adds event-driven webhook triggers, declarative YAML, retries and timeouts on every task, a full execution log per request, and the ability to chain the same logic into scheduled or queue-driven flows. You get an API endpoint plus a fully observable workflow behind it.
WEBHOOK_SECRET_KEY: the webhook key embedded in the trigger URL, used to authorize incoming POST requests.WEBHOOK_SECRET_KEY secret in your Kestra instance.outputs.build_xml.vars.xml from the response to get the XML document.data dictionary with values read from {{ trigger.body }} to echo request data back as XML.ElementTree for lxml to emit pretty-printed or namespaced XML, including SOAP envelopes.application/xml for strict clients.