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

# Pre-Call Webhooks

> Dynamically configure call behavior and inject real-time data before calls begin.

<Info>
  **Dynamic Call Configuration**: Pre-call webhooks allow you to fetch
  customer data, account information, and contextual details in real-time
  before each call starts.
</Info>

## Overview

<img src="https://mintcdn.com/openmic-ea75a20d/n3f_akOE86bDxuYq/images/pre-call-webhook.png?fit=max&auto=format&n=n3f_akOE86bDxuYq&q=85&s=b24565da57c70e6eb074111250e65706" alt="Showing the configuration for pre-call webhook" height="300" className="rounded-lg" data-path="images/pre-call-webhook.png" />

Pre-call webhooks enable bidirectional communication between Openmic and your systems. When a call is about to begin, Openmic sends call details to your webhook endpoint, and your system responds with dynamic variables that customize the call experience.

<CardGroup cols={2}>
  <Card title="Real-time Data Injection" icon="database" iconType="solid">
    Fetch customer details, account status, and contextual information from
    your systems before the call starts
  </Card>

  <Card title="Personalized Conversations" icon="user-check" iconType="solid">
    Use dynamic variables to personalize agent responses and call flows
    based on caller information
  </Card>
</CardGroup>

***

## When Pre-call Webhooks Trigger

Pre-call webhooks respect the `webhook_direction` configuration setting:

<CardGroup cols={3}>
  <Card title="Both" icon="arrows-up-down" iconType="solid">
    Triggered for all inbound and outbound calls
  </Card>

  <Card title="Inbound" icon="phone" iconType="solid">
    Only triggered for incoming calls to your agents
  </Card>

  <Card title="Outbound" icon="phone" iconType="solid">
    Only triggered for calls initiated by your agents
  </Card>
</CardGroup>

<Note>
  If no webhook URL is configured or the webhook direction doesn't match the
  call direction, the call proceeds without dynamic variables.
</Note>

***

## Request Specification

### HTTP Method and Timeout

Openmic sends a `POST` request to your configured webhook URL with:

* **Content-Type**: `application/json`
* **Timeout**: 3 seconds per attempt
* **User-Agent**: `Openmic-Webhook/1.0`

