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

# Contact Property → Focus Group Segmentation

> Extract HubSpot contact segments by custom properties, create Mavera personas per segment, and run a Focus Group

## Scenario

Your HubSpot contacts have custom properties — persona field, buying committee role, company size tier. Before launching a campaign, you want synthetic feedback from each segment: Will the messaging resonate with economic buyers differently than end users? You extract segments, map each to a Mavera persona, then run a Focus Group with segment-specific questions.

## Architecture

```mermaid theme={"dark"}
flowchart LR
    A[HubSpot Contact Search] --> B["Group by persona/role"] --> C["POST /personas"] --> D["POST /focus-groups"] --> E[Segment feedback]
```

## Code

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

  HS = os.environ["HUBSPOT_ACCESS_TOKEN"]
  MV = os.environ["MAVERA_API_KEY"]
  HB = "https://api.hubapi.com/crm/v3"
  MB = "https://app.mavera.io/api/v1"
  MH = {"Authorization": f"Bearer {MV}", "Content-Type": "application/json"}

  SEGMENTS = [
      {"prop": "hs_persona", "val": "persona_economic_buyer", "label": "Economic Buyer"},
      {"prop": "hs_persona", "val": "persona_end_user", "label": "End User"},
      {"prop": "hs_persona", "val": "persona_champion", "label": "Internal Champion"},
      {"prop": "hs_persona", "val": "persona_technical", "label": "Technical Evaluator"},
  ]

  # 1. Create personas from HubSpot segments
  persona_ids = []
  for seg in SEGMENTS:
      r = requests.post(f"{HB}/objects/contacts/search",
          headers={"Authorization": f"Bearer {HS}"},
          json={"filterGroups": [{"filters": [
              {"propertyName": seg["prop"], "operator": "EQ", "value": seg["val"]}
          ]}], "properties": ["jobtitle", "industry"], "limit": 30})
      if r.status_code == 429: time.sleep(1); continue
      r.raise_for_status()
      contacts = r.json().get("results", [])
      if not contacts: continue

      titles = list({c["properties"].get("jobtitle","") for c in contacts if c["properties"].get("jobtitle")})[:5]
      p = requests.post(f"{MB}/personas", headers=MH, json={
          "name": f"HubSpot: {seg['label']}",
          "description": f"{seg['label']} segment. Titles: {', '.join(titles)}. N={len(contacts)}.",
          "demographic": {"job_titles": titles},
      }).json()
      persona_ids.append({"id": p["id"], "label": seg["label"]})
      time.sleep(0.3)

  # 2. Run Focus Group
  CAMPAIGN = '''We're launching an AI analytics platform that cuts reporting time by 60%.
  Early access: $499/mo for teams up to 50. "Stop building dashboards. Start making decisions."'''

  fg = requests.post(f"{MB}/focus-groups", headers=MH, json={
      "name": "Q3 Campaign Pre-Launch",
      "persona_ids": [p["id"] for p in persona_ids],
      "questions": [
          "How does this value proposition resonate with you?",
          "Is $499/mo reasonable for this type of tool?",
          "What objections would you raise to your team?",
          "How would you describe this to a colleague in one sentence?",
      ],
      "context": CAMPAIGN,
      "responses_per_persona": 3,
  }).json()

  # 3. Poll for results
  for _ in range(20):
      time.sleep(5)
      data = requests.get(f"{MB}/focus-groups/{fg['id']}", headers=MH).json()
      if data.get("status") == "completed": break

  for resp in data.get("responses", []):
      label = next((p["label"] for p in persona_ids if p["id"] == resp.get("persona_id")), "?")
      print(f"[{label}] {resp.get('question','')[:60]}")
      print(f"  → {resp.get('answer','')[:200]}\n")
  ```

  ```javascript JavaScript theme={"dark"}
  const HS = process.env.HUBSPOT_ACCESS_TOKEN;
  const MV = process.env.MAVERA_API_KEY;
  const HB = "https://api.hubapi.com/crm/v3";
  const MB = "https://app.mavera.io/api/v1";
  const MH = { Authorization: `Bearer ${MV}`, "Content-Type": "application/json" };

  const SEGMENTS = [
    { prop: "hs_persona", val: "persona_economic_buyer", label: "Economic Buyer" },
    { prop: "hs_persona", val: "persona_end_user", label: "End User" },
    { prop: "hs_persona", val: "persona_champion", label: "Internal Champion" },
    { prop: "hs_persona", val: "persona_technical", label: "Technical Evaluator" },
  ];

  // 1. Create personas
  const personaIds = [];
  for (const seg of SEGMENTS) {
    const res = await fetch(`${HB}/objects/contacts/search`, {
      method: "POST",
      headers: { Authorization: `Bearer ${HS}`, "Content-Type": "application/json" },
      body: JSON.stringify({
        filterGroups: [{ filters: [{ propertyName: seg.prop, operator: "EQ", value: seg.val }] }],
        properties: ["jobtitle", "industry"], limit: 30,
      }),
    });
    if (res.status === 429) { await new Promise(r => setTimeout(r, 1000)); continue; }
    const contacts = (await res.json()).results || [];
    if (!contacts.length) continue;

    const titles = [...new Set(contacts.map(c => c.properties.jobtitle).filter(Boolean))].slice(0, 5);
    const p = await fetch(`${MB}/personas`, { method: "POST", headers: MH,
      body: JSON.stringify({ name: `HubSpot: ${seg.label}`,
        description: `${seg.label} segment. Titles: ${titles.join(", ")}. N=${contacts.length}.`,
        demographic: { job_titles: titles } }),
    }).then(r => r.json());
    personaIds.push({ id: p.id, label: seg.label });
    await new Promise(r => setTimeout(r, 300));
  }

  // 2. Run Focus Group
  const fg = await fetch(`${MB}/focus-groups`, { method: "POST", headers: MH,
    body: JSON.stringify({
      name: "Q3 Campaign Pre-Launch",
      persona_ids: personaIds.map(p => p.id),
      questions: [
        "How does this value proposition resonate with you?",
        "Is $499/mo reasonable for this type of tool?",
        "What objections would you raise to your team?",
        "How would you describe this to a colleague in one sentence?",
      ],
      context: `We're launching an AI analytics platform that cuts reporting time by 60%. $499/mo for teams up to 50.`,
      responses_per_persona: 3,
    }),
  }).then(r => r.json());

  // 3. Poll
  let data;
  for (let i = 0; i < 20; i++) {
    await new Promise(r => setTimeout(r, 5000));
    data = await fetch(`${MB}/focus-groups/${fg.id}`, { headers: MH }).then(r => r.json());
    if (data.status === "completed") break;
  }

  for (const resp of data.responses || []) {
    const label = personaIds.find(p => p.id === resp.persona_id)?.label || "?";
    console.log(`[${label}] ${(resp.question || "").slice(0, 60)}`);
    console.log(`  → ${(resp.answer || "").slice(0, 200)}\n`);
  }
  ```
</CodeGroup>

## Example Output

```text theme={"dark"}
[Economic Buyer] Is $499/mo reasonable?
  → Under $10/user/month — competitive. I'd want an ROI calculator first.

[End User] How does this resonate?
  → "Stop building dashboards" hits home. 3 hours/week on reports nobody reads.

[Technical Evaluator] What objections?
  → Data security and integration depth. SOC 2 non-negotiable.
```

## Error Handling

<AccordionGroup>
  <Accordion title="Custom property not found">If `hs_persona` doesn't exist, Search returns 400. List properties with `GET /crm/v3/properties/contacts`.</Accordion>
  <Accordion title="Focus Group polling timeout">Large groups (4+ personas × 4 questions) may take 60–90s. The loop allows \~100s. Increase attempts for larger configs.</Accordion>
</AccordionGroup>

***

<CardGroup cols={2}>
  <Card title="HubSpot Integration" icon="arrow-left" href="/integrations/hubspot" />

  <Card title="Focus Groups API" icon="users" href="/features/focus-groups" />
</CardGroup>
