Leads API
Push leads for outbound calling, retrieve call details, cancel pending leads, and download recordings.
Every Breeze Buddy endpoint lives under /agent/voice/breeze-buddy. Paths below are relative to that prefix.
Push lead
Submit a new lead. The lead enters the BACKLOG queue and the scheduler dials based on the template’s call execution configuration.
/leads Request body
| Field | Type | Required | Description |
|---|---|---|---|
request_id | string | Yes | Your correlation ID. Returned as order_id in the response and in webhook payloads. No uniqueness enforcement today — treat it as a tag, not an idempotency key. |
template | string | Yes | Name of the template to run (must exist). |
payload | object | Yes | Variable values substituted into the template and the destination phone number (see below). |
reseller_id | string | Yes | Reseller scope. |
merchant_id | string | No | Merchant scope. Required if the template belongs to a merchant. |
reporting_webhook_url | string | No | URL called when the lead finishes. Stored inside payload and read at call completion. |
execution_mode | string | No | One of TELEPHONY (default), TELEPHONY_TEST, DAILY, DAILY_TEST, DAILY_STREAM. |
is_playground | bool | No | Mark as playground run — excluded from analytics and enables configurations_override. |
configurations_override | object | No | Playground-only: partial configurations object merged over the template’s config at runtime. Ignored unless is_playground: true. |
customer_mobile_number is required inside payload
The scheduler reads payload.customer_mobile_number to dial. If the key is missing or misspelled the lead silently stays in BACKLOG. Always include it in E.164 format (e.g. +14155551234).
Example request
curl -X POST $BASE_URL/agent/voice/breeze-buddy/leads \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"request_id": "req_unique_001",
"template": "appointment-reminder",
"reseller_id": "res_001",
"merchant_id": "mer_abc",
"execution_mode": "TELEPHONY",
"reporting_webhook_url": "https://your-server.com/webhooks/breeze",
"payload": {
"customer_mobile_number": "+919876543210",
"customer_name": "Rahul Sharma",
"appointment_date": "2026-02-01",
"appointment_time": "10:00 AM"
}
}'Response — 201 Created
{
"status": "queued",
"lead_call_tracker_id": "2b4e3e4a-9c5e-4b6a-ae7f-3d8e2c1a5b77",
"order_id": "req_unique_001",
"message": "Call request added to queue for processing"
}| Field | Description |
|---|---|
lead_call_tracker_id | The canonical lead ID. Use this for GET /leads/{id}, cancellation, and correlation with Langfuse traces. |
order_id | Echoes the request_id you sent. |
status | Always queued on success. The lead’s lifecycle status starts at BACKLOG — see lead statuses. |
Errors
| Status | Meaning | Common cause |
|---|---|---|
400 | Bad Request | Missing required field, unknown template, or invalid execution_mode. |
403 | Forbidden | payload.customer_mobile_number is on the blacklist. |
404 | Not Found | Template name does not exist under the reseller/merchant. |
422 | Unprocessable Entity | Schema validation failure — type mismatch or missing field in payload. |
500 | Internal Server Error | Database write failed. The lead is not queued; retry. |
Get lead details
/leads/{lead_id} Response — 200 OK
{
"id": "2b4e3e4a-9c5e-4b6a-ae7f-3d8e2c1a5b77",
"reseller_id": "res_001",
"merchant_id": "mer_abc",
"template": "appointment-reminder",
"request_id": "req_unique_001",
"status": "FINISHED",
"outcome": "confirmed",
"attempt_count": 1,
"call_id": "CA1234567890abcdef",
"call_initiated_time": "2026-02-01T10:35:00Z",
"call_end_time": "2026-02-01T10:36:12Z",
"recording_url": "https://storage/.../recording.mp3",
"cost": 0.0072,
"execution_mode": "TELEPHONY",
"call_direction": "OUTBOUND",
"outbound_number_id": "num_abc",
"langfuse_scores": { "breeze buddy outcome correctness": 1.0 },
"payload": {
"customer_mobile_number": "+919876543210",
"customer_name": "Rahul Sharma",
"reporting_webhook_url": "https://your-server.com/webhooks/breeze"
},
"metaData": {
"transcription": [
{ "role": "assistant", "content": "Hello Rahul, calling about your appointment on February 1st." },
{ "role": "user", "content": "Yes, that works." },
{ "role": "assistant", "content": "Great. Goodbye." }
],
"call_ended_by": "agent",
"node_traversal": ["greeting", "farewell"],
"errors": [],
"pre_check_results": []
},
"created_at": "2026-02-01T10:30:00Z",
"updated_at": "2026-02-01T10:36:15Z"
}metaData contents
metaData is the grab-bag of call-time details. Every field is optional and may be absent on leads that never dialled.
| Key | Description |
|---|---|
transcription | Array of {role, content} turns. role is user or assistant. |
call_ended_by | agent, customer, timeout, or error. |
node_traversal | Ordered list of node names visited during the conversation. |
errors | Free-form error objects captured by handlers; empty array on clean runs. |
pre_check_results | Per-pre-check outcome array (when pre-checks ran). |
Correlate with Langfuse
The call_id on the lead record is the telephony call SID (for telephony) or the Daily room name (for Daily). It is the exact filter key in Langfuse traces — paste it into Langfuse’s filter to pull up the trace for this call.
Cancel leads
/lead/abort Request body
{
"leads": [
{ "lead_id": "2b4e3e4a-9c5e-4b6a-ae7f-3d8e2c1a5b77", "cancellation_reason": "duplicate request" },
{ "lead_id": "9f17a0c4-2d31-4e8c-b3a0-c5d7e2f91b12", "cancellation_reason": "customer opted out" }
]
}| Field | Type | Required | Notes |
|---|---|---|---|
leads[].lead_id | string | Yes | The lead_call_tracker_id returned from push. |
leads[].cancellation_reason | string | Yes | Free text; stored on the lead for audit. |
Example request
curl -X POST $BASE_URL/agent/voice/breeze-buddy/lead/abort \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"leads": [
{ "lead_id": "2b4e3e4a-9c5e-4b6a-ae7f-3d8e2c1a5b77", "cancellation_reason": "duplicate request" }
]
}'Response — 200 OK
{
"leads": [
{ "id": "2b4e3e4a-9c5e-4b6a-ae7f-3d8e2c1a5b77", "status": "success", "message": "Lead aborted" },
{ "id": "9f17a0c4-2d31-4e8c-b3a0-c5d7e2f91b12", "status": "already_aborted", "message": "Lead already FINISHED" },
{ "id": "7c33b8d1-6ab2-4d49-9f5e-bb8d4f2a1c90", "status": "processing", "message": "Cannot abort — call is currently in progress" },
{ "id": "not-a-real-id", "status": "error", "message": "Lead not found" }
]
}status | Meaning |
|---|---|
success | Lead aborted (was in BACKLOG or RETRY). |
already_aborted | Lead already reached FINISHED. |
processing | Call is actively dialling or in conversation; cannot be aborted. |
error | Lead not found, or DB error. See message. |
The endpoint always returns 200; inspect per-lead status. Mixed-outcome payloads are normal.
Download recording
/leads/recording/{call_sid} The path parameter is the call SID (telephony) or Daily room name (Daily) — not the lead ID. Find it on the lead record as call_id.
Recording availability
Recordings take 1–2 minutes to process after the call ends. Daily recordings expire after 7 days on Daily’s side — retrieve them sooner. If cloud upload is enabled (UPLOAD_BREEZE_BUDDY_CALL_RECORDINGS_TO_CLOUD=true), the recording is persisted to GCS/S3 per your deployment.
Lead statuses
Four values are emitted by the backend today.
| Status | Description |
|---|---|
BACKLOG | Queued and waiting for the scheduler to pick it up. |
PROCESSING | Scheduler has claimed the lead; call is being dialled or is in progress. |
RETRY | Previous attempt failed; queued for another try within the template’s retry policy. |
FINISHED | Terminal. Read outcome for what actually happened — confirmed, rescheduled, PRECHECK_FAILED, no_answer, etc. |
Polling vs. webhooks
If you don’t configure reporting_webhook_url, poll GET /leads/{id}. Expect the status transitions BACKLOG → PROCESSING → FINISHED (with intermediate RETRY). Give up after the template’s max_retry + 1 attempts or 24 hours, whichever is later.
Execution modes
| Mode | Transport | LLM + template flow | Purpose |
|---|---|---|---|
TELEPHONY | Twilio / Plivo / Exotel | ✓ | Real phone call. Default if execution_mode is omitted. |
TELEPHONY_TEST | Twilio / Plivo / Exotel | ✓ | Telephony with test flags — excluded from production analytics. |
DAILY | Daily.co WebRTC | ✓ | Browser / mobile voice session driven by a template. |
DAILY_TEST | Daily.co WebRTC | ✓ | Same as DAILY, marked as test — excluded from analytics and allows playground configurations_override. |
DAILY_STREAM | Daily.co WebRTC | — | Stream mode. STT + TTS + transcription capture only. Client drives utterances via tts-speak. See Build with Daily for the full flow. |