> ## Documentation Index
> Fetch the complete documentation index at: https://docs.ondial.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# CRM Lead Bank integration

> Simple guide for travel CRM — verify leads and missed follow-ups with Ondial API + webhooks.

# CRM Lead Bank ↔ Ondial AI Voice

**For:** Himalayan Holidayers / Indian Travel Store / Visit Asia CRM\
**Goal:** Your CRM sends a call job → Ondial AI calls the guest → Ondial sends the result back to your CRM.

This guide is written in simple language so your CRM team can implement quickly.

***

## 1. Your requirements (from your PDF)

You asked for **two jobs only**:

| Job                     | What you want                                                                                                        |
| ----------------------- | -------------------------------------------------------------------------------------------------------------------- |
| **1. Lead verify**      | New Lead Bank enquiry → AI calls guest → result back to CRM → CRM allocates or discards                              |
| **2. Missed follow-up** | If consultant does not complete follow-up within **30 minutes** → AI calls → CRM saves remarks + next follow-up time |

### Who does what (important)

| Work                                                       | Owner        |
| ---------------------------------------------------------- | ------------ |
| Duplicate / discard / “already called → do not send again” | **Your CRM** |
| Lead Bank → Allocation (branch + consultant)               | **Your CRM** |
| 30-minute missed follow-up timer                           | **Your CRM** |
| Write Follow-up tab (remarks + next time)                  | **Your CRM** |
| Place AI voice call                                        | **Ondial**   |
| Send call status + analytics to your webhook               | **Ondial**   |

***

## 2. What is supported today on Ondial

| Capability                                                 | Status      |
| ---------------------------------------------------------- | ----------- |
| Your CRM pushes a lead/call job via API                    | ✅ Supported |
| AI outbound voice call                                     | ✅ Supported |
| Webhook with call status                                   | ✅ Supported |
| Webhook with call analytics (outcome, remarks, transcript) | ✅ Supported |
| Schedule another follow-up call via API                    | ✅ Supported |
| Call recording via secure API                              | ✅ Supported |
| Sandbox testing (no live phone call)                       | ✅ Supported |

**Not done by Ondial (by design):** Lead Bank UI, Allocation, 30‑minute CRM timer, writing into your Follow-up tab. Your CRM does those using our webhook data.

***

## 3. How it works on our platform (simple)

```text theme={"system"}
Your CRM                         Ondial
────────                         ──────
1. Check duplicate / already called
2. POST /api/v1/leads  ─────────►  Queue AI call
                                   AI talks to guest
3. Receive webhook  ◄───────────  Status + Analytics
4. Allocate / Discard / Update Follow-up tab
```

**Base URL:** your Ondial dashboard host (example: `https://dashboard.ondial.ai`)\
**Auth:** `Authorization: Bearer <your_api_key>`

Public docs: [Push leads](/get-started/guides/push-leads) · [CRM & webhooks](/get-started/guides/crm-and-webhooks)

***

## 4. One-time setup

1. Request API key in Ondial Dashboard → **API Access**.
2. Create an **API / Custom CRM** campaign (Lead Verify). Start it.
3. Create a second campaign for **Missed Follow-up AI** (optional but recommended). Start it.
4. Register your CRM webhook URL (Dashboard → API Access → Notifications, or API below).
5. Subscribe at least to these events:
   * `outbound.lead.created`
   * `call.outbound.status`
   * `call.outbound.analysis`

### Register webhook (sample)

```bash theme={"system"}
curl -sS -X POST "$ONDIAL_BASE_URL/api/v1/webhooks" \
  -H "Authorization: Bearer $ONDIAL_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://your-crm.example.com/ondial/hooks",
    "eventTypes": [
      "outbound.lead.created",
      "outbound.lead.updated",
      "call.outbound.status",
      "call.outbound.analysis",
      "call.outbound.billed",
      "followup.scheduled",
      "credits.usage"
    ]
  }'
```

Save the **webhook secret**. Every delivery includes:

| Header                     | Meaning                                  |
| -------------------------- | ---------------------------------------- |
| `X-Ondial-Event`           | Event name                               |
| `X-Ondial-Signature`       | HMAC-SHA256 of raw body with your secret |
| `X-Ondial-Idempotency-Key` | Unique delivery key                      |

***

## 5. Use Case 1 — Lead Bank verify → Allocation

### Step A — Your CRM sends the verify call job

Only send if lead is **not** duplicate / discarded / already called.

