import os, requests, time
TF = os.environ["TYPEFORM_TOKEN"]
MV = os.environ["MAVERA_API_KEY"]
TF_BASE = "https://api.typeform.com"
MB = "https://app.mavera.io/api/v1"
TF_H = {"Authorization": f"Bearer {TF}"}
MV_H = {"Authorization": f"Bearer {MV}", "Content-Type": "application/json"}
FORM_ID = os.environ.get("NPS_FORM_ID", "your_nps_form_id")
# 1. Get form structure — find NPS field and comment field
form = requests.get(f"{TF_BASE}/forms/{FORM_ID}", headers=TF_H).json()
nps_field = None
comment_field = None
for f in form.get("fields", []):
if f.get("type") == "opinion_scale" or f.get("type") == "rating":
nps_field = f["id"]
elif f.get("type") in ("long_text", "short_text") and not comment_field:
comment_field = f["id"]
# 2. Pull responses
responses = []
params = {"page_size": 1000}
while True:
r = requests.get(f"{TF_BASE}/forms/{FORM_ID}/responses",
headers=TF_H, params=params)
if r.status_code == 429:
time.sleep(1); continue
r.raise_for_status()
data = r.json()
responses.extend(data.get("items", []))
if len(data.get("items", [])) < 1000: break
params["before"] = data["items"][-1]["token"]
time.sleep(0.6)
# 3. Split by NPS tier
tiers = {"promoter": [], "passive": [], "detractor": []}
for resp in responses:
score = None
comment = ""
for ans in resp.get("answers", []):
fid = ans.get("field", {}).get("id")
if fid == nps_field:
score = ans.get("number", ans.get("rating"))
elif fid == comment_field:
comment = ans.get("text", "")
if score is None:
continue
entry = {"score": score, "comment": comment}
if score >= 9:
tiers["promoter"].append(entry)
elif score >= 7:
tiers["passive"].append(entry)
else:
tiers["detractor"].append(entry)
for tier, entries in tiers.items():
avg = sum(e["score"] for e in entries) / max(len(entries), 1)
print(f"{tier.title()}: {len(entries)} responses (avg: {avg:.1f})")
# 4. Create persona per tier
TIER_PROFILES = {
"promoter": {
"desc": "NPS 9-10. Enthusiastic advocates. Want deeper engagement and referral programs.",
"mindset": "Loyal, engaged, willing to advocate",
},
"passive": {
"desc": "NPS 7-8. Satisfied but not enthusiastic. Could switch if competitor offers more.",
"mindset": "Content but uncommitted, comparing alternatives",
},
"detractor": {
"desc": "NPS 0-6. Frustrated or disappointed. At risk of churn and negative word-of-mouth.",
"mindset": "Frustrated, feeling unheard, considering alternatives",
},
}
MESSAGE_CANDIDATES = [
"We just launched our biggest update ever — 3 features your team has been asking for.",
"Your feedback shaped our roadmap. Here's what we built because of you.",
"We know we can do better. Here's our improvement plan for the next 90 days.",
"Unlock premium features at no extra cost — as a thank you for being with us.",
"Your peers are seeing 40% time savings. Let us help you get there too.",
]
persona_ids = {}
for tier, profile in TIER_PROFILES.items():
entries = tiers[tier]
comments = [e["comment"] for e in entries if e["comment"]][:10]
comment_summary = "; ".join(comments[:5]) if comments else "No comments"
p = requests.post(f"{MB}/personas", headers=MV_H, json={
"name": f"NPS {tier.title()}",
"description": (
f"{profile['desc']} Based on {len(entries)} responses. "
f"Sample feedback: {comment_summary[:300]}"
),
"psychographic": {"mindset": profile["mindset"], "nps_tier": tier},
})
p.raise_for_status()
persona_ids[tier] = p.json()["id"]
time.sleep(0.3)
# 5. Run Focus Group per tier
for tier, pid in persona_ids.items():
entries = tiers[tier]
comments = [e["comment"] for e in entries if e["comment"]][:5]
fg = requests.post(f"{MB}/focus-groups", headers=MV_H, json={
"name": f"NPS {tier.title()} — Message Testing",
"persona_ids": [pid],
"context": (
f"You are a {tier} (NPS {tiers[tier][0]['score'] if tiers[tier] else '?'}). "
f"Recent feedback from this tier: {'; '.join(comments[:3])}"
),
"questions": [
f"Read these 5 messages. Which one would most improve your experience?\n\n" +
"\n".join(f"{i+1}. {m}" for i, m in enumerate(MESSAGE_CANDIDATES)),
"What specifically about your chosen message resonates?",
"Which message would make things worse? Why?",
"Write the message YOU would want to receive right now.",
"What's the #1 thing that would change your NPS score?",
],
"responses_per_persona": 3,
}).json()
for _ in range(20):
time.sleep(5)
result = requests.get(f"{MB}/focus-groups/{fg['id']}",
headers=MV_H).json()
if result.get("status") == "completed":
break
print(f"\n{'='*50}")
print(f"NPS {tier.title()} Focus Group: {fg['id']}")
print(f"{'='*50}")
for resp in result.get("responses", []):
print(f"Q: {resp.get('question', '')[:60]}...")
print(f"A: {resp.get('answer', '')[:200]}\n")