A small Flask webhook service that posts a Slack alert every time a Bolna voice-AI call ends. Pure-Python deps only — runs on Python 3.10+ including 3.14. The alert includes the four fields requested:
id— the execution / call IDagent_id— the Bolna agent that handled the callduration—conversation_durationfrom the Bolna payload, formatted asXm Ystranscript— the full transcript (truncated in Slack to keep messages readable)
Bolna agent finishes a call
│
▼
Bolna POSTs the execution payload to /bolna/webhook
│
▼
This service extracts id / agent_id / conversation_duration / transcript
│
▼
POSTs a formatted message to the Slack Incoming Webhook
Bolna's Analytics tab webhook
delivers the same payload as the Get Execution API.
Only calls whose status is in NOTIFY_STATUSES trigger an alert — by default
the terminal statuses (completed, call-disconnected, failed, no-answer,
busy, canceled, stopped, error).
Follow the Slack docs to create a
Slack app, enable Incoming Webhooks, and add one to the channel you want
alerts in. Copy the generated https://hooks.slack.com/services/... URL.
git clone <this-repo>
cd bolna
python -m venv .venv && source .venv/bin/activate
pip install -r requirements.txt
cp .env.example .env
# edit .env and paste your SLACK_WEBHOOK_URL
python app.pyThe service listens on http://0.0.0.0:8000 by default and exposes:
| Method | Path | Purpose |
|---|---|---|
| GET | /healthz |
Liveness check |
| POST | /bolna/webhook |
Receives Bolna execution payloads |
Bolna needs a publicly reachable HTTPS URL. For local testing use ngrok:
ngrok http 8000
# -> https://<id>.ngrok-free.app- Open your Bolna agent (you can clone the template agent
d311e737-70e6-4075-bef6-c0ef3a7026b4). - Go to the Analytics tab.
- Paste
https://<your-public-host>/bolna/webhookinto "Push all execution data to webhook". - Save the agent.
If you set WEBHOOK_SECRET in .env, also append ?secret=<value> to the URL
(or have Bolna send an X-Webhook-Secret header if your plan supports custom
headers). Bolna's docs
note that requests originate from 13.203.39.153, which you can additionally
allowlist at your network layer.
Trigger any call on that agent. When it ends you should see the message land in Slack within a couple of seconds.
All config lives in .env (see .env.example):
| Variable | Default | Description |
|---|---|---|
SLACK_WEBHOOK_URL |
required | Slack Incoming Webhook URL |
WEBHOOK_SECRET |
empty | If set, required as X-Webhook-Secret or ?secret= |
NOTIFY_STATUSES |
completed,call-disconnected,failed,no-answer,busy,canceled,stopped,error |
Comma-separated statuses that trigger an alert |
HOST / PORT |
0.0.0.0 / 8000 |
Bind address |
You can simulate a Bolna webhook with curl:
curl -X POST http://localhost:8000/bolna/webhook \
-H 'Content-Type: application/json' \
-d '{
"id": "5f7a3e0c-1c4e-4f30-9c52-7b8a1f2d4e10",
"agent_id": "d311e737-70e6-4075-bef6-c0ef3a7026b4",
"conversation_duration": 73.4,
"status": "completed",
"transcript": "agent: Hello, this is Bolna.\nuser: Hi, Id like to book a table."
}'pip install pytest
pytest -q