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

# Lost Deal Focus Group

> Create persona archetypes from Pipedrive lost-deal patterns and run Focus Groups to surface qualitative reasoning behind each loss category

## Scenario

Deals marked "lost" carry structured data: `lost_reason`, amount, stage at loss. You **create persona archetypes for each lost-deal pattern** and run a Focus Group to surface qualitative reasoning behind each loss category.

## Architecture

```mermaid theme={"dark"}
flowchart LR
    A["Pipedrive Deals (lost)"] --> B[Cluster by lost_reason] --> C[Build personas per cluster] --> D["POST /api/v1/focus-groups"] --> E[Loss analysis]
```

## Code

<CodeGroup>
  ```python Python theme={"dark"}
  import os, requests
  from collections import defaultdict

  DOMAIN = os.environ["PIPEDRIVE_DOMAIN"]
  PD_TOKEN = os.environ["PIPEDRIVE_API_TOKEN"]
  PD_BASE = f"https://{DOMAIN}.pipedrive.com"
  MAVERA_KEY = os.environ["MAVERA_API_KEY"]

  def pd_get(path, params=None):
      params = params or {}
      params["api_token"] = PD_TOKEN
      r = requests.get(f"{PD_BASE}{path}", params=params)
      r.raise_for_status()
      return r.json()

  # 1. Pull lost deals and cluster by reason
  lost_deals = pd_get("/api/v2/deals", {"status": "lost", "limit": 200}).get("data", []) or []
  clusters = defaultdict(list)
  for deal in lost_deals:
      reason = deal.get("lost_reason") or "No reason given"
      clusters[reason].append({"title": deal.get("title"), "value": deal.get("value", 0), "stage_id": deal.get("stage_id")})

  # 2. Build personas per archetype
  personas = []
  for reason, deals in clusters.items():
      avg_val = sum(d["value"] or 0 for d in deals) / max(len(deals), 1)
      personas.append({
          "name": f"Lost: {reason[:40]}",
          "description": f"Represents {len(deals)} deals lost because: '{reason}'. Avg value: ${avg_val:,.0f}.",
      })

  # 3. Run Focus Group
  fg_resp = requests.post(
      "https://app.mavera.io/api/v1/focus-groups",
      headers={"Authorization": f"Bearer {MAVERA_KEY}"},
      json={
          "title": "Pipedrive Lost Deal Analysis",
          "personas": personas[:8],
          "questions": [
              "Why did you ultimately decide not to buy?",
              "Was pricing the primary factor, or were there deeper concerns?",
              "How did competitors position themselves against us?",
              "What product capability would have changed your decision?",
              "If we returned in 6 months with improvements, what would you need to see?",
          ],
      },
  )
  fg_resp.raise_for_status()
  fg = fg_resp.json()

  for resp in fg.get("responses", []):
      print(f"\n--- {resp['persona_name']} ---")
      for a in resp.get("answers", []):
          print(f"  Q: {a['question']}\n  A: {a['answer'][:400]}\n")
  ```

  ```javascript JavaScript theme={"dark"}
  const DOMAIN = process.env.PIPEDRIVE_DOMAIN;
  const PD_TOKEN = process.env.PIPEDRIVE_API_TOKEN;
  const PD_BASE = `https://${DOMAIN}.pipedrive.com`;

  async function pdGet(path, params = {}) {
    const url = new URL(`${PD_BASE}${path}`);
    url.searchParams.set("api_token", PD_TOKEN);
    for (const [k, v] of Object.entries(params)) url.searchParams.set(k, v);
    const res = await fetch(url);
    if (!res.ok) throw new Error(`Pipedrive ${res.status}`);
    return res.json();
  }

  // 1. Pull lost deals, cluster by reason
  const lostDeals = (await pdGet("/api/v2/deals", { status: "lost", limit: 200 })).data || [];
  const clusters = {};
  for (const deal of lostDeals) {
    const reason = deal.lost_reason || "No reason given";
    (clusters[reason] ||= []).push({ title: deal.title, value: deal.value || 0, stage_id: deal.stage_id });
  }

  // 2. Build personas
  const personas = Object.entries(clusters).map(([reason, deals]) => {
    const avgVal = deals.reduce((s, d) => s + d.value, 0) / deals.length;
    return { name: `Lost: ${reason.slice(0, 40)}`, description:
      `Represents ${deals.length} deals lost because: '${reason}'. Avg value: $${avgVal.toLocaleString()}.` };
  });

  // 3. Focus Group
  const fgRes = await fetch("https://app.mavera.io/api/v1/focus-groups", {
    method: "POST",
    headers: { Authorization: `Bearer ${process.env.MAVERA_API_KEY}`, "Content-Type": "application/json" },
    body: JSON.stringify({
      title: "Pipedrive Lost Deal Analysis",
      personas: personas.slice(0, 8),
      questions: [
        "Why did you decide not to buy?",
        "Was pricing primary, or deeper concerns?",
        "How did competitors position against us?",
        "What capability would have changed your decision?",
        "If we returned in 6 months, what would you need?",
      ],
    }),
  });
  const fg = await fgRes.json();
  for (const resp of fg.responses || []) {
    console.log(`\n--- ${resp.persona_name} ---`);
    for (const a of resp.answers || []) console.log(`  Q: ${a.question}\n  A: ${a.answer.slice(0, 400)}\n`);
  }
  ```
</CodeGroup>

## Example Output

```text theme={"dark"}
--- Lost: Too expensive ---
  Q: Why did you decide not to buy?
  A: Per-seat pricing didn't work for our 200-person team. We needed
     a volume discount or usage-based model. The competitor offered
     flat-rate enterprise pricing that made budgeting simpler.

--- Lost: Went with competitor ---
  Q: How did competitors position against us?
  A: They led with integration depth — their Salesforce connector was
     native, not API-based. They also offered a free pilot with
     dedicated onboarding. We never got past the PDF proposal stage.
```

## Error Handling

| Error                   | Cause                     | Fix                                                             |
| ----------------------- | ------------------------- | --------------------------------------------------------------- |
| `lost_reason` is `null` | No reason logged          | Map to "No reason given"; prompt sales ops to require reasons   |
| Too many clusters       | Freetext reasons          | Normalize reasons (lowercase, group synonyms) before clustering |
| Focus Group rate limit  | Too many concurrent calls | Queue with 2-3s delay between batches                           |
