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

# Use Call Data in Webhook URLs and Headers

> Insert call variables such as callAdditionalData into the URL, query string, headers and body of tool, result, start and HTTP transfer webhooks.

Put data from the call straight into a webhook request. Write a variable such as `{{callAdditionalData.orderId}}` in the webhook URL, a header, a query parameter or the body, and Dasha BlackBox replaces it with the real value before it sends the request.

**What you'll learn:** Where variables work, which variables exist, how to change the HTTP method, query string and body, and how to test the result.

***

## Quick example

You create a call with this additional data:

```json theme={"theme":{"light":"github-light","dark":"github-dark"}}
{
  "additionalData": { "customerId": "c-42" }
}
```

You configure a tool webhook like this:

| Field              | Value                                                                        |
| ------------------ | ---------------------------------------------------------------------------- |
| Webhook URL        | `https://api.example.com/customers/{{callAdditionalData.customerId}}/orders` |
| Header `X-Call-Id` | `{{callId}}`                                                                 |

Your API receives:

```http theme={"theme":{"light":"github-light","dark":"github-dark"}}
POST https://api.example.com/customers/c-42/orders
X-Call-Id: 67890abcdef123456789
Content-Type: application/json
```

The body is still the standard JSON payload for that webhook. Templating changes only the parts you put variables in.

***

## Where variables work

Variables work the same way in all four webhooks:

| Webhook               | Configure in                                       |
| --------------------- | -------------------------------------------------- |
| Tool webhook          | Agent → **Tools** → tool editor                    |
| Result webhook        | Agent → **Webhooks** → Result Webhooks             |
| Start webhook         | Agent → **Webhooks** → Start Webhooks              |
| HTTP transfer webhook | Agent → call transfer settings → **HTTP** transfer |

Within a webhook, you can use variables in:

| Part of the request                  | Example                                                                |
| ------------------------------------ | ---------------------------------------------------------------------- |
| URL path                             | `https://api.example.com/orders/{{callAdditionalData.orderId}}`        |
| URL query string                     | `https://api.example.com/orders?tenant={{agentAdditionalData.tenant}}` |
| Header names and values              | `X-Tenant: {{agentAdditionalData.tenant}}`                             |
| Query parameters (advanced settings) | `status` = `{{arguments.status}}`                                      |
| Request body (advanced settings)     | `{ "order": "{{callAdditionalData.orderId}}" }`                        |

In the dashboard, every field that accepts variables has a **`{ }`** button. Click it to pick a variable from the list for that webhook. For **callAdditionalData.** and **agentAdditionalData.**, pick the entry and type your own key. The cursor stays inside the braces.

<Note>
  Existing webhooks are not affected. A webhook without variables or advanced settings is sent exactly as before, with the same JSON payload.
</Note>

***

## Variable reference

A variable is a path into the webhook's JSON payload. Every field described in [Webhook Events](/docs/webhooks-and-events/webhook-events) is available.

### Available in every webhook

| Variable                                                                       | Value                                                                                       |
| ------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------- |
| `{{callAdditionalData.<key>}}`                                                 | Additional data you pass when you create or [register](/docs/deploy/register-call) the call |
| `{{agentAdditionalData.<key>}}`                                                | The agent's own **Additional Data**                                                         |
| `{{callId}}`                                                                   | Unique ID of the call                                                                       |
| `{{agentId}}`                                                                  | ID of the agent handling the call                                                           |
| `{{orgId}}`                                                                    | Your organization ID                                                                        |
| `{{endpoint}}`                                                                 | Phone number or endpoint of the call                                                        |
| `{{serverJobId}}`                                                              | Internal conversation job ID, useful for support requests                                   |
| `{{sip.fromUser}}`, `{{sip.fromDomain}}`, `{{sip.toUser}}`, `{{sip.toDomain}}` | Caller and callee SIP details, on inbound phone calls only                                  |

### Specific to one webhook

