> ## 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.

# Webhook Payload Types and Schemas

> Complete reference for webhook payload types, structures, and response formats based on the actual API schema.

Use the `type` field to route incoming webhooks, then reference the tables below for field-by-field details on each payload.

**What you'll learn:** Payload type enum, common fields, event-specific schemas, and response format requirements.

***

## WebHookPayloadType Enum

All webhook payloads include a `type` field that serves as the discriminator. The possible values are:

| Type Value                   | Description                                 | Status    |
| ---------------------------- | ------------------------------------------- | --------- |
| `StartWebHookPayload`        | Call is starting (pre-call webhook)         | Queued    |
| `CompletedWebHookPayload`    | Call completed successfully                 | Completed |
| `FailedWebHookPayload`       | Call failed with an error                   | Failed    |
| `CallDeadLineWebHookPayload` | Call canceled due to deadline expiration    | Canceled  |
| `TransferWebHookPayload`     | Transfer decision requested (HTTP transfer) | Running   |
| `ToolWebHookPayload`         | Tool/function execution requested           | Running   |
| `UnknownWebHookPayload`      | Unknown or unhandled payload type           | -         |

***

## Common Payload Fields

All webhook payloads inherit from `BaseWebHookPayload` and include these common fields:

| Field                 | Type                 | Required | Description                                                                  |
| --------------------- | -------------------- | -------- | ---------------------------------------------------------------------------- |
| `type`                | `WebHookPayloadType` | Yes      | Discriminator field identifying the payload type                             |
| `status`              | `CallStatus`         | Yes      | Current call status (`Queued`, `Running`, `Completed`, `Failed`, `Canceled`) |
| `callId`              | `string`             | Yes      | Unique identifier for the call                                               |
| `agentId`             | `string`             | Yes      | ID of the agent handling the call                                            |
| `orgId`               | `string`             | Yes      | Organization identifier                                                      |
| `callAdditionalData`  | `object`             | Yes      | Custom metadata passed when creating the call                                |
| `agentAdditionalData` | `object`             | Yes      | Custom metadata from agent configuration                                     |
| `serverJobId`         | `string`             | No       | Internal server job identifier                                               |
| `sip`                 | `IncomingSipInfo`    | No       | SIP protocol information (if available)                                      |
| `endpoint`            | `string`             | No       | Call endpoint (phone number, SIP URI, etc.)                                  |

### IncomingSipInfo Structure

When `sip` is present:

| Field        | Type       | Description                    |
| ------------ | ---------- | ------------------------------ |
| `fromUser`   | `string`   | User part of SIP From header   |
| `fromDomain` | `string`   | Domain part of SIP From header |
| `toUser`     | `string`   | User part of SIP To header     |
| `toDomain`   | `string`   | Domain part of SIP To header   |
| `diversion`  | `string[]` | Array of diversion headers     |

### CallStatus Values

| Value       | Description                     |
| ----------- | ------------------------------- |
| `Unknown`   | Unknown status                  |
| `Created`   | Call created but not yet queued |
| `Pending`   | Call pending execution          |
| `Queued`    | Call queued and ready to start  |
| `Running`   | Call in progress                |
| `Completed` | Call completed successfully     |
| `Failed`    | Call failed with error          |
| `Canceled`  | Call was canceled               |

### CallConnectionType Values

| Value           | Description             |
| --------------- | ----------------------- |
| `Unknown`       | Unknown connection type |
| `InboundAudio`  | Inbound phone call      |
| `OutboundAudio` | Outbound phone call     |
| `WebChat`       | Web-based chat session  |
| `WebCall`       | Web-based voice call    |
| `WebPhone`      | Web phone connection    |

***

## StartWebHookPayload

Sent when a call is about to start. This is a **pre-call webhook** that allows you to accept or reject the call, and optionally override the agent configuration.

**Status:** `Queued`

### Fields

| Field                 | Type                    | Required | Description                                   |
| --------------------- | ----------------------- | -------- | --------------------------------------------- |
| `type`                | `"StartWebHookPayload"` | Yes      | Discriminator                                 |
| `status`              | `"Queued"`              | Yes      | Always `Queued` for start payloads            |
| `originalAgentConfig` | `AgentConfigDto`        | Yes      | The current agent configuration at call start |
| *(common fields)*     | -                       | Yes      | All fields from `BaseWebHookPayload`          |

