API Reference
LeadVoice by BotBrained — Voice Assessment as a Service
Overview
LeadVoice lets you add AI voice assessments to any lead pipeline via a simple REST API. You create a session, send the candidate the assessment URL, and receive structured results (scores + transcript) via webhook when the assessment completes.
The typical flow:
- Configure a bot in the admin UI (system prompt, voice, languages)
- Generate an API key (Admin → API Keys)
- Call
POST /api/v1/sessionsto create a session with optional lead context - Send the returned
assessment_urlto the candidate - Receive results at your webhook when the assessment completes
Authentication
All authenticated endpoints require an API key in the Authorization header:
Authorization: Bearer lv_sk_your_api_key_here
API keys are generated in Admin → API Keys. The full key is shown once — store it securely. Keys can be scoped to a specific bot and can expire.
Never expose your API key client-side. All authenticated API calls must be made from your server.
Base URL
https://leadvoice.botbrained.com
For local development: http://localhost:3000
Create session
Creates a new assessment session and returns a secure, time-limited URL for the candidate.
Request body
| Field | Type | Description |
|---|---|---|
| bot_id | string required | UUID of the bot to use for this assessment |
| client_ref | string optional | Your internal reference for this lead (e.g. lead UUID). Returned in the webhook payload. |
| context | object optional | Flat key-value pairs injected into the system prompt at runtime. See Context injection. |
| webhook_url | string optional | Override the bot's webhook URL for this session only. |
| expires_in_hours | number optional | How long the assessment URL remains valid. Default: 72. Min: 1. Max: 720. |
Example request
curl -X POST https://leadvoice.botbrained.com/api/v1/sessions \ -H "Authorization: Bearer lv_sk_your_key" \ -H "Content-Type: application/json" \ -d '{ "bot_id": "550e8400-e29b-41d4-a716-446655440000", "client_ref": "lead-abc123", "expires_in_hours": 48, "context": { "name": "Rahul Sharma", "course": "MBA", "city": "Mumbai" } }'
Response 201 Created
{
"session_id": "7c9e6679-7425-40de-944b-e07fc1f90ae7",
"assessment_url": "https://leadvoice.botbrained.com/assess?t=a1b2c3…",
"expires_at": "2026-04-17T10:00:00.000Z"
}
Get session
Returns the current state and results of a session. Poll this if you prefer pull over webhook push.
Response 200 OK
{
"session_id": "7c9e6679…",
"bot_id": "550e8400…",
"client_ref": "lead-abc123",
"status": "completed",
"started_at": "2026-04-15T09:01:00Z",
"completed_at": "2026-04-15T09:12:00Z",
"language_used": "Hindi",
"overall_recommendation": "Hot Lead",
"scores": {
"potential": { "score": 8, "reason": "Strong motivation…" },
"fluency": { "score": 7, "reason": "Clear communication…" },
"admissibility": { "score": 9, "reason": "Meets all criteria…" }
},
"captured_data": { "preferred_start": "July 2026" },
"transcript": [
{ "role": "model", "text": "Hi Rahul! Tell me about yourself…" },
{ "role": "user", "text": "I'm a software engineer with 5 years…" }
]
}
Session status values
| Status | Meaning |
|---|---|
| pending | Session created, candidate hasn't opened the link yet |
| started | Candidate opened the link and began the assessment |
| completed | Assessment finished. Scores and transcript are available. |
| failed | Assessment ended with an error |
List sessions
Returns a paginated list of sessions for your organisation.
Query parameters
| Param | Type | Description |
|---|---|---|
| bot_id | string | Filter by bot |
| status | string | Filter by status: pending, started, completed, failed |
| limit | number | Max results (default: 50, max: 200) |
| offset | number | Pagination offset (default: 0) |
Example
curl "https://leadvoice.botbrained.com/api/v1/sessions?status=completed&limit=20" \ -H "Authorization: Bearer lv_sk_your_key"
Response 200 OK
{
"sessions": [ /* array of session objects */ ],
"total": 142,
"limit": 20,
"offset": 0
}
Webhook payload
When an assessment completes, LeadVoice sends a POST request to your webhook URL with the full results.
{
"event": "session.completed",
"session_id": "7c9e6679…",
"client_ref": "lead-abc123",
"language_used": "Hindi",
"overall_recommendation": "Hot Lead",
"scores": {
"potential": { "score": 8, "reason": "…" },
"fluency": { "score": 7, "reason": "…" },
"admissibility": { "score": 9, "reason": "…" }
},
"captured_data": { "preferred_start": "July 2026" },
"transcript": [
{ "role": "model", "text": "Hi Rahul…" },
{ "role": "user", "text": "I'm interested in…" }
]
}
Signature verification
Every webhook request includes an X-LeadVoice-Signature header. Verify it to confirm the request came from LeadVoice and wasn't tampered with.
# Header format
X-LeadVoice-Signature: sha256=<hex_digest>
Verification — Node.js
import crypto from 'crypto'; function verifySignature(rawBody, signature, secret) { const expected = 'sha256=' + crypto .createHmac('sha256', secret) .update(rawBody) // rawBody must be the raw Buffer/string .digest('hex'); return crypto.timingSafeEqual( Buffer.from(signature), Buffer.from(expected) ); } // Express: use express.raw() — NOT express.json() — on this route app.post('/webhook/leadvoice', express.raw({ type: 'application/json' }), (req, res) => { const sig = req.headers['x-leadvoice-signature']; if (!verifySignature(req.body, sig, process.env.LEADVOICE_WEBHOOK_SECRET)) { return res.status(401).send('Invalid signature'); } const payload = JSON.parse(req.body); // handle payload... res.json({ received: true }); });
Important: You must read the raw request body before calling JSON.parse(). Using express.json() middleware re-serialises the body and will break HMAC verification.
Retry schedule
If your endpoint returns a non-2xx status or times out, LeadVoice retries automatically:
| Attempt | Delay after previous failure |
|---|---|
| 1 (immediate) | 0s — fired right after assessment completes |
| 2 | 1 minute |
| 3 | 5 minutes |
| 4 | 15 minutes |
| 5 | 60 minutes |
After 5 attempts, delivery stops. The error and last attempt time are recorded in the session.
Your webhook should respond within 15 seconds and return any 2xx status. Process asynchronously if needed — respond immediately, enqueue the work.
Test webhook
Fires a test payload to the bot's configured webhook URL. Useful to verify your endpoint is reachable and signature verification works.
curl -X POST https://leadvoice.botbrained.com/api/v1/webhook-test \ -H "Authorization: Bearer lv_sk_your_key" \ -H "Content-Type: application/json" \ -d '{ "bot_id": "550e8400…" }'
Context injection
Pass a flat JSON object as context when creating a session. Values are injected into the bot's system prompt before the assessment starts.
In your system prompt (admin UI)
You are speaking with ${name}.
They have applied for ${course} starting ${intake}.
They are based in ${city} and have a budget of ${budget}.
Begin by greeting them warmly using their name.
In your API call
{
"bot_id": "…",
"context": {
"name": "Rahul Sharma",
"course": "MBA",
"intake": "September 2026",
"city": "Mumbai",
"budget": "50000"
}
}
Both ${name} and ${context.name} syntax are supported. Values are converted to strings. Keep context flat — nested objects won't interpolate.
Scoring
The bot's system prompt should instruct the model to output a structured JSON block at the end of the assessment. LeadVoice extracts this automatically.
Expected JSON shape (embedded anywhere in the model's final turn):
{
"scores": {
"lead_potential": { "score": 8, "reason": "Strong motivation and clear goals" },
"lead_english_fluency": { "score": 7, "reason": "Communicates clearly with minor gaps" },
"lead_admissibility": { "score": 9, "reason": "Meets all admission criteria" }
},
"overall_recommendation": "Hot Lead",
"captured_data": {
"preferred_start": "July 2026",
"work_experience": "5 years"
}
}
Scores are integers 1–10. overall_recommendation must be one of: Hot Lead, Warm Lead, Cold Lead. If no valid JSON is found, scores are stored as null.
Errors
| Status | Meaning |
|---|---|
| 400 | Missing or invalid request body field |
| 401 | Missing, invalid, or expired API key |
| 403 | Bot is disabled |
| 404 | Resource not found (session, bot) |
| 410 | Assessment token has expired |
| 422 | Bot has no webhook configured (for webhook-test) |
| 500 | Internal server error |
All error responses follow the shape:
{ "error": "Human-readable error message" }