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

# Activity-Based Persona Scoring

> Map Pipedrive activity patterns (calls, emails, meetings) to buyer personas and discover how many touchpoints each type needs before a demo

## Scenario

Pipedrive tracks every touchpoint — calls, emails, meetings. You want to **map activity patterns to buyer personas** and discover how many touchpoints each persona type needs before they're ready for a demo.

## Architecture

```mermaid theme={"dark"}
flowchart LR
    A["Pipedrive Activities (call, email, meeting)"] --> B[Group by person] --> C[Classify archetypes] --> D["POST /api/v1/focus-groups"] --> E[Touchpoint insights]
```

## 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 activities grouped by person
  person_acts = defaultdict(lambda: defaultdict(int))
  for act_type in ["call", "email", "meeting"]:
      for act in (pd_get("/api/v2/activities", {"type": act_type, "limit": 200, "done": 1}).get("data", []) or []):
          if act.get("person_id"):
              person_acts[act["person_id"]][act_type] += 1

  # 2. Classify into persona archetypes
  def classify(counts):
      c, e, m = counts.get("call", 0), counts.get("email", 0), counts.get("meeting", 0)
      if m >= 3 and c >= 5: return "Relationship Buyer (exec, high-touch)"
      if e >= 10 and c <= 2: return "Self-Serve Researcher (dev/IC, async-first)"
      if c >= 5 and e >= 5: return "Engaged Evaluator (mid-level, multi-channel)"
      return "Low-Touch Prospect (early stage)"

  groups = defaultdict(list)
  for pid, counts in person_acts.items():
      groups[classify(counts)].append({"person_id": pid, **counts})

  # 3. Build and run Focus Group
  personas = []
  for archetype, members in groups.items():
      personas.append({
          "name": archetype.split("(")[0].strip(),
          "description": (
              f"{archetype}. {len(members)} contacts. "
              f"Avg calls: {sum(m.get('call',0) for m in members)//max(len(members),1)}, "
              f"Avg emails: {sum(m.get('email',0) for m in members)//max(len(members),1)}."
          ),
      })

  fg_resp = requests.post(
      "https://app.mavera.io/api/v1/focus-groups",
      headers={"Authorization": f"Bearer {MAVERA_KEY}"},
      json={
          "title": "Pipedrive Activity-Based Persona Scoring",
          "personas": personas,
          "questions": [
              "How many touchpoints (calls, emails, meetings) before considering a demo?",
              "What outreach feels helpful vs. intrusive at each stage?",
              "At what point does follow-up become too aggressive?",
          ],
      },
  )
  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'][:300]}")
  ```

  ```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 activities grouped by person
  const personActs = {};
  for (const actType of ["call", "email", "meeting"]) {
    const resp = await pdGet("/api/v2/activities", { type: actType, limit: 200, done: 1 });
    for (const act of resp.data || []) {
      if (!act.person_id) continue;
      personActs[act.person_id] ||= { call: 0, email: 0, meeting: 0 };
      personActs[act.person_id][actType]++;
    }
  }

  // 2. Classify personas
  function classify({ call = 0, email = 0, meeting = 0 }) {
    if (meeting >= 3 && call >= 5) return "Relationship Buyer (exec, high-touch)";
    if (email >= 10 && call <= 2) return "Self-Serve Researcher (dev/IC, async-first)";
    if (call >= 5 && email >= 5) return "Engaged Evaluator (mid-level, multi-channel)";
    return "Low-Touch Prospect (early stage)";
  }

  const groups = {};
  for (const [pid, counts] of Object.entries(personActs)) {
    const arch = classify(counts);
    (groups[arch] ||= []).push({ person_id: pid, ...counts });
  }

  // 3. Run Focus Group
  const personas = Object.entries(groups).map(([arch, members]) => ({
    name: arch.split("(")[0].trim(),
    description: `${arch}. ${members.length} contacts. Avg calls: ${Math.round(
      members.reduce((s, m) => s + m.call, 0) / members.length)}.`,
  }));

  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 Activity-Based Persona Scoring",
      personas,
      questions: [
        "How many touchpoints before considering a demo?",
        "What outreach feels helpful vs. intrusive?",
        "When does follow-up become too aggressive?",
      ],
    }),
  });
  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, 300)}`);
  }
  ```
</CodeGroup>

## Example Output

```text theme={"dark"}
[Relationship Buyer]
  Q: How many touchpoints before considering a demo?
  A: I'd want 2-3 meaningful conversations — a call where you understand
     my business, a follow-up with a relevant case study, and a brief
     meeting with my team. 5-6 total touchpoints over 2-3 weeks.

[Self-Serve Researcher]
  Q: How many touchpoints before considering a demo?
  A: Just send me docs and a sandbox. I don't want calls. Maybe 1-2 emails
     with technical content, then I'll reach out when ready.
```

## Error Handling

| Error               | Cause                        | Fix                                                     |
| ------------------- | ---------------------------- | ------------------------------------------------------- |
| `400 Bad Request`   | Invalid activity type filter | Verify type values match Pipedrive's activity type keys |
| Empty `person_id`   | Unlinked activities          | Skip unlinked activities                                |
| Focus Group timeout | Too many personas            | Limit to 5-8 personas per Focus Group                   |
