# Lead Qualification Agent

> Build a voice agent that qualifies leads, collects information, and routes qualified prospects to sales.

Source: https://edesy.in/docs/voice-agent/examples/lead-qualification

An intelligent voice agent that qualifies inbound leads by asking targeted questions, scoring prospects, and routing qualified leads to your sales team.

## Configuration

```json
{
  "agent": {
    "name": "Lead Qualifier",
    "language": "en-US",

    "llmProvider": "gemini-2.5",
    "llmModel": "gemini-2.5-flash-lite",
    "llmTemperature": 0.6,

    "sttProvider": "deepgram",
    "sttModel": "nova-3",

    "ttsProvider": "cartesia",
    "ttsVoice": "95856005-0332-41b0-935f-352e296aa0df",

    "greetingMessage": "Hi! Thanks for your interest in our product. I'd love to learn more about your needs to see how we can help. Do you have a few minutes?",

    "prompt": "...",

    "allowInterruptions": true
  }
}
```

## System Prompt

```
You are a lead qualification specialist. Your goal is to understand the prospect's needs, qualify them, and schedule a meeting with sales if they're a good fit.

## Qualification Criteria (BANT)

### Budget
- What budget range are they working with?
- Are they decision-makers on budget?

### Authority
- What is their role?
- Who else is involved in decisions?

### Need
- What problem are they trying to solve?
- How urgent is it?

### Timeline
- When are they looking to implement?
- Is there a specific deadline?

## Qualification Questions

Ask these naturally throughout the conversation:

1. "What brings you to [Company] today?"
2. "Tell me about your current situation with [problem area]"
3. "What would solving this problem mean for your business?"
4. "Who else would be involved in evaluating solutions?"
5. "What's your timeline for making a decision?"
6. "Do you have a budget range in mind?"

## Scoring Guidelines

**Hot Lead (Score 80-100)**
- Clear budget authority
- Decision-maker or strong influencer
- Urgent need (within 30 days)
- Specific pain points that match our solution

**Warm Lead (Score 50-79)**
- Budget being discussed
- Part of buying committee
- Timeline within 90 days
- General interest, exploring options

**Cold Lead (Score 0-49)**
- No budget authority
- Just researching
- No timeline
- Needs we can't address

## Response Style
- Be conversational, not interrogative
- Listen actively and respond to what they say
- Don't rapid-fire questions
- Share relevant info about our solution when appropriate
- Be enthusiastic but not pushy

## Handling Objections

"I'm just looking":
→ "Totally understand! What sparked your interest today?"

"We don't have budget":
→ "Makes sense. When do budget discussions typically happen?"

"I need to talk to my team":
→ "Of course! What would be most helpful for me to share with them?"

## Next Steps

For qualified leads:
→ "Based on what you've shared, I think there's a great fit. Would you be open to a 15-minute call with our solutions team to dive deeper?"

For unqualified leads:
→ "Thanks for sharing! It sounds like timing isn't quite right. Can I send you some resources to review?"
```

## Tools

### Save Lead Information

```json
{
  "type": "function",
  "function": {
    "name": "save_lead",
    "description": "Save lead information to CRM",
    "parameters": {
      "type": "object",
      "properties": {
        "name": {
          "type": "string",
          "description": "Lead's full name"
        },
        "company": {
          "type": "string",
          "description": "Company name"
        },
        "role": {
          "type": "string",
          "description": "Job title/role"
        },
        "email": {
          "type": "string",
          "description": "Email address"
        },
        "phone": {
          "type": "string",
          "description": "Phone number"
        },
        "needs": {
          "type": "string",
          "description": "Summary of their needs"
        },
        "budget": {
          "type": "string",
          "description": "Budget range if discussed"
        },
        "timeline": {
          "type": "string",
          "description": "Timeline for decision"
        },
        "score": {
          "type": "integer",
          "description": "Lead score 0-100"
        },
        "notes": {
          "type": "string",
          "description": "Additional notes"
        }
      },
      "required": ["name", "needs", "score"]
    }
  }
}
```

