> ## Documentation Index
> Fetch the complete documentation index at: https://docs.voxworks.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Receiving Webhooks from Voxworks

> How to build an endpoint that receives outbound webhook deliveries from a Voxworks automation — payload shape, headers, retry behaviour, and the URL requirements your endpoint must meet.

## Overview

A Voxworks **automation** can end its pipeline with a **Destination** step of kind **Webhook**, which sends an HTTP request to a URL you control whenever the automation runs — for example, posting a call summary to your own backend after every completed call. This page is for the developer building the endpoint that receives those requests: what the request looks like, how to tell deliveries apart, what happens when your endpoint is slow or down, and what your URL needs to satisfy before Voxworks will send to it.

<Note>
  This page covers webhook deliveries **from** an automation's Destination step. It's a different feature from the **Send Webhook** tool that a Call Script can run mid-call — that tool has its own timeout and no retry behaviour. See [Send Webhook](/tools/webhook) if you're looking for that. For the inbound direction — sending data *into* Voxworks to trigger an automation — see [Triggers](/automations/triggers).
</Note>

***

## Setting up a webhook destination

In an automation's pipeline builder, a **Destination** step configured with kind **Webhook** exposes:

| Field                        | Description                                                                                                          |
| ---------------------------- | -------------------------------------------------------------------------------------------------------------------- |
| **Method**                   | `GET`, `POST`, `PUT`, or `PATCH`. Defaults to `POST`.                                                                |
| **URL**                      | The endpoint Voxworks sends the request to. Supports `{{path}}` interpolation from the pipeline context (see below). |
| **Headers**                  | Any custom headers to add, as key/value pairs. Supports `{{path}}` interpolation in values.                          |
| **Body Template** (optional) | A JSON template with `{{path}}` placeholders, e.g. `{"result": "{{call.call_summary}}"}`.                            |

`{{path}}` placeholders resolve against the automation's pipeline context — `trigger`, `call`, `contact`, `custom`, `source`, `mapped`, `results`, `automation_id`, `execution_id`, and `created_by` — the same context used throughout the pipeline. See [Field Mapping & Context](/automations/field-mapping) for the full reference of what's available at each field.

If you leave **Body Template** blank, Voxworks sends the request with **no body at all** — there's no automatic default payload built from the trigger data. If you want the trigger or call data in the request, put it in the Body Template explicitly.

***

## Request shape

* **Method and URL** — exactly as configured on the step, after `{{path}}` interpolation.
* **Content-Type** — set to `application/json` automatically whenever a JSON body is sent. If Body Template is empty, no body and no `Content-Type` header are sent.
* **Headers** — your configured headers, plus one header Voxworks always adds: `X-Execution-Id`.
* **Timeout** — Voxworks waits up to **30 seconds** for your endpoint to respond. This isn't configurable per step.

### The X-Execution-Id header

| Header           | Type          | Example                                | Description                                                                                                                                                             |
| ---------------- | ------------- | -------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `X-Execution-Id` | string (UUID) | `a1b2c3d4-5e6f-7890-abcd-ef1234567890` | The ID of the automation execution that produced this delivery. Identical across every retry of the same execution — use it to detect and discard duplicate deliveries. |

***

## Retries, backoff, and the duplicate-delivery caveat

Retries apply to the **automation execution as a whole**, not to the webhook delivery in isolation. An automation's pipeline runs top to bottom; if any step other than a Destination step raises an error, the whole execution is scheduled to run again later. Destination steps (including webhook deliveries) are treated as independent — if a webhook delivery itself fails (connection error, timeout, or a blocked URL), that step is recorded as failed and the pipeline continues to the next step, but **that failure alone does not schedule a retry**.

This has an important consequence: if a webhook Destination step succeeds, but a *later* step in the same pipeline (an Upsert Contact, an Upsert Custom Variable, a Create Call, and so on) fails, the entire execution is retried from the beginning — including the webhook step that already succeeded. Your endpoint will receive the same request again, with the same `X-Execution-Id`, even though the first delivery went through fine.

<Warning>
  Because of this, a webhook destination can be delivered more than once for the same automation execution. Always dedupe on `X-Execution-Id` rather than assuming one delivery per event.
</Warning>