<Tabs>
  <Tab title="Tool">
    | Variable               | Value                                                                    |
    | ---------------------- | ------------------------------------------------------------------------ |
    | `{{arguments.<name>}}` | An argument the language model produced, as defined in the tool's schema |
    | `{{toolName}}`         | Name of the tool being called                                            |
  </Tab>

  <Tab title="Result">
    One result webhook receives completed, failed and deadline calls. Some variables exist only for some of these outcomes.

    | Variable                                               | Available for                                                                         |
    | ------------------------------------------------------ | ------------------------------------------------------------------------------------- |
    | `{{status}}`                                           | All outcomes: `Completed`, `Failed` or `Canceled`                                     |
    | `{{callType}}`, `{{createdTime}}`, `{{completedTime}}` | All outcomes                                                                          |
    | `{{durationSeconds}}`, `{{inspectorUrl}}`              | Completed and failed calls                                                            |
    | `{{recordingUrl}}`                                     | Completed and failed calls that were recorded                                         |
    | `{{result.finishReason}}`                              | Completed calls                                                                       |
    | `{{result.postCallAnalysis.<key>}}`                    | Completed calls with [post-call analysis](/docs/advanced-features/post-call-analysis) |
    | `{{errorMessage}}`                                     | Failed calls                                                                          |
    | `{{reasonMessage}}`                                    | Deadline (canceled) calls                                                             |
  </Tab>

  <Tab title="Start">
    The start webhook has no extra variables of its own. `callAdditionalData` holds the data passed when the call was created. Data returned by the start webhook itself is added afterwards.
  </Tab>

  <Tab title="HTTP transfer">
    | Variable             | Value                                                      |
    | -------------------- | ---------------------------------------------------------- |
    | `{{transferReason}}` | The agent's explanation of why it is transferring the call |
  </Tab>
</Tabs>

***

## How values are rendered

| Rule                  | Detail                                                                                                                                                    |
| --------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Syntax                | `{{path}}`. Spaces inside the braces are ignored: `{{ callId }}` works.                                                                                   |
| Nested values         | Use dots: `{{callAdditionalData.customer.id}}`. Use a number for a list item: `{{callAdditionalData.items.0.sku}}`.                                       |
| Text and numbers      | Inserted as they are. `true`, `false` and `null` are inserted as those words.                                                                             |
| Objects and lists     | Inserted as raw JSON text.                                                                                                                                |
| Missing value         | The variable is **sent as written**, for example a literal `{{callAdditionalData.orderId}}`. Make sure every call supplies the keys you reference.        |
| Query string encoding | Query values are fully URL-encoded, so free-form text is safe there.                                                                                      |
| Path encoding         | Path values are only lightly encoded: `/`, `?` and `#` are not escaped. Use URL-safe identifiers in the path and put free-form text in a query parameter. |
| Empty values          | A query parameter or header whose value renders to empty text is left out of the request.                                                                 |

***

## Advanced request settings

Open **Advanced request settings** under the headers to change the request itself.

| Setting              | Options                                                            |
| -------------------- | ------------------------------------------------------------------ |
| **HTTP Method**      | `POST` (default), `GET`, `PUT`, `PATCH`, `DELETE`                  |
| **Query Parameters** | Name and value pairs appended to the URL. Values accept variables. |
| **Request Body**     | `Default`, `Raw text`, `JSON object` or `Form (url-encoded)`       |

<Warning>
  `GET` requests are sent without a body. Your API receives only the URL, query parameters and headers. Put everything it needs into those.
</Warning>

### Request body formats

| Format             | Content type                        | What is sent                                            |
| ------------------ | ----------------------------------- | ------------------------------------------------------- |
| Default            | `application/json`                  | The standard payload for that webhook. Nothing changes. |
| Raw text           | `text/plain`                        | Your text template with variables replaced              |
| JSON object        | `application/json`                  | A JSON object you build field by field                  |
| Form (url-encoded) | `application/x-www-form-urlencoded` | Form fields you build field by field                    |

For **JSON object** and **Form**, each row has a field name and a value:

* For JSON, the field name is a dotted path in the output, so `customer.id` creates `{ "customer": { "id": … } }`.
* A value that is exactly one variable, such as `{{arguments.units}}`, keeps its original type: a number stays a number. You can add a **fallback** used when the variable is missing.
* Any other value is a literal or a text template, such as `order-{{callAdditionalData.orderId}}`.