```bash theme={"system"}
curl -sS -X POST "$ONDIAL_BASE_URL/api/v1/leads" \
  -H "Authorization: Bearer $ONDIAL_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: verify-LB-12345-2026-09-16" \
  -d '{
    "campaignId": "YOUR_VERIFY_CAMPAIGN_ID",
    "phone": "+919876543210",
    "name": "Rahul Sharma",
    "scheduledAt": "2026-09-16T11:05:00Z",
    "channel": "call",
    "consent": {
      "outboundCall": true,
      "capturedAt": "2026-09-16T10:00:00Z",
      "source": "crm"
    },
    "metadata": {
      "crmLeadId": "LB-12345",
      "destination": "Manali",
      "travelMonth": "October",
      "pax": 4,
      "companyName": "Indian Travel Store",
      "useCase": "lead_verify"
    }
  }'
```

`scheduledAt` is optional ISO 8601 UTC. Omit it to dial as soon as the campaign is active.

### Sample API response (201)

```json theme={"system"}
{
  "contactId": "66f0a1b2c3d4e5f678901234",
  "campaignId": "66f0aaaa1111222233334444",
  "status": "accepted",
  "mode": "live",
  "channels": ["call"],
  "scheduledAt": "2026-09-16T11:05:00.000Z",
  "phone": "+919876543210",
  "name": "Rahul Sharma",
  "metadata": {
    "crmLeadId": "LB-12345",
    "destination": "Manali",
    "travelMonth": "October",
    "pax": 4,
    "companyName": "Indian Travel Store",
    "useCase": "lead_verify"
  }
}
```

**Save `contactId`** on your CRM lead.

### Step B — Webhooks Ondial sends to your CRM

Every webhook body looks like:

```json theme={"system"}
{
  "eventType": "<EVENT_NAME>",
  "occurredAt": "2026-09-16T10:01:00.000Z",
  "data": { }
}
```

#### Event 1 — `outbound.lead.created`

Fired when Ondial accepts the new lead.

```json theme={"system"}
{
  "eventType": "outbound.lead.created",
  "occurredAt": "2026-09-16T10:00:05.000Z",
  "data": {
    "direction": "outbound",
    "action": "created",
    "contactId": "66f0a1b2c3d4e5f678901234",
    "campaignId": "66f0aaaa1111222233334444",
    "campaignName": "Lead Bank Verify",
    "source": "api",
    "status": "accepted",
    "mode": "live",
    "channels": ["call"],
    "name": "Rahul Sharma",
    "phone": "+919876543210",
    "phoneSuffix": "3210",
    "metadata": {
      "crmLeadId": "LB-12345",
      "destination": "Manali",
      "travelMonth": "October",
      "pax": 4,
      "useCase": "lead_verify"
    },
    "occurredAt": "2026-09-16T10:00:05.000Z"
  }
}
```

#### Event 2 — `call.outbound.status`

Fired when dial status changes (ringing, answered, completed, no answer, busy, failed).

```json theme={"system"}
{
  "eventType": "call.outbound.status",
  "occurredAt": "2026-09-16T10:02:10.000Z",
  "data": {
    "direction": "outbound",
    "callId": "call_9f3c2a1b",
    "status": "completed",
    "startedAt": "2026-09-16T10:01:00.000Z",
    "endedAt": "2026-09-16T10:02:05.000Z",
    "durationSeconds": 65,
    "fromNumber": "+9198XXXXXXXX",
    "toNumber": "+919876543210",
    "campaignId": "66f0aaaa1111222233334444",
    "contactId": "66f0a1b2c3d4e5f678901234",
    "hasTranscript": true,
    "hasAnalysis": false,
    "hasRecording": true,
    "phoneSuffix": "3210"
  }
}
```

Useful `status` values:

| `status`    | Meaning for your CRM                            |
| ----------- | ----------------------------------------------- |
| `completed` | Call connected and finished — wait for analysis |
| `no_answer` | No answer — retry / hold (your rule, max 2–3)   |
| `busy`      | Busy — retry later                              |
| `failed`    | Failed — hold / manual review                   |

#### Event 3 — `call.outbound.analysis` ★ main result for Allocation

Fired when AI analysis is ready (may be a few seconds after call ends).

