Reference

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.

POST /leads

Request body

FieldTypeRequiredDescription
request_idstringYesYour 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.
templatestringYesName of the template to run (must exist).
payloadobjectYesVariable values substituted into the template and the destination phone number (see below).
reseller_idstringYesReseller scope.
merchant_idstringNoMerchant scope. Required if the template belongs to a merchant.
reporting_webhook_urlstringNoURL called when the lead finishes. Stored inside payload and read at call completion.
execution_modestringNoOne of TELEPHONY (default), TELEPHONY_TEST, DAILY, DAILY_TEST, DAILY_STREAM.
is_playgroundboolNoMark as playground run — excluded from analytics and enables configurations_override.
configurations_overrideobjectNoPlayground-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

push-lead.sh
bash
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

json
{
  "status": "queued",
  "lead_call_tracker_id": "2b4e3e4a-9c5e-4b6a-ae7f-3d8e2c1a5b77",
  "order_id": "req_unique_001",
  "message": "Call request added to queue for processing"
}
FieldDescription
lead_call_tracker_idThe canonical lead ID. Use this for GET /leads/{id}, cancellation, and correlation with Langfuse traces.
order_idEchoes the request_id you sent.
statusAlways queued on success. The lead’s lifecycle status starts at BACKLOG — see lead statuses.

Errors

StatusMeaningCommon cause
400Bad RequestMissing required field, unknown template, or invalid execution_mode.
403Forbiddenpayload.customer_mobile_number is on the blacklist.
404Not FoundTemplate name does not exist under the reseller/merchant.
422Unprocessable EntitySchema validation failure — type mismatch or missing field in payload.
500Internal Server ErrorDatabase write failed. The lead is not queued; retry.

Get lead details

GET /leads/{lead_id}

Response — 200 OK

json
{
  "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.

KeyDescription
transcriptionArray of {role, content} turns. role is user or assistant.
call_ended_byagent, customer, timeout, or error.
node_traversalOrdered list of node names visited during the conversation.
errorsFree-form error objects captured by handlers; empty array on clean runs.
pre_check_resultsPer-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

POST /lead/abort

Request body

json
{
  "leads": [
    { "lead_id": "2b4e3e4a-9c5e-4b6a-ae7f-3d8e2c1a5b77", "cancellation_reason": "duplicate request" },
    { "lead_id": "9f17a0c4-2d31-4e8c-b3a0-c5d7e2f91b12", "cancellation_reason": "customer opted out" }
  ]
}
FieldTypeRequiredNotes
leads[].lead_idstringYesThe lead_call_tracker_id returned from push.
leads[].cancellation_reasonstringYesFree text; stored on the lead for audit.

Example request

cancel-leads.sh
bash
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

json
{
  "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" }
  ]
}
statusMeaning
successLead aborted (was in BACKLOG or RETRY).
already_abortedLead already reached FINISHED.
processingCall is actively dialling or in conversation; cannot be aborted.
errorLead not found, or DB error. See message.

The endpoint always returns 200; inspect per-lead status. Mixed-outcome payloads are normal.

Download recording

GET /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.

StatusDescription
BACKLOGQueued and waiting for the scheduler to pick it up.
PROCESSINGScheduler has claimed the lead; call is being dialled or is in progress.
RETRYPrevious attempt failed; queued for another try within the template’s retry policy.
FINISHEDTerminal. 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

ModeTransportLLM + template flowPurpose
TELEPHONYTwilio / Plivo / ExotelReal phone call. Default if execution_mode is omitted.
TELEPHONY_TESTTwilio / Plivo / ExotelTelephony with test flags — excluded from production analytics.
DAILYDaily.co WebRTCBrowser / mobile voice session driven by a template.
DAILY_TESTDaily.co WebRTCSame as DAILY, marked as test — excluded from analytics and allows playground configurations_override.
DAILY_STREAMDaily.co WebRTCStream mode. STT + TTS + transcription capture only. Client drives utterances via tts-speak. See Build with Daily for the full flow.

Next steps

Was this helpful?