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

# Webhooks API

> Register webhook endpoints to receive real-time event notifications from Boltcall.

Webhooks let your application react to Boltcall events in real time — new leads, completed calls, booked appointments, and more — without polling the API. Boltcall sends an HTTP `POST` request to your endpoint each time a subscribed event occurs.

For a UI-based setup guide, see [Integrations → Webhooks](/integrations/webhooks).

## Events

Each webhook subscription listens to a single trigger event:

| Event                | Description                                                   |
| -------------------- | ------------------------------------------------------------- |
| `new_lead`           | A new lead was captured from a call, SMS, or form             |
| `missed_call`        | An inbound call was not answered by the agent                 |
| `appointment_booked` | An appointment was scheduled by the agent                     |
| `call_completed`     | A call ended — payload includes transcript and recording URLs |
| `review_received`    | A new review was received                                     |

## Payload structure

Every webhook payload follows the same structure:

```json Example payload theme={null}
{
  "event": "call_completed",
  "timestamp": "2025-03-20T09:17:22Z",
  "data": {
    "id": "call_xyz789",
    "agent_id": "agent_abc123",
    "direction": "inbound",
    "caller": "+19876543210",
    "duration_seconds": 142,
    "status": "completed",
    "sentiment": "positive",
    "summary": "Caller requested appointment for Friday.",
    "recording_url": "https://api.boltcall.org/v1/calls/call_xyz789/recording"
  }
}
```

The `data` object contains the full resource that triggered the event (lead, call, appointment, etc.).

## Signature verification

Boltcall signs every webhook request with an `X-Boltcall-Signature` header so you can verify the payload came from Boltcall and was not tampered with.

The signature is an HMAC-SHA256 hex digest computed from the raw request body using the webhook's `secret` as the key.

<Warning>
  Always verify the signature before processing a webhook payload. Skipping verification exposes your endpoint to forged requests.
</Warning>

```javascript Node.js theme={null}
import crypto from 'crypto';

function verifyBoltcallSignature(rawBody, secret, signature) {
  const expected = crypto
    .createHmac('sha256', secret)
    .update(rawBody, 'utf8')
    .digest('hex');

  return crypto.timingSafeEqual(
    Buffer.from(expected, 'hex'),
    Buffer.from(signature, 'hex'),
  );
}

// Express.js example
app.post('/hooks/boltcall', express.raw({ type: 'application/json' }), (req, res) => {
  const signature = req.headers['x-boltcall-signature'];
  const secret = process.env.BOLTCALL_WEBHOOK_SECRET;

  if (!verifyBoltcallSignature(req.body, secret, signature)) {
    return res.status(401).json({ error: 'Invalid signature' });
  }

  const payload = JSON.parse(req.body);
  console.log('Verified event:', payload.event);

  res.sendStatus(200);
});
```

<Note>
  Use `express.raw()` (not `express.json()`) to preserve the raw request body for signature verification. Parsing the body first changes the byte sequence and causes verification to fail.
</Note>

***

## List webhooks

Returns all webhook endpoints registered in your workspace.

<CodeGroup>
  ```bash cURL theme={null}
  curl https://api.boltcall.org/v1/webhooks \
    -H "Authorization: Bearer YOUR_API_KEY"
  ```

  ```javascript Node.js theme={null}
  const response = await fetch('https://api.boltcall.org/v1/webhooks', {
    headers: { 'Authorization': 'Bearer YOUR_API_KEY' },
  });
  const { data } = await response.json();
  ```

  ```python Python theme={null}
  import requests

  response = requests.get(
      'https://api.boltcall.org/v1/webhooks',
      headers={'Authorization': 'Bearer YOUR_API_KEY'},
  )
  result = response.json()
  ```
</CodeGroup>

```json Response theme={null}
{
  "data": [
    {
      "id": "wh_001",
      "name": "Lead notification",
      "url": "https://yourapp.com/hooks/boltcall",
      "trigger_event": "new_lead",
      "is_active": true,
      "created_at": "2025-02-10T12:00:00Z"
    }
  ]
}
```