<Accordion title="Example Payload">
  ```json theme={"theme":{"light":"github-light","dark":"github-dark"}}
  {
    "type": "StartWebHookPayload",
    "status": "Queued",
    "callId": "660e8400-e29b-41d4-a716-446655440001",
    "agentId": "550e8400-e29b-41d4-a716-446655440000",
    "orgId": "org_123abc",
    "callAdditionalData": {
      "customerId": "cust_789",
      "campaignId": "fall-promo-2024"
    },
    "agentAdditionalData": {
      "department": "sales"
    },
    "endpoint": "+15551234567",
    "sip": {
      "fromUser": "+15551234567",
      "fromDomain": "sip.provider.com",
      "toUser": "agent-line",
      "toDomain": "blackbox.dasha.ai",
      "diversion": []
    },
    "originalAgentConfig": {
      "primaryLanguage": "en-US",
      "llmConfig": {
        "vendor": "openai",
        "model": "gpt-4.1-mini",
        "prompt": "You are a helpful customer support agent..."
      },
      "ttsConfig": {
        "vendor": "Dasha",
        "voiceId": "default-voice"
      },
      "sttConfig": {
        "vendor": "Auto"
      }
    }
  }
  ```
</Accordion>

### Start Webhook Response

Your webhook must return one of two response types:

#### StartWebHookResponseAccept

Return this to accept the call and optionally override the agent configuration.

| Field                 | Type             | Required | Description                                                                                                                         |
| --------------------- | ---------------- | -------- | ----------------------------------------------------------------------------------------------------------------------------------- |
| `accept`              | `true`           | Yes      | Must be `true` to accept                                                                                                            |
| `overrideAgentConfig` | `AgentConfigDto` | No       | Complete agent configuration to use instead of the original. **Note:** This replaces the entire configuration, not a partial merge. |
| `additionalData`      | `object`         | No       | Additional data to inject into the call context                                                                                     |

<Accordion title="Example: Accept Response">
  ```json theme={"theme":{"light":"github-light","dark":"github-dark"}}
  {
    "accept": true,
    "overrideAgentConfig": {
      "primaryLanguage": "es-ES",
      "llmConfig": {
        "vendor": "openai",
        "model": "gpt-4.1",
        "prompt": "Eres un agente de soporte al cliente...",
        "options": { "temperature": 0.7 }
      },
      "ttsConfig": {
        "vendor": "ElevenLabs",
        "voiceId": "spanish-voice-id"
      },
      "sttConfig": {
        "vendor": "Auto"
      }
    },
    "additionalData": {
      "customerTier": "premium",
      "preferredLanguage": "es"
    }
  }
  ```
</Accordion>

#### StartWebHookResponseReject

Return this to reject the call.

| Field           | Type     | Required | Description                                |
| --------------- | -------- | -------- | ------------------------------------------ |
| `accept`        | `false`  | Yes      | Must be `false` to reject                  |
| `reasonMessage` | `string` | Yes      | Reason for rejection (minimum 1 character) |

<Accordion title="Example: Reject Response">
  ```json theme={"theme":{"light":"github-light","dark":"github-dark"}}
  {
    "accept": false,
    "reasonMessage": "Customer account is suspended"
  }
  ```
</Accordion>

***

## CompletedWebHookPayload

Sent when a call completes successfully. Contains the full transcription and call results.

**Status:** `Completed`

### Fields