### Schedule Meeting

```json
{
  "type": "function",
  "function": {
    "name": "schedule_meeting",
    "description": "Schedule a meeting with sales team",
    "parameters": {
      "type": "object",
      "properties": {
        "lead_id": {
          "type": "string"
        },
        "preferred_times": {
          "type": "array",
          "items": { "type": "string" },
          "description": "Preferred meeting times"
        },
        "meeting_type": {
          "type": "string",
          "enum": ["discovery", "demo", "technical_review"]
        }
      },
      "required": ["lead_id", "meeting_type"]
    }
  }
}
```

### Check Availability

```json
{
  "type": "function",
  "function": {
    "name": "check_availability",
    "description": "Check sales team availability",
    "parameters": {
      "type": "object",
      "properties": {
        "date_range_start": {
          "type": "string",
          "description": "Start date (YYYY-MM-DD)"
        },
        "date_range_end": {
          "type": "string",
          "description": "End date (YYYY-MM-DD)"
        }
      }
    }
  }
}
```

## Tool Handlers

```go
type Lead struct {
    ID        string
    Name      string
    Company   string
    Role      string
    Email     string
    Phone     string
    Needs     string
    Budget    string
    Timeline  string
    Score     int
    Notes     string
    CreatedAt time.Time
}

func handleSaveLead(params map[string]any) (string, error) {
    lead := Lead{
        ID:        generateID(),
        Name:      params["name"].(string),
        Needs:     params["needs"].(string),
        Score:     int(params["score"].(float64)),
        CreatedAt: time.Now(),
    }

    // Optional fields
    if company, ok := params["company"].(string); ok {
        lead.Company = company
    }
    if role, ok := params["role"].(string); ok {
        lead.Role = role
    }
    if email, ok := params["email"].(string); ok {
        lead.Email = email
    }
    if budget, ok := params["budget"].(string); ok {
        lead.Budget = budget
    }
    if timeline, ok := params["timeline"].(string); ok {
        lead.Timeline = timeline
    }
    if notes, ok := params["notes"].(string); ok {
        lead.Notes = notes
    }

    // Save to CRM
    err := crm.SaveLead(lead)
    if err != nil {
        return "", err
    }

    // If hot lead, notify sales
    if lead.Score >= 80 {
        notifySalesTeam(lead)
    }

    return fmt.Sprintf("Lead saved with ID %s. Score: %d", lead.ID, lead.Score), nil
}

func handleScheduleMeeting(params map[string]any) (string, error) {
    leadID := params["lead_id"].(string)
    meetingType := params["meeting_type"].(string)

    // Get available slots
    slots, _ := calendar.GetAvailableSlots(3) // Next 3 available

    if len(slots) == 0 {
        return "I don't have any available slots right now. Can I have someone reach out to you?", nil
    }

    // Format slots for speech
    response := "Great! I have a few times available: "
    for i, slot := range slots {
        response += formatTimeForSpeech(slot)
        if i < len(slots)-1 {
            response += ", or "
        }
    }
    response += ". Which works best for you?"

    return response, nil
}
```

## Lead Scoring Logic

```go
type LeadScore struct {
    Budget    int // 0-25
    Authority int // 0-25
    Need      int // 0-25
    Timeline  int // 0-25
}

func calculateScore(lead *Lead) int {
    var score LeadScore

    // Budget scoring
    switch lead.Budget {
    case "over_50k":
        score.Budget = 25
    case "25k_50k":
        score.Budget = 20
    case "10k_25k":
        score.Budget = 15
    case "under_10k":
        score.Budget = 10
    default:
        score.Budget = 5
    }

    // Authority scoring
    switch lead.Role {
    case "ceo", "cto", "vp":
        score.Authority = 25
    case "director":
        score.Authority = 20
    case "manager":
        score.Authority = 15
    case "individual":
        score.Authority = 10
    default:
        score.Authority = 5
    }

    // Need scoring
    if lead.Needs != "" && strings.Contains(lead.Needs, "urgent") {
        score.Need = 25
    } else if lead.Needs != "" {
        score.Need = 15
    } else {
        score.Need = 5
    }

    // Timeline scoring
    switch lead.Timeline {
    case "immediate", "this_month":
        score.Timeline = 25
    case "this_quarter":
        score.Timeline = 20
    case "this_year":
        score.Timeline = 10
    default:
        score.Timeline = 5
    }

    return score.Budget + score.Authority + score.Need + score.Timeline
}
```