<Danger>
  If all webhook attempts fail, the call will end. Please read [failure handling](#failure-handling) for more info.
</Danger>

### Request Payload

```json theme={null}
{
	"event": "call",
	"call": {
		"direction": "outbound",
		"bot_id": "cmdx5w8oc0005q671s3cbg063",
		"from_number": "+16167948654",
		"to_number": "+916297653534",
		"attempt": "2"
	}
}
```

### Payload Fields

| Field              | Type   | Required | Description                                 |
| ------------------ | ------ | -------- | ------------------------------------------- |
| `event`            | string | Yes      | Always `"call"` for pre-call webhooks       |
| `call.direction`   | string | Yes      | Call direction: `"inbound"` or `"outbound"` |
| `call.bot_id`      | string | Yes      | Unique identifier for the bot/session       |
| `call.from_number` | string | Yes      | Caller's phone number in E.164 format       |
| `call.to_number`   | string | Yes      | Callee's phone number in E.164 format       |
| `call.attempt`     | string | Yes      | Attempt number of the webhook               |

***

## Expected Response

### Success Response

Your webhook must return a `200` status code with a JSON response containing dynamic variables:

```json theme={null}
{
	"call": {
		"customer_id": "cus_001",
		"dynamic_variables": {
			"customer_name": "John Doe",
			"account_balance": "1,250.50",
			"subscription_status": "premium",
			"last_purchase_date": "2024-07-15",
			"support_tier": "gold",
			"preferred_language": "english"
		}
	}
}
```

### Response Structure

| Field                    | Type   | Required | Description                                                 |
| ------------------------ | ------ | -------- | ----------------------------------------------------------- |
| `call`                   | object | Yes      | Container for call-related data                             |
| `call.customer_id`       | string | No       | Unique identifier for the customer associated with the call |
| `call.dynamic_variables` | object | Yes      | Key-value pairs of variables to inject into the call        |

<Tip>
  **Variable Usage**: Dynamic variables can be referenced in your agent
  prompts using template syntax like `{{ customer_name }}`, `{{ email }}`, etc.
</Tip>

<Note>
  **Customer ID Tracking**: When you provide a `customer_id` in the webhook response, you can later use the [List Calls API](/api-reference/calls/list-calls#parameter-customer-id) to filter and retrieve all calls associated with that customer ID using the `customer_id` query parameter.
</Note>

***

## Retry Logic and Error Handling

### Retry Configuration

<CardGroup cols={3}>
  <Card title="Max Attempts" icon="rotate-right" iconType="solid">
    **3 total attempts** 1 initial request + 2 retries
  </Card>

  <Card title="Timeout" icon="clock" iconType="solid">
    **3 seconds** Per individual request attempt
  </Card>

  <Card title="Backoff Strategy" icon="arrow-trend-up" iconType="solid">
    **Exponential delays** 1s, 2s, 3s between retries
  </Card>
</CardGroup>

### Retry Triggers

Openmic retries your webhook in these scenarios:

* **Timeout**: No response within 3 seconds
* **HTTP Errors**: 4xx or 5xx status codes
* **Network Errors**: Connection failures or DNS resolution issues
* **Invalid JSON**: Malformed response body

### Failure Handling

<Danger>
  If all webhook attempts fail, the call will terminate.
</Danger>

To avoid an incomplete or awkward conversation caused by missing dynamic variables, the default behavior is to end the call after all retry attempts are exhausted.

If you want the call to proceed even after repeated webhook failures, implement the following safeguard:

* Track the `"attempt"` field included in each webhook request payload.
* On the **third attempt** (final retry), return an **empty JSON object** for the dynamic variables.

Example response to allow the call to continue without injected variables:

```json theme={null}
{
	"call": {
		"dynamic_variables": {}
	}
}
```

When using this approach, ensure your agent prompts handle missing variables gracefully.

***

## Examples

```js theme={null}
// Example CRM lookup function
async function getCustomerData(phoneNumber) {
  // Pretend we're calling an internal CRM API or DB
  return {
    customer_name: 'Alice Chen',
    account_balance: '3452.75',
  };
}

app.post('webhook/pre-call', async (req, res) => {
  const { call } = req.body;
  console.log('📞 Pre-call webhook received:', call);
  try {
    // Pull customer data based on from_number
    const customerData = await getCustomerData(call.from_number);
    // Return dynamic variables in correct format
    res.json({
      call: {
        customer_id: customerData.customer_id || "cus_001",
        dynamic_variables: customerData
      }
    });
  } catch (err) {
    console.error('❌ Failed to fetch customer data', err);
    // If this is the 3rd attempt, return empty variables to allow call
    if (parseInt(call.attempt, 10) === 3) {
      return res.json({
        call: {
          dynamic_variables: {}
        }
      });
    }
    // Any other attempt = fail (will trigger retry)
    res.status(500).json({ error: 'Failed to fetch call data' });
  }
});
```

***

## Testing and Debugging

<Accordion title="Webhook not being called">
  **Possible causes:**

  * Webhook URL not configured
  * `webhook_direction` doesn't match call direction
  * Invalid webhook URL format

  **Solutions:**

  * Verify webhook URL in dashboard
  * Check `webhook_direction` setting
  * Ensure URL uses HTTPS and is publicly accessible
</Accordion>

<Accordion title="Webhook timing out">
  **Possible causes:**

  * Slow database queries
  * External API dependencies
  * Heavy processing logic

  **Solutions:**

  * Optimize database queries with indexes
  * Cache frequently accessed data
  * Use asynchronous processing for heavy operations
  * Set shorter timeouts for external API calls
</Accordion>

<Accordion title="Variables not appearing in calls">
  **Possible causes:**

  * Incorrect response format
  * HTTP status code other than 200
  * Variables not referenced in agent prompts

  **Solutions:**

  * Validate JSON response structure
  * Ensure 200 status code response
  * Check agent prompt syntax for variable references
</Accordion>