| Field             | Type                        | Required | Description                                   |
| ----------------- | --------------------------- | -------- | --------------------------------------------- |
| `type`            | `"CompletedWebHookPayload"` | Yes      | Discriminator                                 |
| `status`          | `"Completed"`               | Yes      | Always `Completed`                            |
| `callType`        | `CallConnectionType`        | Yes      | Type of call connection                       |
| `result`          | `CompletedOutput`           | Yes      | Call result data including post-call analysis |
| `transcription`   | `Transcription[]`           | Yes      | Complete conversation transcript              |
| `inspectorUrl`    | `string`                    | Yes      | URL to view call in Call Inspector            |
| `recordingUrl`    | `string`                    | No       | URL to call recording (if enabled)            |
| `createdTime`     | `string` (ISO 8601)         | Yes      | When the call was created                     |
| `completedTime`   | `string` (ISO 8601)         | Yes      | When the call completed                       |
| `durationSeconds` | `number`                    | Yes      | Total call duration in seconds                |
| *(common fields)* | -                           | Yes      | All fields from `BaseWebHookPayload`          |

### CompletedOutput Structure

| Field                 | Type             | Description                                       |
| --------------------- | ---------------- | ------------------------------------------------- |
| `failDetails`         | `string`         | Failure details (if any)                          |
| `finishReason`        | `string`         | Reason for call completion                        |
| `serviceStatus`       | `string`         | Service status code                               |
| `status`              | `string`         | Final status                                      |
| `postCallAnalysis`    | `object`         | Results from configured post-call analysis labels |
| `transferInformation` | `TransferInfo[]` | Array of transfer information (duration, etc.)    |

### Transcription Structure

| Field       | Type                | Description                                    |
| ----------- | ------------------- | ---------------------------------------------- |
| `speaker`   | `string`            | Speaker identifier (`"user"` or `"assistant"`) |
| `name`      | `string`            | Speaker name (optional)                        |
| `text`      | `string`            | Transcribed text                               |
| `startTime` | `string` (ISO 8601) | When this segment started                      |
| `endTime`   | `string` (ISO 8601) | When this segment ended                        |

<Accordion title="Example Payload">
  ```json theme={"theme":{"light":"github-light","dark":"github-dark"}}
  {
    "type": "CompletedWebHookPayload",
    "status": "Completed",
    "callId": "660e8400-e29b-41d4-a716-446655440001",
    "agentId": "550e8400-e29b-41d4-a716-446655440000",
    "orgId": "org_123abc",
    "callAdditionalData": {
      "customerId": "cust_789"
    },
    "agentAdditionalData": {},
    "endpoint": "+15551234567",
    "callType": "OutboundAudio",
    "createdTime": "2024-10-20T14:32:00.000Z",
    "completedTime": "2024-10-20T14:37:45.789Z",
    "durationSeconds": 345.789,
    "inspectorUrl": "https://blackbox.dasha.ai/calls/660e8400-e29b-41d4-a716-446655440001",
    "recordingUrl": "https://storage.blackbox.dasha.ai/recordings/660e8400-e29b-41d4-a716-446655440001.mp3",
    "result": {
      "finishReason": "user_hangup",
      "status": "success",
      "postCallAnalysis": {
        "sentiment": "positive",
        "issueResolved": true,
        "callCategory": "billing_inquiry"
      },
      "transferInformation": []
    },
    "transcription": [
      {
        "speaker": "assistant",
        "name": "Agent",
        "text": "Hello! Thank you for calling. How can I help you today?",
        "startTime": "2024-10-20T14:32:15.000Z",
        "endTime": "2024-10-20T14:32:19.500Z"
      },
      {
        "speaker": "user",
        "name": "Customer",
        "text": "Hi, I have a question about my recent bill.",
        "startTime": "2024-10-20T14:32:20.000Z",
        "endTime": "2024-10-20T14:32:24.000Z"
      },
      {
        "speaker": "assistant",
        "name": "Agent",
        "text": "Of course! I'd be happy to help with your billing question. Could you tell me more about what you're seeing?",
        "startTime": "2024-10-20T14:32:24.500Z",
        "endTime": "2024-10-20T14:32:30.000Z"
      }
    ]
  }
  ```
</Accordion>

***

## FailedWebHookPayload

Sent when a call fails due to an error.

**Status:** `Failed`

### Fields

