> ## 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.

# Deal-Stage Focus Group

> Win/loss analysis via synthetic focus groups — query Opportunities by stage, extract Contact Roles, and run on-demand deal-stage analysis

## Scenario

Win/loss analysis usually happens after deals close — too late to course-correct. This job queries Opportunities at each stage (Negotiation, Closed Won, Closed Lost), extracts Contact Roles and notes, then runs a synthetic focus group with personas mapped to each stage. You get on-demand win/loss analysis instead of waiting for the quarterly retrospective.

## Architecture

```mermaid theme={"dark"}
flowchart LR
    A["Salesforce Opportunities (by Stage)"] --> B[Contact Roles] --> C["POST /api/v1/personas (per stage)"] --> D["POST /api/v1/focus-groups"] --> E["Win/Loss Report"]
```

## Code

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

  SF   = os.environ["SALESFORCE_INSTANCE"]
  SF_T = os.environ["SALESFORCE_ACCESS_TOKEN"]
  MV_K = os.environ["MAVERA_API_KEY"]
  SF_HEADERS = {"Authorization": f"Bearer {SF_T}"}
  MV_HEADERS = {"Authorization": f"Bearer {MV_K}", "Content-Type": "application/json"}

  STAGES = ["Negotiation", "Closed Won", "Closed Lost"]
  persona_ids = []

  for stage in STAGES:
      soql = (
          f"SELECT Id, Name, Amount, "
          f"(SELECT Contact.Name, Contact.Title, Role FROM OpportunityContactRoles) "
          f"FROM Opportunity WHERE StageName = '{stage}' LIMIT 20"
      )
      opps = requests.get(
          f"https://{SF}/services/data/v66.0/query",
          headers=SF_HEADERS, params={"q": soql},
      ).json()["records"]

      titles = []
      for opp in opps:
          roles = opp.get("OpportunityContactRoles", {})
          if roles and roles.get("records"):
              titles.extend(r["Contact"]["Title"] or "Stakeholder" for r in roles["records"])
      top_title = max(set(titles), key=titles.count) if titles else "Decision Maker"

      pr = requests.post(
          "https://app.mavera.io/api/v1/personas", headers=MV_HEADERS,
          json={
              "name": f"{stage} Buyer — {top_title}",
              "description": f"Buyers in '{stage}' stage. Common role: {top_title}. Based on {len(opps)} opps.",
          },
      )
      pr.raise_for_status()
      persona_ids.append(pr.json()["id"])

  fg = requests.post(
      "https://app.mavera.io/api/v1/focus-groups", headers=MV_HEADERS,
      json={
          "persona_ids": persona_ids,
          "questions": [
              {"type": "nps", "text": "How likely are you to recommend our product to a peer?"},
              {"type": "open_ended", "text": "What nearly stopped you from buying?"},
              {"type": "open_ended", "text": "What was the single biggest factor in your decision?"},
              {"type": "open_ended", "text": "If you could change one thing about our sales process, what would it be?"},
          ],
      },
  ).json()

  print(f"Focus Group ID: {fg['id']}")
  for a in fg.get("responses", []):
      print(f"  [{a['persona_name']}] {a['question']}: {a['response']}")
  ```

  ```javascript JavaScript theme={"dark"}
  const SF   = process.env.SALESFORCE_INSTANCE;
  const SF_T = process.env.SALESFORCE_ACCESS_TOKEN;
  const MV_K = process.env.MAVERA_API_KEY;
  const mvH = { Authorization: `Bearer ${MV_K}`, "Content-Type": "application/json" };

  const STAGES = ["Negotiation", "Closed Won", "Closed Lost"];
  const personaIds = [];

  for (const stage of STAGES) {
    const soql = encodeURIComponent(
      `SELECT Id, Name, Amount, ` +
      `(SELECT Contact.Name, Contact.Title, Role FROM OpportunityContactRoles) ` +
      `FROM Opportunity WHERE StageName = '${stage}' LIMIT 20`
    );
    const { records: opps } = await fetch(
      `https://${SF}/services/data/v66.0/query?q=${soql}`,
      { headers: { Authorization: `Bearer ${SF_T}` } }
    ).then((r) => r.json());

    const titles = opps.flatMap((o) =>
      (o.OpportunityContactRoles?.records || []).map((r) => r.Contact?.Title || "Stakeholder")
    );
    const topTitle = [...new Set(titles)].sort(
      (a, b) => titles.filter((t) => t === b).length - titles.filter((t) => t === a).length
    )[0] || "Decision Maker";

    const p = await fetch("https://app.mavera.io/api/v1/personas", {
      method: "POST", headers: mvH,
      body: JSON.stringify({
        name: `${stage} Buyer — ${topTitle}`,
        description: `Buyers in '${stage}' stage. Common role: ${topTitle}. Based on ${opps.length} opps.`,
      }),
    }).then((r) => r.json());
    personaIds.push(p.id);
  }

  const fg = await fetch("https://app.mavera.io/api/v1/focus-groups", {
    method: "POST", headers: mvH,
    body: JSON.stringify({
      persona_ids: personaIds,
      questions: [
        { type: "nps", text: "How likely are you to recommend our product to a peer?" },
        { type: "open_ended", text: "What nearly stopped you from buying?" },
        { type: "open_ended", text: "What was the single biggest factor in your decision?" },
        { type: "open_ended", text: "If you could change one thing about our sales process, what would it be?" },
      ],
    }),
  }).then((r) => r.json());

  console.log(`Focus Group ID: ${fg.id}`);
  (fg.responses || []).forEach((a) => console.log(`  [${a.persona_name}] ${a.question}: ${a.response}`));
  ```
</CodeGroup>

## Example Output

```json theme={"dark"}
{
  "id": "fg_4kN8x",
  "responses": [
    {
      "persona_name": "Closed Lost Buyer — VP Engineering",
      "question": "What nearly stopped you from buying?",
      "response": "Your pricing model penalizes teams that scale. We hit 50 seats and the per-seat cost made no sense compared to a platform license."
    },
    {
      "persona_name": "Closed Won Buyer — Director of Product",
      "question": "What was the single biggest factor in your decision?",
      "response": "The POC was seamless — your SE built an integration in our sandbox within a day. Competitors needed two weeks."
    },
    {
      "persona_name": "Negotiation Buyer — CTO",
      "question": "How likely are you to recommend our product to a peer?",
      "response": "7 — I'd recommend it once I see the first quarterly ROI. Right now I believe the promise but need proof."
    }
  ]
}
```

<Tip>
  Run this monthly to track sentiment drift across stages. Compare NPS scores over time to detect if your sales experience is improving or degrading.
</Tip>

***

<CardGroup cols={2}>
  <Card title="Salesforce Overview" icon="salesforce" href="/integrations/salesforce">
    Back to all 8 Salesforce jobs
  </Card>

  <Card title="Account Intelligence Brief" icon="brain" href="/integrations/salesforce/account-intelligence-brief">
    Next: AI research briefs from Account data
  </Card>
</CardGroup>