## Conversation Flow

```
1. Greeting & Permission
   ↓
2. Understand Situation (Need)
   ↓
3. Explore Impact (qualify need)
   ↓
4. Discuss Decision Process (Authority)
   ↓
5. Timeline Discussion
   ↓
6. Budget (if appropriate)
   ↓
7. Score & Route
   ├─ Hot (80+) → Schedule meeting
   ├─ Warm (50-79) → Send resources + follow-up
   └─ Cold (<50) → Thank + nurture
```

## Outbound Lead Qualification

For outbound campaigns, use variables to personalize:

```bash
curl -X POST https://voice-agent.edesy.in/api/v1/calls \
  -d '{
    "agent_id": "lead_qualifier",
    "to": "+1234567890",
    "variables": {
      "leadName": "Sarah",
      "company": "Acme Corp",
      "triggerEvent": "downloaded whitepaper",
      "salesRep": "John from Sales"
    }
  }'
```

**Outbound Greeting:**

```
Hi {{leadName}}! This is Alex from [Company]. I noticed you {{triggerEvent}} recently and wanted to reach out. Do you have a quick minute?
```

## Analytics

```go
type QualificationMetrics struct {
    TotalCalls           int
    QualifiedLeads       int
    MeetingsScheduled    int
    AverageCallDuration  time.Duration
    AverageLeadScore     float64
    QualificationRate    float64
    ConversionRate       float64
}

func trackQualification(call *Call, lead *Lead) {
    metrics.Increment("leads.calls.total")
    metrics.Histogram("leads.score", float64(lead.Score))
    metrics.Histogram("leads.call_duration", call.Duration.Seconds())

    if lead.Score >= 50 {
        metrics.Increment("leads.qualified")
    }

    if call.MeetingScheduled {
        metrics.Increment("leads.meetings.scheduled")
    }
}
```

## Best Practices

### 1. Natural Conversation Flow

```go
// Don't rapid-fire questions
badFlow := []string{
    "What's your budget?",
    "What's your timeline?",
    "Who makes decisions?",
}

// Build on their responses
goodFlow := `
Lead: "We're struggling with X"
You: "I hear that a lot. Tell me more about how X is affecting your business..."
Lead: [shares more]
You: "That sounds challenging. What would solving this mean for your team?"
`
```

### 2. Handle "Not Interested"

```go
notInterestedResponses := map[string]string{
    "timing": "Totally understand. Would it be helpful if I sent some resources for when timing is better?",
    "competitor": "Got it! Just curious - what drew you to [competitor]?",
    "budget": "Makes sense. Budgets are tight everywhere. When do planning cycles typically happen?",
}
```

### 3. Capture Information Naturally

```go
// Extract info from conversation, don't ask directly
func extractLeadInfo(transcript string) *Lead {
    // Use LLM to extract structured data from natural conversation
    prompt := `Extract lead information from this conversation:
    - Name
    - Company
    - Role
    - Budget signals
    - Timeline
    - Pain points
    - Decision process`

    return llm.Extract(transcript, prompt)
}
```

## Next Steps

- [Outbound Sales](https://edesy.in/docs/voice-agent/examples/outbound-sales) - Proactive sales calls
- [Customer Support](https://edesy.in/docs/voice-agent/examples/customer-support) - Support agent
- [Function Calling](https://edesy.in/docs/voice-agent/features/function-calling) - Tool integration
