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.

The Scenario

Pricing is one of the hardest go-to-market decisions. Ask a budget buyer and they’ll say it’s too expensive. Ask a premium buyer and they’ll say it’s reasonable. The truth lives in the tension between them. This playbook creates two opposing personas and runs them through the same Focus Group evaluating your product at multiple price points. The output is a structured price-sensitivity analysis from opposing perspectives.
Mavera-only workflow. No conjoint analysis software, no survey panels, no incentive budgets. Just Mavera’s Personas, Focus Groups, and Chat surfaces.

When to Use This

  • Pre-launch pricing decisions — find the range that maximizes both WTP and adoption.
  • Tier structure design — which features justify premium vs standard pricing?
  • Price increase planning — simulate reactions from loyal customers and price-sensitive prospects.
  • Competitive pricing — test your price against a competitor’s with opposing buyer mindsets.
  • Freemium vs paid debates — let opposing personas argue for and against free tiers.

Architecture

Mavera SurfaceRole in Pipeline
Personas (POST /personas)Create opposing buyer archetypes
Focus Groups (POST /focus-groups)Both personas evaluate the product at 4 price points
Chat (OpenAI-compatible)Synthesize opposing viewpoints into a recommendation

What You Need

RequirementDetails
Mavera API keyStarts with mvra_live_. Get one at Developer Settings.
Python 3.8+ or Node.js 18+requests for Python; native fetch for Node.
Credits~85–205 total. See Credits Estimate.
MAVERA_API_KEY=mvra_live_your_key_here

Step 1 — Create Opposing Personas

The key is making these genuinely opposed — not just different price preferences, but different value frameworks.
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"}

OPPOSING = [
    {"name": "Dana — Budget-Conscious Buyer",
     "role": "Operations Manager at a bootstrapped 30-person startup",
     "description": (
         "Every purchase goes through a personal ROI calculator. Uses free tiers and open-source "
         "before paying. Negotiates every contract. Measures value in dollars saved per hour. "
         "Trusts usage-based pricing over flat fees. Will cancel the moment usage drops below cost."),
     "traits": ["price-sensitive", "ROI-calculator mentality", "free-tier-first",
                "negotiation-driven", "churn-prone if value drops"]},
    {"name": "Victoria — Premium Buyer",
     "role": "VP of Marketing at a Series C company ($30M raised)",
     "description": (
         "Pays significantly more for reliability, support, and time savings. Believes 'you get what you pay for.' "
         "Values white-glove onboarding, dedicated support, and SLAs. Sees price as a quality signal — "
         "if it's too cheap, something must be wrong. Happy to sign annual contracts."),
     "traits": ["quality-over-cost", "time-is-money mentality", "enterprise-expectation",
                "annual-contract-comfortable", "brand-as-signal buyer"]},
]

def create_persona(p):
    resp = requests.post(f"{BASE}/personas", headers=HEADERS, json={
        "name": p["name"], "role": p["role"], "description": p["description"], "traits": p["traits"]})
    resp.raise_for_status()
    data = resp.json()
    print(f"  Created: {data['name']}{data['id']}")
    return data["id"]

budget_id = create_persona(OPPOSING[0])
premium_id = create_persona(OPPOSING[1])

Step 2 — Define Product and Price Points

PRODUCT = {
    "name": "Mavera Pro",
    "description": "AI-powered audience research. Focus Groups (unlimited), Video Analysis (50/mo), "
                   "Brand Voice, Chat API, Generate, Speak, dedicated Slack support. 5 seats.",
    "features": ["Unlimited Focus Groups", "50 Video Analyses/mo", "Brand Voice extraction",
                 "Chat API", "Generate (all apps)", "Speak conversations", "Dedicated support", "5 seats"],
}

PRICES = [
    {"label": "Starter", "price": "$199/month", "annual": "$1,990/year"},
    {"label": "Growth", "price": "$499/month", "annual": "$4,990/year"},
    {"label": "Scale", "price": "$999/month", "annual": "$9,990/year"},
    {"label": "Enterprise", "price": "$2,499/month", "annual": "$24,990/year"},
]

Step 3 — Run the Debate Focus Group

