Next LabAPI Docsv1

API Reference

Everything you need to integrate voice AI lead qualification.

POST/api/v1/calls/triggerAI calls your leadResults via webhook + API
1

Qualify

AI asks your custom criteria questions and evaluates answers server-side

2

Book

If qualified, the agent proposes viewing slots and books the visit

3

Report

Score, transcript, and criteria results delivered via webhook or API

Call Flow

1. POST /api/v1/calls/trigger

2. AI agent calls the lead via SIP

3. Agent introduces itself with your agency name

4. Agent confirms lead identity

5. Agent asks your qualification criteria

6. Answers evaluated server-side (deterministic)

7. If qualified → agent proposes viewing slots

8. If accepted → books viewing + SMS/email confirmation

9. Call ends → score calculated

10. POST results to your callback_webhook

11. GET /api/v1/calls/{callId} for results anytime

Authentication

All requests require an API key via the x-api-key header.

bash
curl "https://immo.next-lab.tech/api/v1/usage" \
  -H "x-api-key: ak_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"

Header: x-api-key: ak_live_xxx

Alternative: Authorization: Bearer ak_live_xxx

Rate limit: 10 requests/minute per API key

Get a key: Contact abdullah@next-lab.tech

Quick Start

Trigger your first AI call in under a minute.

bash
# Complete example with all available fields
curl -X POST "https://immo.next-lab.tech/api/v1/calls/trigger" \
  -H "x-api-key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "lead": {
      "firstName": "John",
      "lastName": "Smith",
      "phone": "+41791234567",
      "email": "john.smith@example.com",
      "language": "en",
      "budget": "3500",
      "remarks": "Prefers ground floor, needs parking"
    },
    "property": {
      "title": "Modern 4.5 Room Apartment in Geneva",
      "address": "Rue du Mont-Blanc 12, 1201 Geneva",
      "price": 3100,
      "type": "rent",
      "description": "Beautiful renovated 95m2 apartment, bright, lake view.",
      "features": ["Lake view", "Parking", "Cellar", "Balcony", "Equipped kitchen"],
      "area": 95,
      "rooms": 4.5,
      "bathrooms": 2,
      "terrace": 12
    },
    "agent_config": {
      "agent_name": "Sarah",
      "agency_name": "Avendo Real Estate",
      "transfer_number": "+41791234000",
      "notification_email": "notifications@avendo.ch",
      "hangup_instruction": "Thank you for your interest. We will follow up by email within 24 hours. Have a great day!",
      "qualification_criteria": [
        {
          "question": "What is your maximum monthly budget?",
          "type": "number",
          "expectedValue": "3100",
          "eliminatory": true,
          "rejectionMessage": "Unfortunately, the budget requirement for this property is 3100 CHF minimum."
        },
        {
          "question": "Do you have a stable job?",
          "type": "yes_no",
          "expectedValue": "yes",
          "eliminatory": true,
          "rejectionMessage": "A stable employment is required for this property."
        },
        {
          "question": "How many people will occupy the apartment?",
          "type": "number",
          "expectedValue": "1-4",
          "eliminatory": false
        }
      ],
      "transfer_conditions": [
        "Lead wants to negotiate the price",
        "Lead asks about financing options",
        "Lead mentions having a pet"
      ]
    },
    "viewing_slots": [
      {
        "date": "2026-03-20",
        "startTime": "14:00",
        "endTime": "15:00",
        "maxBookings": 3
      },
      {
        "date": "2026-03-21",
        "startTime": "10:00",
        "endTime": "11:00",
        "maxBookings": 2
      },
      {
        "date": "2026-03-22",
        "startTime": "16:00",
        "endTime": "17:00",
        "maxBookings": 1
      }
    ],
    "callback_webhook": "https://your-api.com/webhooks/immo-calls",
    "external_ref": "LEAD-12345-GENEVA"
  }'

Response:

json
{
  "callId": "a91b4f0f-00bc-429f-bac8-2ec0969aa214",
  "status": "initiated",
  "externalRef": "LEAD-001",
  "roomName": "immolab-call-..."
}

Poll for Results

bash
#!/bin/bash
CALL_ID="your-call-id"
API_KEY="your-api-key"

while true; do
  RESULT=$(curl -s "https://immo.next-lab.tech/api/v1/calls/$CALL_ID" \
    -H "x-api-key: $API_KEY")

  STATUS=$(echo $RESULT | jq -r '.status')
  echo "Status: $STATUS"

  if [ "$STATUS" = "completed" ] || [ "$STATUS" = "failed" ]; then
    echo $RESULT | jq .
    break
  fi

  sleep 10
done

Trigger Call

