The Scenario
You’re launching a new product and need buy-in from an entire buying committee — CEO, CFO, CMO, VP Engineering, IT Director, Legal, Procurement, End User, Champion, and Detractor. Traditionally this means weeks of scheduling, travel budgets, and NDAs. With Mavera you create all ten personas, run one Focus Group, and have structured committee feedback in minutes.Mavera-only workflow. No external API, no CRM integration, no calendar links. Just Mavera’s Personas and Focus Groups surfaces.
When to Use This
- Pre-launch concept testing when you need cross-functional perspective.
- Board presentations where you want simulated committee data behind your positioning.
- Enterprise sales enablement — train reps on objections from every seat at the table.
- Competitive repositioning when you need to pressure-test a pivot across roles.
Architecture
| Mavera Surface | Role in Pipeline |
|---|---|
Personas (POST /personas) | Create 10 distinct buying-committee members with role-specific priorities |
Focus Groups (POST /focus-groups) | Run all 10 personas through the same product concept questions |
What You Need
| Requirement | Details |
|---|---|
| Mavera API key | Starts with mvra_live_. Get one at Developer Settings. |
| Python 3.8+ or Node.js 18+ | requests for Python; native fetch for Node. |
| Credits | ~150–300 total. See Credits Estimate. |
MAVERA_API_KEY=mvra_live_your_key_here
Step 1 — Define and Create the Buying Committee
Each persona gets a distinct role, seniority, and decision-making priority.import os, time, json, requests
API_KEY = os.environ["MAVERA_API_KEY"]
BASE = "https://app.mavera.io/api/v1"
HEADERS = {"Authorization": f"Bearer {API_KEY}", "Content-Type": "application/json"}
COMMITTEE = [
{"name": "Sarah Chen — CEO", "role": "Chief Executive Officer",
"description": "Strategic decision-maker focused on market positioning and ROI narratives for the board.",
"traits": ["big-picture thinker", "risk-aware", "time-constrained"]},
{"name": "Marcus Williams — CFO", "role": "Chief Financial Officer",
"description": "Owns budget approval. Focused on TCO, payback period, and financial risk. Needs hard numbers.",
"traits": ["analytical", "cost-conscious", "ROI-driven"]},
{"name": "Priya Patel — CMO", "role": "Chief Marketing Officer",
"description": "Evaluates products on differentiation potential, speed to market, and brand alignment.",
"traits": ["creative", "data-informed", "brand-protective"]},
{"name": "David Kim — VP Engineering", "role": "VP of Engineering",
"description": "Technical evaluator concerned with API quality, security posture, and integration complexity.",
"traits": ["detail-oriented", "security-conscious", "integration-focused"]},
{"name": "Rachel Torres — IT Director", "role": "IT Director",
"description": "Manages infrastructure and compliance. Evaluates SSO, data residency, and SLA guarantees.",
"traits": ["process-driven", "compliance-focused", "vendor-skeptical"]},
{"name": "James O'Brien — General Counsel", "role": "General Counsel",
"description": "Reviews contracts, data processing agreements, and liability exposure.",
"traits": ["cautious", "regulation-aware", "contract-focused"]},
{"name": "Linda Zhao — Procurement Lead", "role": "Head of Procurement",
"description": "Negotiates pricing, evaluates vendor stability, compares against existing contracts.",
"traits": ["negotiation-oriented", "benchmark-driven", "process-rigid"]},
{"name": "Alex Rivera — End User", "role": "Marketing Manager",
"description": "Day-to-day user. Evaluates UX, learning curve, and daily workflow impact.",
"traits": ["practical", "time-pressed", "UX-sensitive"]},
{"name": "Nina Sorensen — Internal Champion", "role": "Product Marketing Lead",
"description": "Ran a pilot and advocates internally. Biased positive but needs ammunition for skeptics.",
"traits": ["enthusiastic", "evidence-seeking", "politically aware"]},
{"name": "Tom Bradley — Internal Detractor", "role": "Senior Director of Operations",
"description": "Prefers the incumbent. Worried about switching costs and team retraining.",
"traits": ["resistant to change", "process-protective", "risk-averse"]},
]
def create_persona(member):
resp = requests.post(f"{BASE}/personas", headers=HEADERS, json={
"name": member["name"], "role": member["role"],
"description": member["description"], "traits": member["traits"],
})
resp.raise_for_status()
data = resp.json()
print(f" Created: {data['name']} → {data['id']}")
return data["id"]
print("Creating buying committee personas...")
persona_ids = [create_persona(m) for m in COMMITTEE]
print(f"\n{len(persona_ids)} personas ready.")
const API_KEY = process.env.MAVERA_API_KEY;
const BASE = "https://app.mavera.io/api/v1";
const HEADERS = { Authorization: `Bearer ${API_KEY}`, "Content-Type": "application/json" };
const COMMITTEE = [
{ name: "Sarah Chen — CEO", role: "Chief Executive Officer",
description: "Strategic decision-maker focused on market positioning and ROI narratives for the board.",
traits: ["big-picture thinker", "risk-aware", "time-constrained"] },
{ name: "Marcus Williams — CFO", role: "Chief Financial Officer",
description: "Owns budget approval. Focused on TCO, payback period, and financial risk. Needs hard numbers.",
traits: ["analytical", "cost-conscious", "ROI-driven"] },
{ name: "Priya Patel — CMO", role: "Chief Marketing Officer",
description: "Evaluates products on differentiation potential, speed to market, and brand alignment.",
traits: ["creative", "data-informed", "brand-protective"] },
{ name: "David Kim — VP Engineering", role: "VP of Engineering",
description: "Technical evaluator concerned with API quality, security posture, and integration complexity.",
traits: ["detail-oriented", "security-conscious", "integration-focused"] },
{ name: "Rachel Torres — IT Director", role: "IT Director",
description: "Manages infrastructure and compliance. Evaluates SSO, data residency, and SLA guarantees.",
traits: ["process-driven", "compliance-focused", "vendor-skeptical"] },
{ name: "James O'Brien — General Counsel", role: "General Counsel",
description: "Reviews contracts, data processing agreements, and liability exposure.",
traits: ["cautious", "regulation-aware", "contract-focused"] },
{ name: "Linda Zhao — Procurement Lead", role: "Head of Procurement",
description: "Negotiates pricing, evaluates vendor stability, compares against existing contracts.",
traits: ["negotiation-oriented", "benchmark-driven", "process-rigid"] },
{ name: "Alex Rivera — End User", role: "Marketing Manager",
description: "Day-to-day user. Evaluates UX, learning curve, and daily workflow impact.",
traits: ["practical", "time-pressed", "UX-sensitive"] },
{ name: "Nina Sorensen — Internal Champion", role: "Product Marketing Lead",
description: "Ran a pilot and advocates internally. Biased positive but needs ammunition for skeptics.",
traits: ["enthusiastic", "evidence-seeking", "politically aware"] },
{ name: "Tom Bradley — Internal Detractor", role: "Senior Director of Operations",
description: "Prefers the incumbent. Worried about switching costs and team retraining.",
traits: ["resistant to change", "process-protective", "risk-averse"] },
];
async function createPersona(member) {
const resp = await fetch(`${BASE}/personas`, {
method: "POST", headers: HEADERS,
body: JSON.stringify({ name: member.name, role: member.role,
description: member.description, traits: member.traits }),
});
const data = await resp.json();
if (data.error) throw new Error(data.error.message);
console.log(` Created: ${data.name} → ${data.id}`);
return data.id;
}
console.log("Creating buying committee personas...");
const personaIds = [];
for (const m of COMMITTEE) personaIds.push(await createPersona(m));
console.log(`\n${personaIds.length} personas ready.`);
Persona creation is idempotent by name. If you’ve already created these personas, fetch them with
GET /personas and reuse the IDs.Step 2 — Run the Focus Group
Create a Focus Group with all 10 persona IDs. Questions cover concept reaction, purchase likelihood, objections, ownership, approval criteria, and pricing perception.PRODUCT_CONCEPT = """
We're launching an AI-powered audience research platform that replaces traditional
focus groups with synthetic personas. Marketers can test messaging, positioning,
and creative in minutes instead of weeks. Pricing starts at $500/month.
"""
def run_panel_focus_group(pids):
payload = {
"name": "Buying Committee — Product Concept Review",
"persona_ids": pids, "sample_size": len(pids),
"questions": [
{"question": f"Share your initial reaction from your role's perspective:\n\n{PRODUCT_CONCEPT}",
"type": "OPEN_ENDED", "order": 1},
{"question": "How likely is your organization to purchase this? (0-10)", "type": "NPS", "order": 2},
{"question": "What is the single biggest objection you'd raise in a buying meeting?",
"type": "OPEN_ENDED", "order": 3},
{"question": "Which department should own this tool?", "type": "MULTIPLE_CHOICE",
"options": ["Marketing", "Product", "Research/Insights", "Engineering", "Shared/Cross-functional"], "order": 4},
{"question": "What would need to be true for you to approve this purchase?", "type": "OPEN_ENDED", "order": 5},
{"question": "Rate the pricing ($500/mo) relative to value.", "type": "MULTIPLE_CHOICE",
"options": ["Strong value", "Fair price", "Slightly expensive — need ROI first", "Too expensive"], "order": 6},
],
}
resp = requests.post(f"{BASE}/focus-groups", headers=HEADERS, json=payload)
resp.raise_for_status()
return resp.json()
def poll_focus_group(fg_id, timeout_min=10):
for i in range(timeout_min * 6):
resp = requests.get(f"{BASE}/focus-groups/{fg_id}", headers=HEADERS).json()
if "error" in resp: raise Exception(resp["error"]["message"])
if resp["status"] == "COMPLETED": return resp
time.sleep(10)
raise TimeoutError(f"Focus Group {fg_id} timed out")
fg = run_panel_focus_group(persona_ids)
print(f"Focus Group created: {fg['id']}")
results = poll_focus_group(fg["id"])
const PRODUCT_CONCEPT = `We're launching an AI-powered audience research platform that replaces traditional focus groups with synthetic personas. Pricing starts at $500/month.`;
async function runPanelFocusGroup(pids) {
const resp = await fetch(`${BASE}/focus-groups`, {
method: "POST", headers: HEADERS,
body: JSON.stringify({
name: "Buying Committee — Product Concept Review",
persona_ids: pids, sample_size: pids.length,
questions: [
{ question: `Share your initial reaction:\n\n${PRODUCT_CONCEPT}`, type: "OPEN_ENDED", order: 1 },
{ question: "How likely is your org to purchase? (0-10)", type: "NPS", order: 2 },
{ question: "Biggest objection you'd raise in a buying meeting?", type: "OPEN_ENDED", order: 3 },
{ question: "Which department should own this?", type: "MULTIPLE_CHOICE",
options: ["Marketing", "Product", "Research/Insights", "Engineering", "Shared/Cross-functional"], order: 4 },
{ question: "What would need to be true for you to approve?", type: "OPEN_ENDED", order: 5 },
{ question: "Rate the pricing ($500/mo) relative to value.", type: "MULTIPLE_CHOICE",
options: ["Strong value", "Fair price", "Slightly expensive — need ROI first", "Too expensive"], order: 6 },
],
}),
});
const data = await resp.json();
if (data.error) throw new Error(data.error.message);
return data;
}
async function pollFocusGroup(fgId, timeoutMin = 10) {
for (let i = 0; i < timeoutMin * 6; i++) {
const resp = await fetch(`${BASE}/focus-groups/${fgId}`, { headers: HEADERS }).then((r) => r.json());
if (resp.error) throw new Error(resp.error.message);
if (resp.status === "COMPLETED") return resp;
await new Promise((r) => setTimeout(r, 10000));
}
throw new Error(`Focus Group ${fgId} timed out`);
}
const fg = await runPanelFocusGroup(personaIds);
const results = await pollFocusGroup(fg.id);
Step 3 — Parse and Display the Committee Report
def print_committee_report(fg_results):
print("\n" + "=" * 70)
print("BUYING COMMITTEE FEEDBACK REPORT")
print("=" * 70)
for qr in fg_results.get("results", []):
print(f"\n{'─' * 60}\nQ: {qr['question'][:80]}\n{'─' * 60}")
if qr["type"] == "NPS":
print(f" NPS Score: {qr.get('nps_score')}")
for r in qr.get("responses", []):
print(f" {r.get('persona_name', ''):40s} → {r.get('value', 'N/A')}")
elif qr["type"] == "MULTIPLE_CHOICE":
for opt, cnt in sorted(qr.get("option_counts", {}).items(), key=lambda x: -x[1]):
print(f" {opt:40s} {'█' * cnt} ({cnt})")
elif qr["type"] == "OPEN_ENDED":
print(f" Summary: {qr.get('summary', 'N/A')}")
for r in qr.get("responses", [])[:3]:
print(f" [{r.get('persona_name', '')}] {r.get('value', '')[:120]}")
print_committee_report(results)
with open("committee_feedback.json", "w") as f:
json.dump(results, f, indent=2)
function printCommitteeReport(fgResults) {
console.log("\n" + "=".repeat(70));
console.log("BUYING COMMITTEE FEEDBACK REPORT");
console.log("=".repeat(70));
for (const qr of fgResults.results || []) {
console.log(`\n${"─".repeat(60)}\nQ: ${(qr.question || "").slice(0, 80)}\n${"─".repeat(60)}`);
if (qr.type === "NPS") {
console.log(` NPS Score: ${qr.nps_score}`);
for (const r of qr.responses || [])
console.log(` ${(r.persona_name || "").padEnd(40)} → ${r.value}`);
} else if (qr.type === "MULTIPLE_CHOICE") {
for (const [opt, cnt] of Object.entries(qr.option_counts || {}).sort((a, b) => b[1] - a[1]))
console.log(` ${opt.padEnd(40)} ${"█".repeat(cnt)} (${cnt})`);
} else {
console.log(` Summary: ${qr.summary || "N/A"}`);
for (const r of (qr.responses || []).slice(0, 3))
console.log(` [${r.persona_name}] ${(r.value || "").slice(0, 120)}`);
}
}
}
printCommitteeReport(results);
const fs = require("fs");
fs.writeFileSync("committee_feedback.json", JSON.stringify(results, null, 2));
Example Output
NPS by Role:
Sarah Chen — CEO → 8
Marcus Williams — CFO → 5
Priya Patel — CMO → 9
David Kim — VP Engineering → 7
Rachel Torres — IT Director → 6
James O'Brien — General Counsel → 4
Linda Zhao — Procurement Lead → 5
Alex Rivera — End User → 8
Nina Sorensen — Internal Champion → 10
Tom Bradley — Internal Detractor → 3
Department Ownership:
Marketing ████ (4)
Research/Insights ███ (3)
Shared/Cross-functional ██ (2)
Product █ (1)
Pricing Perception:
Fair price ███ (3)
Slightly expensive — need ROI first ████ (4)
Strong value █ (1)
Too expensive ██ (2)
Variations
Add industry context to each persona
Add industry context to each persona
for m in COMMITTEE:
m["description"] += " Works in B2B SaaS, 500 employees, $50M ARR."
Run separate Focus Groups per functional area
Run separate Focus Groups per functional area
groups = {"Executive": persona_ids[:3], "Technical": persona_ids[3:5],
"Gatekeepers": persona_ids[5:7], "Users": persona_ids[7:]}
for label, ids in groups.items():
fg = run_panel_focus_group(ids)
print_committee_report(poll_focus_group(fg["id"]))
Test multiple product concepts
Test multiple product concepts
Run the same committee through two concepts and compare NPS:
for i, concept in enumerate([CONCEPT_A, CONCEPT_B]):
PRODUCT_CONCEPT = concept
fg = run_panel_focus_group(persona_ids)
result = poll_focus_group(fg["id"])
print(f"\n=== Concept {i + 1} ===")
print_committee_report(result)
Follow-up Focus Group for objection handling
Follow-up Focus Group for objection handling
followup = [
{"question": "If we offered a 90-day pilot with guaranteed ROI metrics, would that address your concerns?",
"type": "MULTIPLE_CHOICE", "options": ["Yes", "Partially", "No"], "order": 1},
{"question": "What metric would justify the investment?", "type": "OPEN_ENDED", "order": 2},
]
Export to CSV
Export to CSV
import csv
with open("committee.csv", "w", newline="") as f:
w = csv.writer(f)
w.writerow(["Persona", "Question", "Response"])
for qr in results.get("results", []):
for r in qr.get("responses", []):
w.writerow([r.get("persona_name"), qr["question"][:80], r.get("value", "")])
Credits Estimate
| Operation | Typical Cost | Notes |
|---|---|---|
| Persona creation (×10) | 0–50 | One-time; reuse across runs |
| Focus Group (10 personas, 6 questions) | 150–250 | Primary cost driver |
| Total | ~150–300 |
Personas persist across sessions. Create them once and reuse the IDs — you only pay the creation cost once.
What’s Next
Generational Content Testing
Test the same concept across Gen Z, Millennial, Gen X, and Boomer personas
Message Testing Matrix
5 messages × 5 personas for optimal message-persona fit
Persona Debate
Pit opposing buyer types against each other for pricing insights
Persona Selection Guide
Choose the right persona types for your research goal
Focus Groups Reference
All question types, sample sizes, and configuration options
Credits & Budget
Pre-flight checks and usage tracking