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

# My webhook never arrived

> Debug missing Bolna Voice AI webhooks: IP whitelisting, endpoint reachability, which statuses fire, and how to fall back to polling the executions API.

Work down this list in order. The first two causes account for most reports.

<Steps>
  <Step title="Whitelist all three source IPs">
    Bolna delivers webhooks from `13.203.39.153`, `13.126.9.249` and `13.202.133.53`. If your firewall allows only one or two of them, deliveries look intermittent rather than broken.

    ```
    13.203.39.153
    13.126.9.249
    13.202.133.53
    ```
  </Step>

  <Step title="Confirm the endpoint is publicly reachable">
    The URL must accept HTTP `POST` from the public internet. `localhost`, a VPN-only host, or an endpoint behind SSO will silently receive nothing. Test it from outside your network:

    ```bash theme={"system"}
    curl -X POST https://your-app.example.com/bolna-webhook \
      -H 'Content-Type: application/json' \
      -d '{"ping":true}'
    ```
  </Step>

  <Step title="Check the URL is saved on the right agent">
    The webhook URL lives in **Push all execution data to webhook** on the [Extractions tab](/docs/agent-setup/analytics-tab), and it is per agent. Setting it and not clicking **Save agent** is a common miss.
  </Step>

  <Step title="Check what you are waiting for">
    Bolna posts as the status changes. If your handler only acts on `completed`, you will see nothing while a call sits in `queued` or `in-progress`, and nothing at all for a call that ended `no-answer` or `busy`. See [Call statuses](/docs/post-call/list-phone-call-status).
  </Step>

  <Step title="Check your own response codes">
    A handler that returns a non-2xx status, redirects, or takes too long to respond looks like a failed delivery from Bolna's side. Log the raw request before doing any processing.
  </Step>
</Steps>

***

## "The webhook arrived but the fields were empty"

This is expected on the disconnect event. At `call-disconnected` the line has dropped but post-call processing has not finished, so `conversation_duration`, `total_cost`, `recording_url` and `extracted_data` are still empty. Act on **`completed`**, which arrives a few seconds later with those fields populated.

<Warning>
  Do not treat `call-disconnected` as the end of the call in your integration. It is the end of the *audio*, not the end of the *record*.
</Warning>

***

## Fall back to polling

If you cannot expose a public endpoint at all, poll instead — the payload is the same object the webhook delivers.

```python theme={"system"}
TERMINAL = {"completed","no-answer","busy","failed","canceled","stopped","error","balance-low"}

while True:
    data = get_execution(execution_id)   # GET /executions/{execution_id}
    if data["status"] in TERMINAL:
        break
    time.sleep(5)
```

See [Pull executions with the API](/docs/fetch-agent-executions) and [Get results with webhooks](/docs/post-call/polling-call-status-webhooks).

***

## Still nothing

Collect the `execution_id`, the exact webhook URL configured on the agent, and your server's access log for that timestamp, then reach out through [Get help](/docs/getting-help).


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.