POST/api/v1/calls/trigger

Trigger an outbound AI voice call to qualify a lead.

Lead

lead.firstNamestringrequired

First name (alias: prenom)

lead.lastNamestringrequired

Last name (alias: nom)

lead.phonestringrequired

Phone number, intl format e.g. +41791234567 (alias: telephone)

lead.emailstringrequired

Email address

lead.languagestringrequired

"de", "fr", "en", or "nl"

lead.budgetstringoptional

Lead's stated budget

lead.remarksstringoptional

Additional notes for the agent

Property

property.titlestringrequired

Property title

property.addressstringrequired

Full address

property.pricenumberrequired

Price (rent per month or sale price)

property.typestringoptional

"sale" or "rent" (default: "sale")

property.descriptionstringrequired

Description the agent uses to answer property questions

property.featuresstring[]optional

Array of features/amenities

property.areanumberoptional

Living area in m²

property.roomsnumberoptional

Number of rooms (e.g. 4.5)

property.bathroomsnumberoptional

Number of bathrooms

property.terracenumberoptional

Terrace/balcony area in m²

Agent Configuration

agent_config.agent_namestringoptional

AI persona name (e.g. "Sarah"). Used in greeting: "Hello, this is Sarah from..."

agent_config.agency_namestringoptional

Company/agency name (default: "Next Lab"). Used in greeting: "...from Your Agency"

agent_config.qualification_criteriaarrayoptional

Questions to qualify the lead (see Scoring)

agent_config.transfer_numberstringoptional

Phone to transfer on complex questions

agent_config.transfer_conditionsarray<string>optional

Custom conditions that trigger transfer (in addition to defaults)

agent_config.notification_emailstringoptional

Email to receive booking/call notifications

agent_config.hangup_instructionstringoptional

Custom farewell message when ending the call (max 1000 chars)

Qualification Criteria

questionstringrequired

The question the agent asks

typestringoptional

"yes_no", "number", "text", or "multiple_choice" (default: "yes_no")

expectedValuestringrequired

Expected answer (see Scoring for evaluation rules)

eliminatorybooleanoptional

If true, wrong answer = disqualification (default: false)

rejectionMessagestringoptional

Custom message shown when criterion fails (deprecated - agent now continues all questions)

optionsstring[]optional

Available choices for "multiple_choice" type criteria

ordernumberoptional

Display order (0-indexed, default: array order)

Viewing Slots

viewing_slots[].datestringrequired

Date in YYYY-MM-DD format

viewing_slots[].startTimestringrequired

Start time in HH:MM format

viewing_slots[].endTimestringrequired

End time in HH:MM format

viewing_slots[].maxBookingsnumberoptional

Max bookings per slot (default: 1)

Advanced Options

callback_webhookstringoptional

URL to POST results when call completes

external_refstringoptional

Your unique reference ID (duplicates rejected with 409)

Get Call Result

GET/api/v1/calls/{callId}

Retrieve full results of a call including score, criteria, and transcript.

bash
curl "https://immo.next-lab.tech/api/v1/calls/CALL_ID" \
  -H "x-api-key: YOUR_API_KEY"

Response:

json
{
  "id": "a91b4f0f-00bc-429f-bac8-2ec0969aa214",
  "status": "completed",
  "externalRef": "LEAD-001",
  "leadName": "Jean Dupont",
  "leadPhone": "+41791234567",
  "leadEmail": "jean@example.com",
  "startedAt": "2026-03-07T21:55:47.227Z",
  "endedAt": "2026-03-07T21:58:04.040Z",
  "duration": "133s",
  "outcome": null,
  "score": 85,
  "qualified": true,
  "criteriaResults": [
    {
      "question": "Quel est votre budget mensuel?",
      "answer": "environ 3200",
      "passed": true,
      "eliminatory": true
    },
    {
      "question": "Avez-vous un emploi stable?",
      "answer": "Oui, absolument",
      "passed": true,
      "eliminatory": true
    }
  ],
  "transcript": [
    { "role": "agent", "text": "Bonjour, ici Your Agency...", "timestamp": "..." },
    { "role": "user", "text": "Oui, bonjour", "timestamp": "..." }
  ],
  "toolCallsLog": [
    { "timestamp": "...", "tool": "save_criterion_result" },
    { "timestamp": "...", "tool": "book_property_viewing" }
  ]
}

List Calls

GET/api/v1/calls

List all calls for your API key with optional filters.

limitnumberoptional

Max results, default 50, max 100

offsetnumberoptional

Pagination offset, default 0

statusstringoptional

Filter by status: pending, ringing, in_progress, completed, failed

