What you get
Set a webhook URL on a workflow and Bolna sends your server one request per execution, at the moment that execution finishes. There is no request per node — the single payload carries the outcome plus the complete trail of every node the contact passed through, so you can reconstruct the whole journey without polling. Every execution reports when it finishes, not just the ones that finish happily. A contact whose call never connected, a run you cancelled, and a run still in flight when you aborted its campaign all send a webhook, with astatus and termination_reason that tell you which. Contacts still waiting to start when a campaign is aborted never begin an execution, so they send nothing.
This is separate from the call status webhook, which fires per phone call. A workflow that places two calls sends two call webhooks and one execution webhook.
Configuring it
The webhook lives in the workflow’ssettings. Set it with the Update Workflow API:
headers are sent with every delivery and are the usual way to authenticate the request as genuinely from Bolna.
A few rules the URL has to satisfy:
httpsonly, on port 443 or 8443.- No internal IP addresses. A host that is a private, loopback, link-local or carrier-NAT IP address is rejected, including alternate spellings of one.
- Redirects are not followed. Point the URL at its final destination — a server that answers with a redirect is treated as not having received the webhook.
Changing it later
settings is merged into what is already stored, so you only send what changes:
Moving the URL to a different host or port drops the stored headers, so a credential only ever goes to the host it was entered for. Send the headers again in the same request. Renaming a workflow never touches its webhook.
Reading it back
GET /workflows/{workflow_id} returns the settings with every header value masked:
********** back as a value is rejected.
Testing it before you run anything
1
Publish the workflow
The sample is built from your published graph, so publish first.
2
Fire a test
Call the Test Webhook API:
3
Read the verdict
delivered is true only for a 2xx reply. error_type: "http_error" means your server was reached and replied with anything else, redirects included; "unreachable" means it could not be contacted at all.The payload
Every field is also described on the Execution webhook payload reference page.
Reading the trail
Each entry is one attempt at one node. A node reached twice through a retry appears twice, withattempt 1 and 2. to_node_id is the node it moved to next, and matched_case_index is which of that node’s branches matched — so the trail is the exact route through your workflow, not a summary of it.
outputs keys are namespaced by what produced them: call.* from an agent node, extraction.* for each disposition you selected, response.* from an API node, whatsapp.* from a WhatsApp node.
Status combinations worth handling
Reaching any end node produces
status: "completed", including one you labelled a failure. To separate genuine successes from handled failures, read outcome, not status.
What to expect in delivery
- One delivery per execution. A duplicate is not expected, but a resend delivers the same payload again, so key your handler on
execution_id. - No ordering between executions. Two executions finishing at the same moment can arrive in either order. Each payload is self-contained, so this only matters if you are sequencing across contacts yourself.
execution_idis stable and is the same id the execution APIs use, so you can always fetch the full record if a delivery is missed.
Resending a webhook
Call the Resend Webhook API with the execution’s id:occurred_at included. That makes it the way to recover a delivery your server missed, and to redeliver after correcting a wrong URL. The response is 202 once the webhook is queued; the execution must have finished, and its workflow must have a webhook configured.