Both personas participate in the same group. Questions surface the tension between their opposing value frameworks.
def build_debate_questions():
    product_block = f"**{PRODUCT['name']}**\n{PRODUCT['description']}\n\n" + "\n".join(f"- {f}" for f in PRODUCT["features"])
    price_block = "\n".join(f"- **{p['label']}**: {p['price']} (annual: {p['annual']})" for p in PRICES)
    return [
        {"question": f"Share your impression of value:\n\n{product_block}", "type": "OPEN_ENDED", "order": 1},
        {"question": f"Which tier would you choose?\n\n{price_block}", "type": "MULTIPLE_CHOICE",
         "options": [f"{p['label']} ({p['price']})" for p in PRICES] + ["None — would not purchase"], "order": 2},
        {"question": "At which price is this 'too expensive' — you'd look for alternatives?", "type": "MULTIPLE_CHOICE",
         "options": [f"{p['label']} ({p['price']})" for p in PRICES] + ["All acceptable"], "order": 3},
        {"question": "At which price is this 'too cheap' — you'd question quality?", "type": "MULTIPLE_CHOICE",
         "options": [f"{p['label']} ({p['price']})" for p in PRICES] + ["None too cheap"], "order": 4},
        {"question": "What features justify the Enterprise tier?", "type": "OPEN_ENDED", "order": 5},
        {"question": "What could be removed to make Starter a fair deal?", "type": "OPEN_ENDED", "order": 6},
        {"question": "If a competitor offered 40% less, would you switch? What prevents it?", "type": "OPEN_ENDED", "order": 7},
        {"question": "Rate overall value at Growth ($499/mo). (0-10)", "type": "NPS", "order": 8},
    ]