<Warning>
  Changing the body format of a **result** or **start** webhook replaces the standard payload. Your endpoint then receives only the fields you map. For the start webhook, your endpoint must still [return an accept or reject response](/docs/webhooks-and-events/webhook-events#start-webhook-response).
</Warning>

***

## Configure in the dashboard

<Steps>
  <Step title="Pass the data with the call">
    Include `additionalData` when you create or register the call, for example `{ "customerId": "c-42" }`.
  </Step>

  <Step title="Open the webhook">
    Open the tool, the result or start webhook, or the HTTP transfer you want to change.
  </Step>

  <Step title="Insert variables">
    In **Webhook URL** or a header value, click **`{ }`** and pick a variable. For custom data, pick **callAdditionalData.** and type the key.
  </Step>

  <Step title="Adjust the request if needed">
    Open **Advanced request settings** to change the method, add query parameters or change the body.
  </Step>

  <Step title="Test and save">
    Fill in **Test values for custom data**, click **Test Tool** or **Test Webhook**, and check **Request Sent**. Then save.
  </Step>
</Steps>

An amber **Unknown variable** hint under a field means the name is not in the list for that webhook. Check it for typos.

***

## Configure via API

Set `customSettings` on the webhook object. This example is a tool webhook that sends a `GET` request:

```json theme={"theme":{"light":"github-light","dark":"github-dark"}}
{
  "webhook": {
    "url": "https://api.example.com/customers/{{callAdditionalData.customerId}}/orders",
    "headers": {
      "Authorization": "Bearer your-webhook-key",
      "X-Call-Id": "{{callId}}"
    },
    "customSettings": {
      "httpMethod": "GET",
      "queryParams": {
        "status": ["{{arguments.status}}"],
        "tenant": ["{{agentAdditionalData.tenant}}"]
      }
    }
  }
}
```

The same `webhook` object shape is used by `config.resultWebhook`, `config.startWebhook.webhook` and the HTTP transfer `webhook`.

<Warning>
  Variables are replaced **only when the webhook has `customSettings`**. Without it, the URL and headers are sent exactly as written, including the braces. If you only need variables, add the minimal setting `"customSettings": { "httpMethod": "POST" }`. The dashboard adds this for you when a URL or header contains a variable.
</Warning>

<Accordion title="customSettings reference">
  | Field                 | Type                | Description                                                                                            |
  | --------------------- | ------------------- | ------------------------------------------------------------------------------------------------------ |
  | `httpMethod`          | `string`            | `GET`, `POST`, `PUT`, `PATCH` or `DELETE`. Required.                                                   |
  | `queryParams`         | `object`            | Map of parameter name to a list of values. A name with several values is repeated in the query string. |
  | `bodyFormat`          | `object`            | Omit it to send the standard payload.                                                                  |
  | `bodyFormat.type`     | `string`            | `Text`, `Json` or `Form`                                                                               |
  | `bodyFormat.template` | `string` or `array` | For `Text`, the text template. For `Json` and `Form`, a list of field mappings.                        |

  Each field mapping has:

  | Field              | Description                                                                                                  |
  | ------------------ | ------------------------------------------------------------------------------------------------------------ |
  | `jsonPath`         | Output path (JSON) or field name (form). Required.                                                           |
  | `argumentJsonPath` | Path in the webhook payload to copy from, without braces, such as `arguments.units`. Keeps the value's type. |
  | `defaultValue`     | Used when `argumentJsonPath` is not set or the path is missing. Text inside it may contain variables.        |
</Accordion>

<Accordion title="Example: build a JSON body">
  ```json theme={"theme":{"light":"github-light","dark":"github-dark"}}
  {
    "customSettings": {
      "httpMethod": "POST",
      "bodyFormat": {
        "type": "Json",
        "template": [
          { "jsonPath": "customer.id", "argumentJsonPath": "callAdditionalData.customerId" },
          { "jsonPath": "units", "argumentJsonPath": "arguments.units", "defaultValue": "metric" },
          { "jsonPath": "source", "defaultValue": "voice-agent" },
          { "jsonPath": "reference", "defaultValue": "call-{{callId}}" }
        ]
      }
    }
  }
  ```

  Request body:

  ```json theme={"theme":{"light":"github-light","dark":"github-dark"}}
  {
    "customer": { "id": "c-42" },
    "units": "imperial",
    "source": "voice-agent",
    "reference": "call-67890abcdef123456789"
  }
  ```
</Accordion>

***

## Test with sample values

`callAdditionalData` and `agentAdditionalData` exist only on a real call, so a test needs stand-in values.

**In the dashboard:** the editor shows **Test values for custom data** with one input for every custom-data variable the webhook uses. Sample values are never saved. A blank `agentAdditionalData` value falls back to the agent's real Additional Data. The test result includes **Request Sent**, the exact URL, headers and body that were sent.

**Via API:** pass the values to the test endpoint:

```javascript theme={"theme":{"light":"github-light","dark":"github-dark"}}
const response = await fetch('https://blackbox.dasha.ai/api/v1/webhooks/test', {
  method: 'POST',
  headers: {
    'Authorization': 'Bearer YOUR_API_KEY',
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({
    webhookType: 'ToolWebHookPayload',
    toolName: 'get_orders',
    toolArguments: { status: 'open' },
    callAdditionalData: { customerId: 'c-42' },
    agentAdditionalData: { tenant: 'acme' },
    webHook: {
      url: 'https://api.example.com/customers/{{callAdditionalData.customerId}}/orders',
      customSettings: { httpMethod: 'GET', queryParams: { status: ['{{arguments.status}}'] } }
    }
  })
});

const result = await response.json();
console.log(result.sentRequest.url);
// https://api.example.com/customers/c-42/orders?status=open
```

See [Testing Webhooks](/docs/webhooks-and-events/testing-webhooks) for more testing methods.

***

## Good to know

* **One result webhook, three payloads.** A variable that a payload does not have is sent as written. Use variables that exist for every outcome, such as `{{status}}` or `{{callAdditionalData.<key>}}`, in the URL of a result webhook.
* **The URL is rebuilt when `customSettings` is set.** Ordinary URLs are unchanged. A query parameter with an empty value, such as `?flag=`, is left out, and an encoded slash (`%2F`) in the path is decoded. Give parameters a value and avoid encoded slashes in templated webhook URLs.
* **Query parameters merge.** A parameter in both the URL and the advanced settings is sent with both values.
* **Secrets stay in headers.** Put API keys in a header value, not in the URL, so they do not appear in access logs.

***

## Troubleshooting

| Symptom                                                        | Cause and fix                                                                                                      |
| -------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------ |
| Your API receives a literal `{{callAdditionalData.orderId}}`   | The call did not supply that key, or the key name differs in case. Check the call's `additionalData`.              |
| No variable is replaced at all                                 | The webhook was configured via API without `customSettings`. Add `"customSettings": { "httpMethod": "POST" }`.     |
| A result webhook works for completed calls but not failed ones | The variable exists only for completed calls. See the **Result** tab in [Variable reference](#variable-reference). |
| Your API receives no body                                      | The method is `GET`. Use `POST`, or move the data into query parameters.                                           |
| A query parameter is missing                                   | Its value rendered to empty text. Check the variable's value on that call.                                         |

***

## What's next

<CardGroup cols={2}>
  <Card title="Webhook Events" icon="bell" href="/docs/webhooks-and-events/webhook-events">
    Every payload field you can reference
  </Card>

  <Card title="Tools & Functions" icon="wrench" href="/docs/create/tools-and-functions">
    Define tools and their webhooks
  </Card>

  <Card title="HTTP Transfer" icon="webhook" href="/docs/advanced-features/call-transfers/http-transfer">
    Route transfers with your own API
  </Card>

  <Card title="Testing Webhooks" icon="flask-vial" href="/docs/webhooks-and-events/testing-webhooks">
    Testing and debugging
  </Card>
</CardGroup>