| Field             | Type                     | Required | Description                             |
| ----------------- | ------------------------ | -------- | --------------------------------------- |
| `type`            | `"FailedWebHookPayload"` | Yes      | Discriminator                           |
| `status`          | `"Failed"`               | Yes      | Always `Failed`                         |
| `callType`        | `CallConnectionType`     | Yes      | Type of call connection                 |
| `errorMessage`    | `string`                 | Yes      | Description of the error                |
| `inspectorUrl`    | `string`                 | No       | URL to view call in Call Inspector      |
| `recordingUrl`    | `string`                 | No       | URL to partial recording (if available) |
| `createdTime`     | `string` (ISO 8601)      | Yes      | When the call was created               |
| `completedTime`   | `string` (ISO 8601)      | Yes      | When the call failed                    |
| *(common fields)* | -                        | Yes      | All fields from `BaseWebHookPayload`    |

<Accordion title="Example Payload">
  ```json theme={"theme":{"light":"github-light","dark":"github-dark"}}
  {
    "type": "FailedWebHookPayload",
    "status": "Failed",
    "callId": "660e8400-e29b-41d4-a716-446655440002",
    "agentId": "550e8400-e29b-41d4-a716-446655440000",
    "orgId": "org_123abc",
    "callAdditionalData": {
      "customerId": "cust_790"
    },
    "agentAdditionalData": {},
    "endpoint": "+15551234568",
    "callType": "OutboundAudio",
    "createdTime": "2024-10-20T14:40:00.000Z",
    "completedTime": "2024-10-20T14:40:30.456Z",
    "errorMessage": "Call was not answered within timeout period",
    "inspectorUrl": "https://blackbox.dasha.ai/calls/660e8400-e29b-41d4-a716-446655440002"
  }
  ```
</Accordion>

***

## CallDeadLineWebHookPayload

Sent when a call is canceled because its scheduled deadline expired before the call could be executed.

**Status:** `Canceled`

### Fields

| Field             | Type                           | Required | Description                          |
| ----------------- | ------------------------------ | -------- | ------------------------------------ |
| `type`            | `"CallDeadLineWebHookPayload"` | Yes      | Discriminator                        |
| `status`          | `"Canceled"`                   | Yes      | Always `Canceled`                    |
| `callType`        | `CallConnectionType`           | Yes      | Type of call connection              |
| `reasonMessage`   | `string`                       | No       | Reason for cancellation              |
| `createdTime`     | `string` (ISO 8601)            | No       | When the call was created            |
| `completedTime`   | `string` (ISO 8601)            | No       | When the call was canceled           |
| *(common fields)* | -                              | Yes      | All fields from `BaseWebHookPayload` |

<Accordion title="Example Payload">
  ```json theme={"theme":{"light":"github-light","dark":"github-dark"}}
  {
    "type": "CallDeadLineWebHookPayload",
    "status": "Canceled",
    "callId": "660e8400-e29b-41d4-a716-446655440003",
    "agentId": "550e8400-e29b-41d4-a716-446655440000",
    "orgId": "org_123abc",
    "callAdditionalData": {
      "scheduledFor": "2024-10-20T14:00:00.000Z"
    },
    "agentAdditionalData": {},
    "endpoint": "+15551234569",
    "callType": "OutboundAudio",
    "createdTime": "2024-10-20T13:00:00.000Z",
    "completedTime": "2024-10-20T15:00:00.000Z",
    "reasonMessage": "Call deadline expired before execution"
  }
  ```
</Accordion>

***

## TransferWebHookPayload

Sent during HTTP transfers to request a transfer decision. Your webhook determines where to route the call.

**Status:** `Running`

### Fields

| Field             | Type                       | Required | Description                                     |
| ----------------- | -------------------------- | -------- | ----------------------------------------------- |
| `type`            | `"TransferWebHookPayload"` | Yes      | Discriminator                                   |
| `status`          | `"Running"`                | Yes      | Always `Running`                                |
| `transferReason`  | `string`                   | No       | Reason for transfer execution                   |
| `transcription`   | `Transcription[]`          | Yes      | Partial transcription up to the transfer moment |
| *(common fields)* | -                          | Yes      | All fields from `BaseWebHookPayload`            |