def poll_fg(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 = requests.post(f"{BASE}/focus-groups", headers=HEADERS, json={
    "name": "Persona Debate — Price Positioning",
    "persona_ids": [budget_id, premium_id], "sample_size": 10,
    "questions": build_debate_questions(),
}).json()
print(f"Debate Focus Group: {fg['id']}")
results = poll_fg(fg["id"])

Step 4 — Parse the Debate

Separate responses by persona type and display side by side.
def print_debate_report(fg_results):
    print("\n" + "=" * 70)
    print("PERSONA DEBATE — PRICING ANALYSIS")
    print("=" * 70)

    for qr in fg_results.get("results", []):
        print(f"\n{'─' * 60}\nQ: {qr['question'][:75]}\n{'─' * 60}")

        if qr["type"] == "MULTIPLE_CHOICE":
            for opt, cnt in sorted(qr.get("option_counts", {}).items(), key=lambda x: -x[1]):
                print(f"    {opt:45s} {'█' * cnt} ({cnt})")
            budget = [r for r in qr.get("responses", []) if "Budget" in r.get("persona_name", "")]
            premium = [r for r in qr.get("responses", []) if "Premium" in r.get("persona_name", "")]
            if budget:
                choices = [r.get("value", "") for r in budget]
                print(f"\n  Budget tendency: {max(set(choices), key=choices.count)}")
            if premium:
                choices = [r.get("value", "") for r in premium]
                print(f"  Premium tendency: {max(set(choices), key=choices.count)}")

        elif qr["type"] == "NPS":
            print(f"  Overall NPS: {qr.get('nps_score', 'N/A')}")
            for label, keyword in [("Budget", "Budget"), ("Premium", "Premium")]:
                scores = [int(r["value"]) for r in qr.get("responses", [])
                          if keyword in r.get("persona_name", "") and r.get("value") is not None]
                if scores:
                    print(f"  {label} avg: {sum(scores)/len(scores):.1f}/10")

        elif qr["type"] == "OPEN_ENDED":
            print(f"  Summary: {qr.get('summary', 'N/A')}")
            for keyword, label in [("Budget", "Budget"), ("Premium", "Premium")]:
                resps = [r for r in qr.get("responses", []) if keyword in r.get("persona_name", "")]
                if resps:
                    print(f"\n  {label} perspective:")
                    print(f"    \"{resps[0].get('value', '')[:140]}\"")

print_debate_report(results)

Step 5 — Generate Pricing Recommendation

from openai import OpenAI

mavera = OpenAI(api_key=API_KEY, base_url="https://app.mavera.io/api/v1")

def generate_recommendation(fg_results):
    summary = [{"question": qr["question"][:60], "type": qr["type"],
                "summary": qr.get("summary", ""),
                **({"nps": qr.get("nps_score")} if qr["type"] == "NPS" else {}),
                **({"counts": qr.get("option_counts")} if qr["type"] == "MULTIPLE_CHOICE" else {})}
               for qr in fg_results.get("results", [])]

    prices = ", ".join(f"{p['label']}={p['price']}" for p in PRICES)
    resp = mavera.responses.create(model="mavera-1", input=[{"role": "user", "content":
        f"Two opposing buyer personas evaluated this product at these prices: {prices}\n\n"
        f"Results:\n{json.dumps(summary, indent=2)}\n\n"
        "Produce: 1) Van Westendorp interpretation 2) Recommended price point "
        "3) Tier strategy (keep 4 or collapse?) 4) Feature allocation per tier "
        "5) Competitive moat 6) Risk assessment"}])
    return resp.output[0].content[0].text

rec = generate_recommendation(results)
print("\n=== PRICING RECOMMENDATION ===\n")
print(rec)
with open("pricing_debate_report.md", "w") as f:
    f.write(f"# Persona Debate — Pricing Analysis\n\n{rec}")

Example Output

Tier Selection:
  Starter ($199/month)                          ████ (4)
  Growth ($499/month)                           ███ (3)
  Scale ($999/month)                            ██ (2)
  None — would not purchase                     █ (1)

  Budget tendency: Starter ($199/month)
  Premium tendency: Scale ($999/month)

"Too Expensive" Threshold:
  Budget tendency: Scale ($999/month)
  Premium tendency: All acceptable

"Too Cheap" Threshold:
  Budget tendency: None too cheap
  Premium tendency: Starter ($199/month)

Value NPS at Growth ($499/mo):
  Overall NPS: 35
  Budget avg: 4.2/10
  Premium avg: 7.8/10

Variations

middle = {"name": "Sam — Pragmatic Evaluator", "role": "Director of Marketing, 150 people",
 "description": "Compares 3 vendors, picks best value/risk ratio. Reads G2 reviews. Wants a pilot.",
 "traits": ["comparison-shopper", "risk-balanced", "pilot-oriented"]}
middle_id = create_persona(middle)
# Add middle_id to persona_ids list
TIERS = {
    "Starter": {"features": ["Chat API", "5 Focus Groups/mo"], "price": "$199/mo"},
    "Growth": {"features": ["Chat", "Unlimited FGs", "Brand Voice"], "price": "$499/mo"},
    "Scale": {"features": ["Everything + Video + Speak"], "price": "$999/mo"},
}
After the first debate narrows the range, test smaller increments:
REFINED = [{"label": f"Tier {c}", "price": f"${p}/mo"} for c, p in
           zip("ABCD", [349, 449, 549, 649])]
mave = requests.post(f"{BASE}/mave/chat", headers=HEADERS, json={
    "message": "Research pricing of UserTesting, Wynter, Poll the People, Remesh. "
               "Compare models, tiers, and what's included."}).json()
print(mave.get("content", ""))
healthcare_budget = {"name": "Community Clinic Director",
 "description": "Tiny budget, grant-funded, high compliance needs..."}
healthcare_premium = {"name": "Hospital System CMO",
 "description": "$50M marketing budget, demands SLAs and HIPAA compliance..."}

Credits Estimate

OperationTypical CostNotes
Persona creation (×2)0–10One-time; reuse across runs
Focus Group (2 personas, 10 respondents, 8 questions)80–180Primary cost driver
Chat recommendation5–15Single synthesis call
Total~85–205
The debate format is highly efficient — opposing perspectives from a single Focus Group rather than two separate studies. Roughly half the cost of running each persona independently.

What’s Next

Industry Panel Simulation

Expand from 2 opposing personas to 10 buying-committee members

Message Testing Matrix

Test which messaging angle works best at each price point

Pricing Research

Full Van Westendorp analysis with persona segments

Generational Content Testing

How pricing perception varies across age demographics

Persona Selection Guide

Choose the right persona types for your research goal

Credits & Budget

Pre-flight checks and usage tracking