bash
curl "https://immo.next-lab.tech/api/v1/calls?limit=20&status=completed" \
  -H "x-api-key: YOUR_API_KEY"

Response:

json
{
  "calls": [
    {
      "id": "a91b4f0f-...",
      "status": "completed",
      "externalRef": "LEAD-001",
      "leadName": "Jean Dupont",
      "leadPhone": "+41791234567",
      "score": 85,
      "qualified": true,
      "startedAt": "2026-03-07T21:55:47.227Z",
      "duration": "133s",
      "criteriaResults": [...]
    }
  ],
  "total": 14,
  "limit": 50,
  "offset": 0
}

Usage Stats

GET/api/v1/usage

Get your API key usage statistics, remaining calls, and qualification rates.

bash
curl "https://immo.next-lab.tech/api/v1/usage" \
  -H "x-api-key: YOUR_API_KEY"

Response:

json
{
  "totalCalls": 14,
  "maxCalls": 31,
  "remaining": 17,
  "byStatus": {
    "completed": 12,
    "failed": 2
  },
  "activeCalls": [],
  "averageScore": 78,
  "qualifiedCount": 9
}

Webhooks

When a call completes, if you provided callback_webhook, we POST the full results to your endpoint.

Method: POST

Content-Type: application/json

Timeout: 10 seconds

Fallback: If your endpoint is unreachable, results are always available via GET /api/v1/calls/{callId}

Webhook payload:

json
{
  "event": "call.completed",
  "callId": "a91b4f0f-00bc-429f-bac8-2ec0969aa214",
  "externalRef": "LEAD-001",
  "status": "completed",
  "duration": "133s",
  "leadName": "Jean Dupont",
  "leadPhone": "+41791234567",
  "leadEmail": "jean@example.com",
  "score": 85,
  "qualified": true,
  "criteriaResults": [
    {
      "criterionId": "...",
      "question": "Quel est votre budget mensuel?",
      "answer": "environ 3200",
      "passed": true,
      "eliminatory": true
    }
  ],
  "transcript": [
    {
      "role": "agent",
      "text": "Bonjour, ici Your Agency...",
      "timestamp": "2026-03-07T21:55:50.000Z"
    }
  ],
  "completedAt": "2026-03-07T21:58:04.040Z"
}

Tip: Use webhook.site to test webhook delivery during development.

Scoring System

Criteria answers are evaluated server-side (deterministic, not by AI). The score is calculated automatically after the call.

Evaluation Rules

TypeexpectedValueRuleExample
numberSingle value, e.g. "3100"Answer >= expected = PASSLead says "3200", expected "3100" → PASS
numberRange, e.g. "1-4"Answer within range = PASSLead says "3" → PASS, "6" → FAIL
yes_no"oui" or "non"Detects positive/negative words (FR/EN/DE)"Oui, absolument" → positive → matches "oui"
textFree textAI evaluates subjectively--

Points & Qualification

Eliminatory criterion

+30 pts|0 pts + disqualified

Non-eliminatory criterion

+10 pts|0 pts

score = (earned_points / max_possible_points) * 100

qualified = all eliminatory passed AND score >= 60%

Example: 2 eliminatory + 1 non-eliminatory = max 70 pts

Budget 3200 (expected >= 3100)PASS +30
Emploi stable: "oui" (expected "oui")PASS +30
Nb personnes: 6 (expected 1-4)FAIL +0
Total: 60/70Score 86 — Qualified

The score adapts proportionally to the number of criteria. 2 criteria or 10 criteria — the percentage always reflects the match quality.

Number Formats

The server handles international number formats automatically:

3 200

FR (space)

3'200

CH (apostrophe)

3.200

DE (period)

3,200

EN (comma)

All formats are normalized to 3200 before comparison.

Supported Languages

FR

Francais

"fr"

DE

Deutsch

"de"

EN

English

"en"

NL

Nederlands

"nl"

Set via lead.language. The agent speaks, asks questions, and sends SMS/email confirmations in the selected language. Yes/no evaluation also detects positive/negative words in all supported languages.

Error Codes

StatusMeaningExample
400Validation errorMissing or invalid fields in request body
401UnauthorizedMissing or invalid API key
403ForbiddenUsage limit exceeded or API key call limit reached
404Not foundCall ID does not exist or belongs to another key
409ConflictDuplicate external_ref (already used in another call)
429Rate limitedMore than 10 requests/minute
500Internal errorServer error — contact support

Error response format:

json
{
  "error": "Validation error",
  "details": [
    {
      "path": ["lead", "telephone"],
      "message": "String must contain at least 7 character(s)"
    }
  ]
}

ImmoLab API by Next Lab

next-lab.tech