<Accordion title="Example Payload">
  ```json theme={"theme":{"light":"github-light","dark":"github-dark"}}
  {
    "type": "TransferWebHookPayload",
    "status": "Running",
    "callId": "660e8400-e29b-41d4-a716-446655440004",
    "agentId": "550e8400-e29b-41d4-a716-446655440000",
    "orgId": "org_123abc",
    "callAdditionalData": {
      "customerId": "cust_791",
      "accountTier": "premium"
    },
    "agentAdditionalData": {},
    "endpoint": "+15551234570",
    "transferReason": "Customer requested human agent for billing dispute",
    "transcription": [
      {
        "speaker": "assistant",
        "name": "Agent",
        "text": "I understand you'd like to speak with a billing specialist about your dispute.",
        "startTime": "2024-10-20T14:45:00.000Z",
        "endTime": "2024-10-20T14:45:05.000Z"
      },
      {
        "speaker": "user",
        "name": "Customer",
        "text": "Yes, I need to talk to someone who can actually help me with this refund.",
        "startTime": "2024-10-20T14:45:06.000Z",
        "endTime": "2024-10-20T14:45:10.000Z"
      }
    ]
  }
  ```
</Accordion>

### Transfer Webhook Response

Your webhook should return a transfer decision specifying where to route the call. The response format depends on your transfer configuration.

<Note>
  For complete details on transfer webhook responses and HTTP transfer configuration, see [Call Transfers](/docs/advanced-features/call-transfers). Transfer parameters documented there align with this TransferWebHookPayload.
</Note>

<Accordion title="Example: Cold Transfer Response">
  ```json theme={"theme":{"light":"github-light","dark":"github-dark"}}
  {
    "transferTo": "+15559876543",
    "transferType": "cold"
  }
  ```
</Accordion>

<Accordion title="Example: Warm Transfer Response">
  ```json theme={"theme":{"light":"github-light","dark":"github-dark"}}
  {
    "transferTo": "+15559876543",
    "transferType": "warm",
    "briefing": "Customer Jane Doe needs help with billing dispute. Account: premium tier."
  }
  ```
</Accordion>

***

## ToolWebHookPayload

Sent when the AI agent invokes a configured tool/function during a conversation.

**Status:** `Running`

### Fields

| Field             | Type                   | Required | Description                                              |
| ----------------- | ---------------------- | -------- | -------------------------------------------------------- |
| `type`            | `"ToolWebHookPayload"` | Yes      | Discriminator                                            |
| `status`          | `"Running"`            | Yes      | Always `Running`                                         |
| `toolName`        | `string`               | Yes      | Name of the tool being called                            |
| `arguments`       | `object`               | Yes      | Arguments passed to the tool (as defined in tool schema) |
| *(common fields)* | -                      | Yes      | All fields from `BaseWebHookPayload`                     |

<Accordion title="Example Payload">
  ```json theme={"theme":{"light":"github-light","dark":"github-dark"}}
  {
    "type": "ToolWebHookPayload",
    "status": "Running",
    "callId": "660e8400-e29b-41d4-a716-446655440005",
    "agentId": "550e8400-e29b-41d4-a716-446655440000",
    "orgId": "org_123abc",
    "callAdditionalData": {
      "customerId": "cust_792"
    },
    "agentAdditionalData": {},
    "endpoint": "+15551234571",
    "toolName": "check_account_balance",
    "arguments": {
      "customerId": "cust_792",
      "accountType": "checking"
    }
  }
  ```
</Accordion>

<Accordion title="Tool Webhook Response">
  Return the tool execution result as JSON. The structure depends on your tool definition.

  ```json theme={"theme":{"light":"github-light","dark":"github-dark"}}
  {
    "balance": 1234.56,
    "currency": "USD",
    "lastTransaction": "2024-10-19T10:15:00Z"
  }
  ```
</Accordion>

***

## Event Handling Best Practices

<Accordion title="Use the Type Discriminator">
  Always route based on the `type` field, not assumptions about payload structure:

  ```javascript theme={"theme":{"light":"github-light","dark":"github-dark"}}
  const handlers = {
    'StartWebHookPayload': handleStart,
    'CompletedWebHookPayload': handleCompleted,
    'FailedWebHookPayload': handleFailed,
    'CallDeadLineWebHookPayload': handleDeadline,
    'TransferWebHookPayload': handleTransfer,
    'ToolWebHookPayload': handleTool
  };

  app.post('/webhooks/blackbox', (req, res) => {
    const handler = handlers[req.body.type];
    if (handler) {
      return handler(req.body, res);
    }
    console.warn(`Unknown webhook type: ${req.body.type}`);
    res.status(200).send('OK');
  });
  ```