When a retry is scheduled, the delay before the next attempt grows with each failure:

| Attempt | Delay before this attempt |
| ------- | ------------------------- |
| 1       | — (runs immediately)      |
| 2       | 10 seconds                |
| 3       | 30 seconds                |
| 4       | 90 seconds                |
| 5       | 270 seconds (4.5 minutes) |

An execution gets up to **5 attempts**. If it's still failing after the 5th, it's marked **Dead Letter** and stops retrying.

Two more behaviours worth knowing when you're designing around this:

* **Non-2xx responses from your endpoint aren't treated as failures.** Voxworks records whatever status code and body your endpoint returns, but it doesn't inspect the status code to decide whether to retry — only a network-level failure (connection error, DNS failure, timeout) on a *non*-Destination step schedules a retry. Returning `500` from your webhook endpoint will not, by itself, cause Voxworks to resend that delivery.
* **A blocked or unreachable webhook URL doesn't stop the rest of the pipeline.** If your URL fails validation or the request errors, the Destination step is marked failed in the Execution Log and the automation continues to any steps after it.

***

## URL and network requirements

Every webhook URL — checked fresh on every attempt, after `{{path}}` interpolation — must satisfy:

* **Scheme** — `http` or `https` only.
* **A resolvable hostname.** URLs whose hostname can't be resolved are rejected outright.
* **No private, loopback, or link-local addresses.** Voxworks blocks requests to:
  * `10.0.0.0/8`, `172.16.0.0/12`, `192.168.0.0/16` (private ranges)
  * `127.0.0.0/8` (loopback)
  * `169.254.0.0/16` (link-local — this also covers common cloud metadata endpoints)
  * `0.0.0.0/8`
  * `::1/128` and `fd00::/8` (IPv6 loopback and unique local addresses)
  * the hostnames `metadata.google.internal` and `metadata.google.com` explicitly

In practice: your webhook URL needs to be a publicly routable `http`/`https` address. Internal, localhost, or cloud-metadata URLs are rejected before any request is sent.

There's currently no request-signing header (no HMAC) on outbound webhook deliveries — `X-Execution-Id` is the only Voxworks-added header. If you need to confirm a request genuinely came from Voxworks, treat the URL itself (a long, unguessable path) as the shared secret rather than expecting a signature to verify.

***

## Response logging

Every automation run appears in the automation's **Execution Log** (Automations > select an automation > **Execution Log**). Expanding a run shows each pipeline step and its result — for a webhook Destination step, that includes the status code and response body Voxworks received back from your endpoint.

Response bodies are captured for logging up to **10KB**; anything your endpoint returns beyond that is truncated. See [Execution Log & Monitoring](/automations/execution-log) for the full breakdown of statuses and what's stored per run.

***

## Recommended endpoint patterns

* **Dedupe on `X-Execution-Id`.** Store recently seen IDs and skip processing a request you've already handled — this is the only reliable way to make repeat deliveries safe, given the duplicate-delivery caveat above.
* **Respond quickly.** Voxworks waits up to 30 seconds; if your processing is slow, acknowledge the request immediately with a `2xx` and do the real work asynchronously rather than making Voxworks wait on it.
* **Validate the payload defensively.** The body shape is whatever your team configured in Body Template — treat it as untrusted input and check for the fields you expect before using them.
* **Use HTTPS.** `http` is accepted, but an endpoint on the public internet should be encrypted.
* **Don't rely on your response code to trigger a resend.** As covered above, returning an error doesn't make Voxworks retry that delivery — if you need guaranteed reprocessing, handle that on your own side (e.g. a dead-letter queue on your endpoint).

***

## Next Steps

<CardGroup cols={2}>
  <Card title="Automations" href="/automations/overview">
    How automations, triggers, and pipelines fit together.
  </Card>

  <Card title="Steps" href="/automations/steps">
    Every pipeline step type, including the Destination step's other kinds (SMS, email, integration sync).
  </Card>

  <Card title="Field Mapping & Context" href="/automations/field-mapping">
    The full pipeline context reference for building your Body Template.
  </Card>

  <Card title="Execution Log & Monitoring" href="/automations/execution-log">
    Read run history, attempts, and per-step results for an automation.
  </Card>
</CardGroup>
