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:

  1. Configure a bot in the admin UI (system prompt, voice, languages)
  2. Generate an API key (Admin → API Keys)
  3. Call POST /api/v1/sessions to create a session with optional lead context
  4. Send the returned assessment_url to the candidate
  5. 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

POST /api/v1/sessions API key required

Creates a new assessment session and returns a secure, time-limited URL for the candidate.

Request body

FieldTypeDescription
bot_idstring requiredUUID of the bot to use for this assessment
client_refstring optionalYour internal reference for this lead (e.g. lead UUID). Returned in the webhook payload.
contextobject optionalFlat key-value pairs injected into the system prompt at runtime. See Context injection.
webhook_urlstring optionalOverride the bot's webhook URL for this session only.
expires_in_hoursnumber optionalHow 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

GET /api/v1/sessions/:id API key required

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

StatusMeaning
pendingSession created, candidate hasn't opened the link yet
startedCandidate opened the link and began the assessment
completedAssessment finished. Scores and transcript are available.
failedAssessment ended with an error

List sessions

GET /api/v1/sessions API key required

Returns a paginated list of sessions for your organisation.

Query parameters

ParamTypeDescription
bot_idstringFilter by bot
statusstringFilter by status: pending, started, completed, failed
limitnumberMax results (default: 50, max: 200)
offsetnumberPagination 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:

AttemptDelay after previous failure
1 (immediate)0s — fired right after assessment completes
21 minute
35 minutes
415 minutes
560 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

POST /api/v1/webhook-test API key required

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

StatusMeaning
400Missing or invalid request body field
401Missing, invalid, or expired API key
403Bot is disabled
404Resource not found (session, bot)
410Assessment token has expired
422Bot has no webhook configured (for webhook-test)
500Internal server error

All error responses follow the shape:

{ "error": "Human-readable error message" }