import os, requests, time
from collections import defaultdict
KL_KEY = os.environ["KLAVIYO_API_KEY"]
MV = os.environ["MAVERA_API_KEY"]
MB = "https://app.mavera.io/api/v1"
MH = {"Authorization": f"Bearer {MV}", "Content-Type": "application/json"}
KH = {
"Authorization": f"Klaviyo-API-Key {KL_KEY}",
"Content-Type": "application/json",
"revision": "2024-10-15",
}
r = requests.get("https://a.klaviyo.com/api/catalog-items", headers=KH, params={
"fields[catalog-item]": "title,description,url,price",
"page[size]": 50,
})
products = []
if r.status_code == 200:
products = r.json().get("data", [])
if not products:
products = [
{"id": "prod_001", "attributes": {"title": "Running Shoes Pro", "price": 129, "description": "High-performance running shoes for daily training"}},
{"id": "prod_002", "attributes": {"title": "Performance Socks 3-Pack", "price": 24, "description": "Moisture-wicking athletic socks"}},
{"id": "prod_003", "attributes": {"title": "GPS Running Watch", "price": 299, "description": "Multi-sport GPS watch with heart rate monitoring"}},
{"id": "prod_004", "attributes": {"title": "Hydration Belt", "price": 35, "description": "Hands-free running hydration system"}},
{"id": "prod_005", "attributes": {"title": "Recovery Foam Roller", "price": 45, "description": "Deep-tissue massage foam roller"}},
{"id": "prod_006", "attributes": {"title": "Training Plan (Digital)", "price": 19, "description": "12-week progressive running program"}},
]
PRODUCT_PAIRS = [
{"bought": "Running Shoes Pro", "suggest": "Performance Socks 3-Pack", "logic": "Complementary — socks protect the shoe investment"},
{"bought": "GPS Running Watch", "suggest": "Training Plan (Digital)", "logic": "Watch + plan = structured training"},
{"bought": "Running Shoes Pro", "suggest": "Recovery Foam Roller", "logic": "Runners who invest in shoes care about recovery"},
{"bought": "Hydration Belt", "suggest": "GPS Running Watch", "logic": "Hydration belt = long runs = watch needed"},
]
personas = []
for name, desc in [
("Casual Runner", "Runs 2-3x per week for fitness. Buys basics, price-conscious. Doesn't consider themselves 'a runner' — it's just exercise."),
("Dedicated Runner", "Runs 4-5x per week, tracks every metric. Invests in gear. Training for a half marathon. Reads running blogs."),
("New Runner", "Started running 2 months ago. Bought first pair of real running shoes. Overwhelmed by options. Wants guidance."),
]:
p = requests.post(f"{MB}/personas", headers=MH, json={"name": name, "description": desc}).json()
personas.append(p)
time.sleep(0.3)
product_catalog = "\n".join(
f"- {p.get('attributes', p).get('title', 'Unknown')}: ${p.get('attributes', p).get('price', 0)} — {p.get('attributes', p).get('description', '')}"
for p in products
)
pair_questions = []
for pair in PRODUCT_PAIRS:
pair_questions.append(
f"You recently bought '{pair['bought']}'. On a scale of 1-5 (1=No interest, 5=Would buy immediately), "
f"how likely are you to buy '{pair['suggest']}'? "
f"Explain your rating — what would make you more or less likely?"
)
pair_questions.append(
"On a scale of 0-10, how likely are you to recommend our store to a friend? "
"What's the #1 thing we'd need to do to move your score up by 2 points?"
)
fg = requests.post(f"{MB}/focus-groups", headers=MH, json={
"name": "Klaviyo: Product Affinity Cross-Sell Study",
"persona_ids": [p["id"] for p in personas],
"questions": pair_questions,
"context": f"""Product affinity study for an e-commerce running gear store.
PRODUCT CATALOG:
{product_catalog}
CROSS-SELL HYPOTHESES:
{chr(10).join(f"- {p['bought']} → {p['suggest']}: {p['logic']}" for p in PRODUCT_PAIRS)}
Each persona represents a different buyer segment. We want to validate which cross-sell pairs resonate with each segment before building automated flows.""",
"responses_per_persona": 2,
}).json()
for _ in range(30):
time.sleep(5)
data = requests.get(f"{MB}/focus-groups/{fg['id']}", headers=MH).json()
if data.get("status") == "completed":
break
print(f"Focus Group: {data.get('id')} — {data.get('status')}\n")
for resp in data.get("responses", []):
print(f"[{resp.get('persona_id','?')}] {resp.get('question','')[:80]}")
print(f" → {resp.get('answer','')[:300]}\n")