</Accordion>

### Respond Quickly

Dasha BlackBox expects webhook responses within the configured timeout (default: 10 seconds for start webhooks, 5 seconds for tools).

<Accordion title="Example: Async processing for long operations">
  ```javascript theme={"theme":{"light":"github-light","dark":"github-dark"}}
  // For long-running operations, acknowledge immediately and process asynchronously
  app.post('/webhooks/blackbox', async (req, res) => {
    if (req.body.type === 'CompletedWebHookPayload') {
      // Acknowledge immediately
      res.status(200).send('OK');
      // Process asynchronously
      processCompletedCall(req.body).catch(console.error);
      return;
    }
    // For start/transfer/tool webhooks, must respond with data
    // ...
  });
  ```
</Accordion>

<Accordion title="Handle All Payload Types">
  Ensure your webhook handles all possible payload types gracefully:

  ```javascript theme={"theme":{"light":"github-light","dark":"github-dark"}}
  app.post('/webhooks/blackbox', (req, res) => {
    const { type } = req.body;

    // Log all received webhooks for debugging
    console.log(`Received webhook: ${type}, callId: ${req.body.callId}`);

    switch (type) {
      case 'StartWebHookPayload':
        return handleStart(req, res);
      case 'CompletedWebHookPayload':
      case 'FailedWebHookPayload':
      case 'CallDeadLineWebHookPayload':
        // Status webhooks don't require response data
        processStatusWebhook(req.body);
        return res.status(200).send('OK');
      case 'TransferWebHookPayload':
        return handleTransfer(req, res);
      case 'ToolWebHookPayload':
        return handleTool(req, res);
      default:
        console.warn(`Unhandled webhook type: ${type}`);
        return res.status(200).send('OK');
    }
  });
  ```
</Accordion>

***