***

## Register a webhook

Creates a new webhook subscription.

<ParamField body="name" type="string">
  Optional display name for the webhook (e.g. `"Zapier Lead Notification"`). For your reference only.
</ParamField>

<ParamField body="url" type="string" required>
  The HTTPS endpoint URL that Boltcall will POST events to. Must use HTTPS.
</ParamField>

<ParamField body="trigger_event" type="string" required>
  The event type to subscribe to. See the [events table](#events) for accepted values.
</ParamField>

<Warning>
  The `secret` is returned in full only at creation time. Copy and store it immediately in a secure location (e.g. your environment variables). You cannot retrieve it again from the API.
</Warning>

<CodeGroup>
  ```bash cURL theme={null}
  curl -X POST https://api.boltcall.org/v1/webhooks \
    -H "Authorization: Bearer YOUR_API_KEY" \
    -H "Content-Type: application/json" \
    -d '{
      "name": "New lead alert",
      "url": "https://yourapp.com/hooks/boltcall",
      "trigger_event": "new_lead"
    }'
  ```

  ```javascript Node.js theme={null}
  const response = await fetch('https://api.boltcall.org/v1/webhooks', {
    method: 'POST',
    headers: {
      'Authorization': 'Bearer YOUR_API_KEY',
      'Content-Type': 'application/json',
    },
    body: JSON.stringify({
      name: 'New lead alert',
      url: 'https://yourapp.com/hooks/boltcall',
      trigger_event: 'new_lead',
    }),
  });
  const webhook = await response.json();
  // Save webhook.secret to your environment variables immediately
  ```

  ```python Python theme={null}
  import requests

  webhook = requests.post(
      'https://api.boltcall.org/v1/webhooks',
      headers={'Authorization': 'Bearer YOUR_API_KEY'},
      json={
          'name': 'New lead alert',
          'url': 'https://yourapp.com/hooks/boltcall',
          'trigger_event': 'new_lead',
      },
  ).json()
  # Save webhook['secret'] to your environment variables immediately
  ```
</CodeGroup>

```json Response theme={null}
{
  "id": "wh_002",
  "name": "New lead alert",
  "url": "https://yourapp.com/hooks/boltcall",
  "trigger_event": "new_lead",
  "is_active": true,
  "secret": "whsec_abc123...",
  "created_at": "2025-03-20T16:00:00Z"
}
```

***

## Delete a webhook

Removes a webhook subscription. Boltcall will stop sending events to the registered URL immediately.

**Path parameter**

<ParamField path="webhook_id" type="string" required>
  The ID of the webhook to delete.
</ParamField>

<CodeGroup>
  ```bash cURL theme={null}
  curl -X DELETE https://api.boltcall.org/v1/webhooks/wh_002 \
    -H "Authorization: Bearer YOUR_API_KEY"
  ```

  ```javascript Node.js theme={null}
  await fetch('https://api.boltcall.org/v1/webhooks/wh_002', {
    method: 'DELETE',
    headers: { 'Authorization': 'Bearer YOUR_API_KEY' },
  });
  ```

  ```python Python theme={null}
  import requests

  requests.delete(
      'https://api.boltcall.org/v1/webhooks/wh_002',
      headers={'Authorization': 'Bearer YOUR_API_KEY'},
  )
  ```
</CodeGroup>

```json Response theme={null}
{ "deleted": true }
```

## Retry behavior

Boltcall does not automatically retry failed webhook deliveries. If your endpoint returns a non-2xx status code or times out, the delivery is logged as failed. You can view delivery history in **Dashboard → Integrations → Webhooks** and use the test/replay feature to manually re-send a payload after resolving the issue.

<Tip>
  Your endpoint should respond with `200 OK` as quickly as possible. Process the payload asynchronously (e.g. push to a queue) rather than doing heavy work synchronously during the HTTP request.
</Tip>
