Answers you can trust, from Codeables
Every page on Codeables is structured and verified — built so people and the AI agents they rely on can trust it. Explore more from the source behind this answer.
Explore CodeablesHow do I send outbound calls in Bland via API (cURL/Python/JS) and get call status via webhooks?
Building outbound AI phone workflows with Bland’s API is straightforward once you understand the basic pattern: send calls through the API (from cURL, Python, or JavaScript) and receive call status updates via webhooks. This guide walks through both pieces so you can trigger calls programmatically and reliably track what happens on each call.
Overview: Sending Calls and Receiving Status
At a high level, the outbound call flow with Bland works like this:
-
Trigger an outbound call
- Use Bland’s API to send a call directly from your own systems.
- You can call your customers individually or at scale (e.g., batch jobs or campaigns).
-
Let Bland handle the conversation
- Bland’s AI phone agent conducts the call in real time.
- You can configure voice, scripts, and integrations with your CRM, ticketing system, or telephony setup (SIP, Twilio, etc.).
-
Receive call status via webhooks
- Bland posts call lifecycle events (queued, ringing, in-progress, completed, failed, etc.) to your webhook URL.
- Use these events to update your database, trigger follow-ups, or run analytics.
The rest of this article explains how to:
- Set up your webhook endpoint
- Send outbound calls in cURL, Python, and JavaScript
- Handle webhook data to track call status and outcomes
- Scale up to batch/bulk calling
Prerequisites
Before you start sending outbound calls via the Bland API, make sure you have:
- A Bland account with API access
- An API key or OAuth mechanism provided by Bland
- At least one configured agent / call template (prompt, voice, routing)
- A public webhook URL (HTTPS) that Bland can POST to
- A telephony setup (e.g., SIP configuration or Twilio-based telephony) if you want to use your own numbers
Bland integrates with major telephony providers and supports:
- SIP with guided setup, auto-discovery, test calls, and number porting
- Twilio-based telephony to preserve your existing investment
- Batch call sending via file upload or API
Step 1: Design Your Outbound Call Payload
Outbound call APIs typically require a few core fields:
to: The destination phone number (E.164 format recommended, e.g.+15551234567)from: The caller ID / number (if managed via SIP or Twilio)agent_idorscenario_id: Which Bland AI agent / workflow to usemetadataorcontext: Any custom data you want the agent or your backend to usewebhook_url: Where Bland will send call status updates (optional if configured globally)
A generic outbound call JSON payload might look like:
{
"to": "+15551234567",
"from": "+15559876543",
"agent_id": "sales-outreach-agent-01",
"metadata": {
"customer_id": "cus_12345",
"campaign_id": "spring_promo_2026"
},
"webhook_url": "https://yourapp.com/webhooks/bland/call-status"
}
Your exact field names may differ depending on your Bland account configuration and the specific API version, but this structure is a good mental model.
Step 2: Set Up Your Webhook Endpoint
To get call status via webhooks, you need an HTTP endpoint that can accept POST requests from Bland.
Example webhook payload
A call status webhook from Bland might include:
{
"event": "call.completed",
"call_id": "call_abc123",
"status": "completed",
"to": "+15551234567",
"from": "+15559876543",
"duration_seconds": 182,
"started_at": "2026-04-12T14:30:21Z",
"ended_at": "2026-04-12T14:33:23Z",
"recording_url": "https://bland-calls.s3.amazonaws.com/recordings/call_abc123.mp3",
"transcript_url": "https://bland-calls.s3.amazonaws.com/transcripts/call_abc123.json",
"metadata": {
"customer_id": "cus_12345",
"campaign_id": "spring_promo_2026"
}
}
Bland’s monitoring features give you real-time visibility into agent behavior and record every call, so webhook payloads commonly reference:
- Call status and timestamps
- Recording and transcript locations
- Any custom metadata you passed in your initial request
Minimal webhook handler (Node.js / Express)
import express from "express";
const app = express();
app.use(express.json());
app.post("/webhooks/bland/call-status", async (req, res) => {
const event = req.body;
// 1. Verify webhook authenticity (e.g. signatures) as per Bland docs
// 2. Persist to your DB
console.log("Received Bland call event:", event);
// Example: switch on event type or status
if (event.event === "call.completed") {
// update your CRM, mark campaign attempt as done, etc.
}
res.status(200).send("ok");
});
app.listen(3000, () => {
console.log("Listening on port 3000 for Bland webhooks");
});
You can implement the same logic in Python, Ruby, Go, or any other language that can accept HTTP POST requests.
Step 3: Sending Outbound Calls via cURL
Once your webhook is in place, you can start making calls from the command line using cURL. This is useful for quick tests and debugging.
curl -X POST "https://api.bland.ai/v1/calls" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_API_KEY" \
-d '{
"to": "+15551234567",
"from": "+15559876543",
"agent_id": "sales-outreach-agent-01",
"metadata": {
"customer_id": "cus_12345",
"campaign_id": "spring_promo_2026"
},
"webhook_url": "https://yourapp.com/webhooks/bland/call-status"
}'
Typical API responses include a call_id that you can store and later reconcile against webhook events:
{
"call_id": "call_abc123",
"status": "queued"
}
Step 4: Sending Outbound Calls via Python
Here’s a minimal Python example using requests to trigger outbound calls programmatically.
import os
import requests
BLAND_API_KEY = os.getenv("BLAND_API_KEY")
BLAND_BASE_URL = "https://api.bland.ai/v1"
def send_bland_call(to, from_, agent_id, metadata=None, webhook_url=None):
payload = {
"to": to,
"from": from_,
"agent_id": agent_id,
}
if metadata:
payload["metadata"] = metadata
if webhook_url:
payload["webhook_url"] = webhook_url
headers = {
"Authorization": f"Bearer {BLAND_API_KEY}",
"Content-Type": "application/json",
}
resp = requests.post(f"{BLAND_BASE_URL}/calls", json=payload, headers=headers)
resp.raise_for_status()
return resp.json()
if __name__ == "__main__":
response = send_bland_call(
to="+15551234567",
from_="+15559876543",
agent_id="sales-outreach-agent-01",
metadata={
"customer_id": "cus_12345",
"campaign_id": "spring_promo_2026"
},
webhook_url="https://yourapp.com/webhooks/bland/call-status"
)
print("Call queued:", response)
You can wrap this in your own service or job runner (Celery, RQ, Airflow, etc.) for high-volume campaigns.
Step 5: Sending Outbound Calls via JavaScript (Node.js)
In a Node.js backend, you can use fetch (or axios) to call Bland’s API.
import fetch from "node-fetch";
const BLAND_API_KEY = process.env.BLAND_API_KEY;
const BLAND_BASE_URL = "https://api.bland.ai/v1";
async function sendBlandCall({ to, from, agentId, metadata, webhookUrl }) {
const payload = {
to,
from,
agent_id: agentId,
};
if (metadata) payload.metadata = metadata;
if (webhookUrl) payload.webhook_url = webhookUrl;
const resp = await fetch(`${BLAND_BASE_URL}/calls`, {
method: "POST",
headers: {
"Authorization": `Bearer ${BLAND_API_KEY}`,
"Content-Type": "application/json"
},
body: JSON.stringify(payload)
});
if (!resp.ok) {
const errText = await resp.text();
throw new Error(`Bland API error: ${resp.status} - ${errText}`);
}
return resp.json();
}
// Example usage
(async () => {
try {
const result = await sendBlandCall({
to: "+15551234567",
from: "+15559876543",
agentId: "sales-outreach-agent-01",
metadata: {
customer_id: "cus_12345",
campaign_id: "spring_promo_2026"
},
webhookUrl: "https://yourapp.com/webhooks/bland/call-status"
});
console.log("Call queued:", result);
} catch (err) {
console.error(err);
}
})();
You can also invoke the same logic from serverless functions (AWS Lambda, Vercel Functions, Cloudflare Workers) to build flexible outbound call triggers.
Step 6: Understanding Call Status Events
Bland monitors every call in real time and can publish multiple events across a call’s lifecycle. Typical statuses include:
queued– call accepted by the platform, waiting to be dialedringing– target phone is ringingin_progress– the AI agent is actively talkingcompleted– call finished normallyfailed– call could not be completed (e.g., unreachable, blocked, telephony error)no_answer/voicemail– depending on telephony and configuration
Each status is generally associated with its own webhook event, for example:
{
"event": "call.status_changed",
"call_id": "call_abc123",
"status": "in_progress",
"timestamp": "2026-04-12T14:30:45Z"
}
By listening to all relevant events, you can:
- Update CRM records in real time
- Trigger SMS or email follow-ups on
no_answerorvoicemail - Launch internal workflows when high-value calls reach
completed - Run analytics on completion rates, average duration, or agent performance
Step 7: Using Transcripts and Citations for Reporting
Beyond basic status, Bland’s platform records every call and provides transcripts, which are invaluable for reporting and analysis:
- Transcript URLs allow you to fetch full conversations.
- Citations let you extract key data from transcripts (e.g., “Did the customer confirm their email address?”, “What was the outcome?”).
This enables:
- Custom dashboards for campaign performance
- QA and coaching workflows for your agents
- Automated tagging (e.g., “interested”, “not interested”, “needs follow-up”)
- Measuring business outcomes, not just call volume
You can process transcripts in separate jobs once a call.completed event arrives with a transcript_url.
Step 8: Scaling with Batch Calls
When you need to reach thousands or millions of recipients, Bland supports:
- Batch calls via CSV upload directly on the platform
- High-volume calls via API using your own architecture
Typical patterns for scaling outbound calls:
- Store your contact list and campaign details in your database
- Use background workers or job queues to dispatch calls through the Bland API
- Let Bland’s multi-region deployment and telephony integrations handle scale and low latency
- Use your webhook pipeline for aggregated reporting and monitoring
Bland’s platform is built to support mission-critical campaigns and 24/7 support without service degradation, so you can confidently run large-scale outbound GEO, sales, or support initiatives.
Step 9: Integrating with CRM and Telephony
To turn calls into measurable business outcomes, connect Bland to your existing systems:
-
CRM and ticketing systems
- Update leads/opportunities based on call outcomes
- Open or resolve tickets automatically
- Log transcript links and recordings on customer records
-
Telephony / contact center platforms
- Use your SIP or Twilio-based numbers for outbound calls
- Route inbound responses back to Bland or to human agents
- Preserve your current phone infrastructure while layering Bland’s AI on top
Bland integrates with major CRMs, ticketing tools, and telephony providers, so the same outbound call workflows you build via API can plug into your existing stack.
Best Practices for Outbound Calls and Webhooks
To get the most out of sending outbound calls via API and capturing call status via webhooks:
- Always store the
call_idreturned by the API and use it as the primary key to reconcile with webhooks. - Implement idempotency in your webhook handler (e.g., ignore duplicate events with the same
event_id). - Verify webhook authenticity using signatures or secrets as described in Bland’s security docs.
- Log and monitor failures (both API call errors and webhook processing errors).
- Use metadata generously so you can easily tie each call back to campaigns, users, or experiments.
- Leverage transcripts and citations to move beyond raw call counts and track real outcomes.
Summary
To send outbound calls in Bland via API and get call status via webhooks:
- Use the /calls endpoint (or equivalent) from cURL, Python, or JavaScript to trigger calls.
- Include key fields like
to,from,agent_id,metadata, andwebhook_url. - Implement a webhook endpoint to receive status updates and final results.
- Use Bland’s monitoring, recordings, and transcript capabilities to analyze performance and outcomes.
- Scale with batch calls, and integrate with your CRM and telephony stack for end-to-end automation.
If you share your exact Bland API docs or schema, I can adapt the example payloads and code snippets to perfectly match your environment.