Skip to main content
Go from an API key to a real phone call (with a transcript and recording) in four steps. Every request below uses the production base URL https://api.bolna.ai and Bearer authentication.
Don’t have a key yet? Follow Generate an API key first, then come back here. Telephone calls consume wallet credits, so keep a test number handy.

Prerequisites

  • A Bolna API key (Authorization: Bearer <key>)
  • A recipient phone number in E.164 format, e.g. +919876543210
  • curl, or Python 3, or Node 18+
Set your key as an environment variable so it’s not pasted into every command:
export BOLNA_API_KEY="bn-xxxxxxxxxxxxxxxx"
1

Verify your API key

A quick read-only call confirms the key works and shows your wallet balance and concurrency limit before you spend any credits.
curl https://api.bolna.ai/user/me \
  -H "Authorization: Bearer $BOLNA_API_KEY"
A successful response returns your account details:
{
  "id": "…",
  "name": "Bruce Wayne",
  "email": "bruce@example.com",
  "wallet": 42.42,
  "concurrency": { "max": 10, "current": 0 }
}
A 401 Access denied means the key is wrong or missing the Bearer prefix.
2

Get an agent ID

You need an agent_id to make a call. Pick one path:
Create an agent once in the dashboard (Auto Build is quickest), open it, and copy the agent ID from the URL or the agent settings. Then:
export BOLNA_AGENT_ID="your-agent-id"
This is the most reliable way to finish the quickstart, because the full agent configuration is large.
3

Place the call

Pass your agent_id and the recipient’s number. Omit from_phone_number to use Bolna’s default number, or set it to one of your purchased numbers.
curl https://api.bolna.ai/call \
  -H "Authorization: Bearer $BOLNA_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "agent_id": "'"$BOLNA_AGENT_ID"'",
    "recipient_phone_number": "+919876543210"
  }'
The response returns an execution_id you’ll use to track the call:
{ "message": "done", "status": "queued", "execution_id": "123e4567-e89b-12d3-a456-426614174000" }
Your phone should ring within a few seconds.
4

Fetch the result

Poll the execution until it finishes. Bolna fires a call-disconnected event the instant the line drops, then a final completed event a few seconds later once duration, cost, recording, and the AI call summary are finalized — so wait for completed (or a hard-failure status like no-answer, busy, failed) rather than stopping at call-disconnected, or you’ll read a half-populated payload with conversation_duration: 0. The completed execution includes the full transcript, recording URL, duration, cost breakdown, and extracted_data.
curl https://api.bolna.ai/executions/EXECUTION_ID \
  -H "Authorization: Bearer $BOLNA_API_KEY"
Completed execution (truncated)
{
  "id": "b7140255-af33-4608-8e97-04dd944b8e48",
  "agent_id": "5bc97541-e320-4d95-a3a5-242cfe45621d",
  "status": "completed",
  "conversation_duration": 16,
  "total_cost": 3.23,
  "transcript": "assistant: Hi! How is your day going?\nuser: …",
  "user_number": "+919876543210",
  "agent_number": "+918035739222",
  "extracted_data": { "General": { "Call Summary": { "subjective": "…", "confidence_label": "High" } } },
  "telephony_data": {
    "duration": 16,
    "recording_url": "https://api.bolna.ai/recordings/call/b7140255-af33-4608-8e97-04dd944b8e48",
    "call_type": "outbound",
    "provider": "plivo",
    "hangup_by": "Plivo",
    "hangup_reason": "inactivity_timeout",
    "to_number_carrier": "Bharat Sanchar Nigam Ltd (BSNL)"
  },
  "cost_breakdown": { "platform": 2, "network": 1, "transcriber": 0.23, "llm": 0, "synthesizer": 0 },
  "latency_data": { "time_to_first_audio": 189.69 }
}
For production, don’t poll — register a webhook to receive the execution payload automatically when the call ends.

Alternative: receive results via webhook

Polling is fine for a quickstart, but in production you don’t want to hammer the API. Instead, give your agent a webhook_url and Bolna will POST the execution payload to your server as the call progresses — same JSON shape as Step 4.
1

Stand up a public endpoint

Your endpoint must be publicly reachable over HTTPS and return 200 quickly. For local testing, run a small receiver and expose it with a tunnel:
python3 bolna_webhook_server.py          # listens on :8080, prints every payload
ngrok http 8080                          # gives you https://<id>.ngrok.app
Bolna sends webhooks from a fixed IP — whitelist 13.203.39.153 on your server or firewall so events aren’t dropped.
2

Attach the webhook to your agent

Set webhook_url inside agent_config when creating (or updating) the agent. With the test harness:
python3 bolna_quickstart_test.py --to "+919876543210" \
  --webhook-url "https://<id>.ngrok.app/webhook"
Or set it in the dashboard under the Analytics Tab — “Push all execution data to webhook”.
3

Place the call and watch the events arrive

Make the call as in Step 3. Your endpoint receives a POST each time the status changes (queued → in-progress → completed/call-disconnected), with the full transcript on the final event.
Bolna sends several POSTs per call as the status changes. Two land near the end: call-disconnected fires the instant the line drops (with conversation_duration: 0, no recording, no summary), then completed arrives a few seconds later with the finalized duration, cost, recording_url, and extracted_data. Treat completed as “call is done” — along with hard-failure statuses (no-answer, busy, failed). The same URL may also receive in-progress / pre-call webhooks; tell them apart by status. See Webhooks.

Run the whole flow as one script

The complete, dependency-free Python script runs all four steps end to end:
export BOLNA_API_KEY="bn-xxxx"
# optional: export BOLNA_AGENT_ID="..."  to reuse a dashboard agent
python3 bolna_quickstart_test.py --to "+919876543210"
Add --dry-run to print the exact request bodies without making any network calls.

Next steps

Personalize calls

Pass user_data variables like {customer_name} into the call body.

Call many people

Upload a CSV and run a batch campaign instead of single calls.

Receive results via webhook

Get the execution payload pushed to your server when a call ends.

Full agent schema

Every field you can set when creating an agent.