```json theme={"system"}
{
  "eventType": "call.outbound.analysis",
  "occurredAt": "2026-09-16T10:02:40.000Z",
  "data": {
    "direction": "outbound",
    "callId": "call_9f3c2a1b",
    "campaignId": "66f0aaaa1111222233334444",
    "contactId": "66f0a1b2c3d4e5f678901234",
    "hasAnalysis": true,
    "analysisStatus": "completed",
    "classification": {
      "category": "Verified",
      "reason": "Guest confirmed name, Manali trip in October, 4 pax, and interest."
    },
    "conversationSummary": "Rahul confirmed interest in Manali for October with 4 travellers. Preferred callback after 6 PM.",
    "nextAction": {
      "type": "Call",
      "priority": "High",
      "action": "Allocate to consultant. First follow-up after 6 PM."
    },
    "conversation": {
      "transcript": "Agent: Hello, am I speaking with Rahul?\nUser: Yes.\nAgent: Are you planning Manali in October for 4 people?\nUser: Yes, interested.",
      "turnCount": 4,
      "turns": [
        { "role": "agent", "text": "Hello, am I speaking with Rahul?", "at": "2026-09-16T10:01:05.000Z" },
        { "role": "user", "text": "Yes.", "at": "2026-09-16T10:01:08.000Z" },
        { "role": "agent", "text": "Are you planning Manali in October for 4 people?", "at": "2026-09-16T10:01:15.000Z" },
        { "role": "user", "text": "Yes, interested.", "at": "2026-09-16T10:01:22.000Z" }
      ]
    }
  }
}
```

### Step C — What your CRM does after analysis

| `classification.category` (example) | Your CRM action                                      |
| ----------------------------------- | ---------------------------------------------------- |
| `Verified` / `Interested`           | Mark verified → **Allocation** (branch + consultant) |
| `Callback Requested`                | Verified + set first follow-up to preferred time     |
| `Not Interested`                    | Discard with reason + remarks                        |
| `Wrong Number` / `Invalid`          | Discard as fake / invalid                            |
| (from status) `no_answer` / `busy`  | Retry max 2–3, then hold for manual review           |

Use `conversationSummary` as **remarks**.\
Match lead with `metadata.crmLeadId` or saved `contactId`.

### Optional — Get recording URL

Recording is **not** inside the analysis webhook. Fetch it like this:

```bash theme={"system"}
curl -sS "$ONDIAL_BASE_URL/api/v1/calls/call_9f3c2a1b/recording" \
  -H "Authorization: Bearer $ONDIAL_API_KEY"
```

***

## 6. Use Case 2 — Follow-up pending 30 minutes → AI call

### Step A — Your CRM timer (not Ondial)

1. Follow-up time arrives.
2. Consultant still has not saved a follow-up.
3. Wait **30 minutes**.
4. If still pending → send AI call job to Ondial.

### Step B — Send follow-up AI call job

**Option 1 — New / requeue dial on follow-up campaign**

```bash theme={"system"}
curl -sS -X POST "$ONDIAL_BASE_URL/api/v1/leads" \
  -H "Authorization: Bearer $ONDIAL_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: followup-LB-12345-2026-09-16T11" \
  -d '{
    "campaignId": "YOUR_FOLLOWUP_CAMPAIGN_ID",
    "phone": "+919876543210",
    "name": "Rahul Sharma",
    "channel": "call",
    "requeue": true,
    "consent": {
      "outboundCall": true,
      "capturedAt": "2026-09-16T11:00:00Z",
      "source": "crm"
    },
    "metadata": {
      "crmLeadId": "LB-12345",
      "consultantName": "Anita Verma",
      "companyName": "Indian Travel Store",
      "useCase": "missed_followup"
    }
  }'
```

> If this phone already finished on that campaign, send `"requeue": true`. Otherwise Ondial returns `422 requeue_required`.

**Option 2 — Schedule follow-up on existing contact**

```bash theme={"system"}
curl -sS -X POST "$ONDIAL_BASE_URL/api/v1/contacts/66f0a1b2c3d4e5f678901234/followups" \
  -H "Authorization: Bearer $ONDIAL_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "campaignId": "YOUR_FOLLOWUP_CAMPAIGN_ID",
    "channels": ["call"],
    "scheduledAt": "2026-09-16T11:05:00Z",
    "force": true
  }'
```

### Step C — Webhooks (same event names)

You will again receive:

1. `outbound.lead.updated` (if requeued) **or** `followup.scheduled`
2. `call.outbound.status`
3. `call.outbound.analysis` ← use this to update Follow-up tab

#### Sample — `outbound.lead.updated` (requeued)

```json theme={"system"}
{
  "eventType": "outbound.lead.updated",
  "occurredAt": "2026-09-16T11:00:05.000Z",
  "data": {
    "direction": "outbound",
    "action": "requeued",
    "contactId": "66f0a1b2c3d4e5f678901234",
    "campaignId": "66f0bbbb1111222233334444",
    "status": "accepted",
    "channels": ["call"],
    "phone": "+919876543210",
    "metadata": {
      "crmLeadId": "LB-12345",
      "consultantName": "Anita Verma",
      "useCase": "missed_followup"
    }
  }
}
```

#### Sample — `followup.scheduled`

