Read a lead
GET /api/public/leads/:id — poll for status, transcript, and recording.
GET /api/public/leads/:id
Authorization: Bearer ck_live_...
Reads the current state of a single lead. Always scoped to the workspace owning the API key — a leaked key from Workspace A can never read Workspace B's leads.
Use this for
- Polling for status changes from your CRM.
- Pulling the transcript / recording URL once the call ends (voice workspaces).
- Showing booking confirmation status in your own UI.
Webhooks would be a better fit if you have a lot of leads — they're on the roadmap but not shipped yet.
Responses
200 OK
{
"ok": true,
"lead": {
"id": "f54466f4-afc3-4e27-84f9-a3be6fcac978",
"channel": "voice",
"name": "Jane Doe",
"phone": "+447123456789",
"email": "jane@acme.com",
"goal": "Looking to migrate from a competitor",
"status": "booked",
"qualificationNotes": null,
"bookingUid": "xshQhAccwdqJKxTDKFAUNi",
"bookingStart": "2026-06-08T13:00:00.000Z",
"metadata": {
"companyName": "Acme Corp",
"industry": "B2B SaaS"
},
"createdAt": "2026-06-07T13:03:37.162Z",
"updatedAt": "2026-06-07T13:09:11.444Z"
},
"voiceCall": {
"status": "ended",
"startedAt": "2026-06-07T13:03:42.000Z",
"endedAt": "2026-06-07T13:09:05.000Z",
"durationSeconds": 323,
"summary": "Jane confirmed she's evaluating us to replace Competitor X. Budget is ~£500/mo. Booked a consultation for Monday at 2pm.",
"transcript": "Assistant: Hi Jane, this is Riley from ...\n\nLead: Yeah, hi ...\n\n...",
"recordingUrl": "https://storage.vapi.ai/.../019ea22e-80ca-7001-95fb-4932d5c048f2.wav",
"endedReason": "customer-ended-call"
}
}
The voiceCall field is null for WhatsApp workspaces. For voice workspaces, it carries the latest call_session row.
Lead status values
status | Means |
|---|---|
new | Just arrived. Agent hasn't reached out yet. |
in_conversation | Agent has reached out and is qualifying. |
booked | Qualified + booked onto Cal.com. bookingUid + bookingStart populated. |
unqualified | Agent decided the lead isn't a fit. Reason in qualificationNotes. |
needs_human | Either the agent escalated, or an operator clicked "Take over" in the dashboard. |
404 Not Found
{ "ok": false, "error": "Lead not found." }
Returned when:
- The lead ID doesn't exist.
- The lead belongs to a different workspace from your API key.
(We deliberately don't distinguish the two — leaking the existence of leads across workspaces would be a security regression.)
401 Unauthorized
See Authentication.
Polling strategy
If you're using polling instead of webhooks:
- Poll every 10–30 seconds while the lead is
neworin_conversation. - Stop polling once
statusreaches a terminal state (booked,unqualified,needs_human) — those won't change without operator action. - For voice workspaces specifically, also stop polling when
voiceCall.status === "ended"— the call won't restart.
Don't poll faster than every 5 seconds; you'll burn through the hourly rate limit fast.