<Accordion title="Complete Webhook Handler Example">
  Here's a production-ready Express.js webhook handler implementing all payload types:

  ```javascript theme={"theme":{"light":"github-light","dark":"github-dark"}}
  const express = require('express');
  const app = express();
  app.use(express.json());

  // Start webhook handler - accept/reject calls
  async function handleStartWebhook(payload, res) {
    const { callId, callAdditionalData, originalAgentConfig } = payload;

    try {
      // Example: Check if customer is allowed to call
      const customerId = callAdditionalData?.customerId;
      const isAllowed = await checkCustomerStatus(customerId);

      if (!isAllowed) {
        return res.json({
          accept: false,
          reasonMessage: 'Customer account is not active'
        });
      }

      // Example: Override config based on customer tier
      const customerTier = await getCustomerTier(customerId);
      if (customerTier === 'premium') {
        return res.json({
          accept: true,
          overrideAgentConfig: {
            ...originalAgentConfig,
            llmConfig: {
              ...originalAgentConfig.llmConfig,
              model: 'gpt-4.1' // Upgrade to better model for premium
            }
          },
          additionalData: {
            customerTier: 'premium'
          }
        });
      }

      // Accept with default config
      return res.json({ accept: true });

    } catch (error) {
      console.error('Start webhook error:', error);
      // On error, accept with default config
      return res.json({ accept: true });
    }
  }

  // Completed webhook handler - process results
  async function handleCompletedWebhook(payload) {
    const {
      callId,
      transcription,
      result,
      durationSeconds,
      callAdditionalData
    } = payload;

    // Store call data
    await storeCallRecord({
      callId,
      customerId: callAdditionalData?.customerId,
      duration: durationSeconds,
      transcript: transcription,
      postCallAnalysis: result.postCallAnalysis,
      finishReason: result.finishReason
    });

    // Trigger follow-up actions based on analysis
    if (result.postCallAnalysis?.issueResolved === false) {
      await createFollowUpTask(callId, callAdditionalData?.customerId);
    }
  }

  // Failed webhook handler - handle errors
  async function handleFailedWebhook(payload) {
    const { callId, errorMessage, callAdditionalData } = payload;

    await logCallFailure({
      callId,
      customerId: callAdditionalData?.customerId,
      error: errorMessage
    });

    // Alert on repeated failures
    const recentFailures = await getRecentFailureCount(
      callAdditionalData?.customerId,
      '1h'
    );
    if (recentFailures > 3) {
      await alertOperations('High failure rate for customer');
    }
  }

  // Transfer webhook handler - route calls
  async function handleTransferWebhook(payload, res) {
    const { callAdditionalData, transferReason } = payload;

    try {
      // Route based on customer tier or transfer reason
      const customerId = callAdditionalData?.customerId;
      const accountTier = callAdditionalData?.accountTier;

      if (accountTier === 'premium') {
        // Premium customers get warm transfer to dedicated rep
        const assignedRep = await getAssignedRep(customerId);
        return res.json({
          transferTo: assignedRep.phone,
          transferType: 'warm',
          briefing: `Premium customer ${customerId}. Reason: ${transferReason}`
        });
      }

      // Standard customers get cold transfer to queue
      return res.json({
        transferTo: '+1-555-0100',
        transferType: 'cold'
      });

    } catch (error) {
      console.error('Transfer webhook error:', error);
      // Fallback to default support line
      return res.json({
        transferTo: '+1-555-0100',
        transferType: 'cold'
      });
    }
  }

  // Tool webhook handler - execute functions
  async function handleToolWebhook(payload, res) {
    const { toolName, arguments: args, callAdditionalData } = payload;

    try {
      switch (toolName) {
        case 'check_account_balance':
          const balance = await getAccountBalance(
            args.customerId,
            args.accountType
          );
          return res.json(balance);

        case 'schedule_callback':
          const scheduled = await scheduleCallback(
            callAdditionalData?.customerId,
            args.preferredTime
          );
          return res.json({ success: true, scheduledTime: scheduled });

        case 'process_refund':
          const refund = await processRefund(
            args.orderId,
            args.amount
          );
          return res.json(refund);

        default:
          return res.json({ error: `Unknown tool: ${toolName}` });
      }
    } catch (error) {
      console.error(`Tool ${toolName} error:`, error);
      return res.json({ error: error.message });
    }
  }

  // Main webhook endpoint
  app.post('/webhooks/blackbox', async (req, res) => {
    const payload = req.body;

    console.log(`Webhook received: ${payload.type}, callId: ${payload.callId}`);

    switch (payload.type) {
      case 'StartWebHookPayload':
        return handleStartWebhook(payload, res);

      case 'CompletedWebHookPayload':
        await handleCompletedWebhook(payload);
        return res.status(200).send('OK');

      case 'FailedWebHookPayload':
        await handleFailedWebhook(payload);
        return res.status(200).send('OK');

      case 'CallDeadLineWebHookPayload':
        console.log(`Call ${payload.callId} canceled: ${payload.reasonMessage}`);
        return res.status(200).send('OK');

      case 'TransferWebHookPayload':
        return handleTransferWebhook(payload, res);

      case 'ToolWebHookPayload':
        return handleToolWebhook(payload, res);

      default:
        console.warn(`Unknown webhook type: ${payload.type}`);
        return res.status(200).send('OK');
    }
  });

  // Health check
  app.get('/health', (req, res) => res.status(200).send('OK'));

  const PORT = process.env.PORT || 3000;
  app.listen(PORT, () => {
    console.log(`Webhook server running on port ${PORT}`);
  });
  ```
</Accordion>

***

## Next Steps

* [Configuring Webhooks](/docs/webhooks-and-events/configuring-webhooks) - Set up webhook endpoints
* [Testing Webhooks](/docs/webhooks-and-events/testing-webhooks) - Test your webhook integration
* [Call Transfers](/docs/advanced-features/call-transfers) - Transfer parameters align with TransferWebHookPayload
* [Tools and Functions](/docs/create/tools-and-functions) - Configure tools for ToolWebHookPayload