```json theme={"system"}
{
  "eventType": "followup.scheduled",
  "occurredAt": "2026-09-16T11:00:06.000Z",
  "data": {
    "contactId": "66f0a1b2c3d4e5f678901234",
    "campaignId": "66f0bbbb1111222233334444",
    "channels": ["call"],
    "scheduledAt": "2026-09-16T11:05:00.000Z"
  }
}
```

#### Sample — `call.outbound.analysis` (follow-up result)

```json theme={"system"}
{
  "eventType": "call.outbound.analysis",
  "occurredAt": "2026-09-16T11:08:00.000Z",
  "data": {
    "direction": "outbound",
    "callId": "call_aa11bb22",
    "campaignId": "66f0bbbb1111222233334444",
    "contactId": "66f0a1b2c3d4e5f678901234",
    "hasAnalysis": true,
    "analysisStatus": "completed",
    "classification": {
      "category": "Callback Requested",
      "reason": "Guest asked to call tomorrow at 11 AM."
    },
    "conversationSummary": "Guest is still interested. Requested callback tomorrow 11:00 AM. Do not close the lead.",
    "nextAction": {
      "type": "Call",
      "priority": "High",
      "action": "Set next follow-up to tomorrow 11:00 AM. Keep lead open for consultant Anita Verma."
    },
    "conversation": {
      "transcript": "Agent: ...\nUser: Please call tomorrow at 11.",
      "turnCount": 2,
      "turns": [
        { "role": "agent", "text": "When should we call you back?", "at": "2026-09-16T11:06:10.000Z" },
        { "role": "user", "text": "Tomorrow at 11 AM.", "at": "2026-09-16T11:06:18.000Z" }
      ]
    }
  }
}
```

### Step D — What your CRM does (Follow-up tab)

| Outcome                        | Your CRM action                                         |
| ------------------------------ | ------------------------------------------------------- |
| Connected / Callback requested | Save remarks + next follow-up date/time from guest      |
| Not interested                 | Save remarks; consultant review (**do not auto-close**) |
| Wrong number                   | Flag consultant (**do not auto-close**)                 |
| No answer / busy               | Save remarks; set next follow-up +30 / +60 minutes      |

***

## 7. Suggested outcome mapping

Agree these categories during campaign setup (script + analysis):

| Ondial `classification.category` | Use Case 1 (Lead Bank)      | Use Case 2 (Follow-up)    |
| -------------------------------- | --------------------------- | ------------------------- |
| `Verified`                       | → Allocation                | Update remarks + next FU  |
| `Callback Requested`             | Allocation + preferred slot | Set next FU to guest time |
| `Not Interested`                 | Discard                     | Remarks; no auto-close    |
| `Wrong Number`                   | Discard                     | Flag consultant           |
| Status `no_answer` / `busy`      | Retry then hold             | Next FU +30 / +60 min     |

***

## 8. Typical webhook order (one dial)

```text theme={"system"}
1. outbound.lead.created   (or outbound.lead.updated if requeue)
2. call.outbound.status      (e.g. completed / no_answer)
3. call.outbound.analysis    ★ use for CRM business decision
4. call.outbound.billed      (optional — billing)
5. credits.usage             (optional — wallet)
```

Always upsert by **`callId`**. A requeue creates a **new** `callId` and a new set of call webhooks.

***

## 9. Quick checklist

### Your CRM

* [ ] API key stored securely
* [ ] After Lead Bank checks → `POST /api/v1/leads` (verify campaign)
* [ ] Webhook URL live + signature verify
* [ ] On `call.outbound.analysis` → Allocation / Discard
* [ ] 30‑min missed follow-up timer → send follow-up AI job
* [ ] On analysis → update Follow-up tab
* [ ] Store `contactId` + `crmLeadId` together

### Ondial

* [ ] Verify campaign + follow-up campaign ready
* [ ] Analysis categories aligned with your table
* [ ] Retries 2–3 configured
* [ ] Sandbox test → then live

***

## 10. Summary

| Topic                        | Answer                                                      |
| ---------------------------- | ----------------------------------------------------------- |
| Can Ondial do your two jobs? | **Yes**                                                     |
| How do you send a call?      | `POST /api/v1/leads`                                        |
| How do you get the result?   | Webhooks: `call.outbound.status` + `call.outbound.analysis` |
| Who allocates the lead?      | **Your CRM** (using analysis webhook)                       |
| Who runs the 30‑min timer?   | **Your CRM**                                                |
| New product build needed?    | **No** — use existing API + webhooks                        |

**Bottom line:** Your CRM remains the brain (Lead Bank, Allocation, Follow-up). Ondial places the AI call and returns analytics to your webhook.
