Skip to main content

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.

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

Code

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")

Example Output

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

ErrorCauseFix
lost_reason is nullNo reason loggedMap to “No reason given”; prompt sales ops to require reasons
Too many clustersFreetext reasonsNormalize reasons (lowercase, group synonyms) before clustering
Focus Group rate limitToo many concurrent callsQueue with 2-3s delay between batches