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

Every survey needs a report, and reports need to match your brand voice. This job pulls response data, generates statistical summaries, then uses Mavera’s Generate endpoint with your brand voice to produce an executive summary report. The output reads like it was written by your research team — same tone, same structure, same level of insight — but generated in seconds instead of days. Flow: SurveyMonkey bulk responses → Aggregate statistics → Mavera POST /api/v1/generations (with brand voice) → “Create executive summary of this survey.” → Branded research report

Architecture

Code

import os, requests, time
from collections import Counter, defaultdict

SM = os.environ["SURVEYMONKEY_TOKEN"]
MV = os.environ["MAVERA_API_KEY"]
SM_BASE = "https://api.surveymonkey.com/v3"
MB = "https://app.mavera.io/api/v1"
SM_H = {"Authorization": f"Bearer {SM}"}
MV_H = {"Authorization": f"Bearer {MV}", "Content-Type": "application/json"}

SURVEY_ID = os.environ.get("SURVEY_ID", "your_survey_id")
BRAND_VOICE_ID = os.environ.get("BRAND_VOICE_ID", "")

# 1. Survey structure
survey = requests.get(f"{SM_BASE}/surveys/{SURVEY_ID}/details",
    headers=SM_H).json()

questions = {}
choice_labels = {}
for page in survey.get("pages", []):
    for q in page.get("questions", []):
        qid = q["id"]
        heading = q.get("headings", [{}])[0].get("heading", "")
        questions[qid] = {"title": heading, "type": q.get("family", "")}
        for c in q.get("answers", {}).get("choices", []):
            choice_labels[c["id"]] = c.get("text", "")
        for r in q.get("answers", {}).get("rows", []):
            choice_labels[r["id"]] = r.get("text", "")
        for c in q.get("answers", {}).get("columns", []):
            choice_labels[c["id"]] = c.get("text", c.get("label", ""))

# 2. Pull responses
all_responses = []
page_num = 1
while True:
    r = requests.get(f"{SM_BASE}/surveys/{SURVEY_ID}/responses/bulk",
        headers=SM_H, params={"page": page_num, "per_page": 100})
    if r.status_code == 429:
        time.sleep(60); continue
    r.raise_for_status()
    data = r.json()
    all_responses.extend(data.get("data", []))
    if len(all_responses) >= data.get("total", 0) or not data.get("data"):
        break
    page_num += 1
    time.sleep(0.6)

# 3. Statistical summary
qa_data = defaultdict(list)
for resp in all_responses:
    for pg in resp.get("pages", []):
        for q in pg.get("questions", []):
            for ans in q.get("answers", []):
                if "text" in ans:
                    qa_data[q["id"]].append(ans["text"])
                elif "choice_id" in ans:
                    label = choice_labels.get(ans["choice_id"], "?")
                    if "row_id" in ans:
                        label = f"{choice_labels.get(ans['row_id'], '')}: {label}"
                    qa_data[q["id"]].append(label)

report_data = []
for qid, answers in qa_data.items():
    q = questions.get(qid, {})
    title = q["title"]
    q_type = q["type"]

    if q_type in ("single_choice", "multiple_choice"):
        counts = Counter(answers)
        total = len(answers)
        dist = {k: f"{v} ({v/total*100:.0f}%)" for k, v in counts.most_common(10)}
        report_data.append({"question": title, "type": q_type,
                           "n": total, "distribution": dist})
    elif q_type == "open_ended":
        report_data.append({"question": title, "type": "open_ended",
                           "n": len(answers), "samples": answers[:10]})
    else:
        nums = []
        for a in answers:
            try: nums.append(float(a))
            except ValueError: pass
        if nums:
            report_data.append({"question": title, "type": "numeric",
                               "n": len(nums), "mean": sum(nums)/len(nums),
                               "min": min(nums), "max": max(nums)})

# 4. Ensure brand voice
if not BRAND_VOICE_ID:
    bv = requests.post(f"{MB}/brand-voices", headers=MV_H, json={
        "name": "Research Report Voice",
        "samples": [
            "Executive Summary: Our Q4 customer satisfaction survey reveals "
            "strong product-market fit with critical friction points in onboarding. "
            "Key finding: 78% of respondents report daily usage, yet 34% cite "
            "documentation gaps as their primary frustration."
        ],
    }).json()
    BRAND_VOICE_ID = bv["id"]
    print(f"Created brand voice: {BRAND_VOICE_ID}")
    time.sleep(2)

# 5. Generate report
import json
data_block = json.dumps(report_data, indent=2)[:5000]

gen = requests.post(f"{MB}/generations", headers=MV_H, json={
    "brand_voice_id": BRAND_VOICE_ID,
    "prompt": f"""Create an executive summary report for this survey.

SURVEY: {survey.get('title', 'Survey')}
RESPONSES: {len(all_responses)}
DATE: {survey.get('date_modified', 'N/A')}

DATA:
{data_block}

Structure:
1. Executive Summary (3-4 sentences)
2. Methodology (survey type, sample size, collection period)
3. Key Findings (top 5, each with data point + insight)
4. Detailed Results (per-question analysis)
5. Recommendations (5 actionable items)
6. Appendix: Response distribution tables

Use a professional research report tone. Include specific numbers.
Lead each finding with the data, then the implication.""",
}).json()

report = gen.get("output", gen.get("content", gen.get("text", "")))
print(f"\n{'='*60}")
print(f"EXECUTIVE SUMMARY: {survey.get('title', 'Survey')}")
print(f"{'='*60}")
print(report[:3000])

Example Output

============================================================
EXECUTIVE SUMMARY: Q1 Customer Satisfaction Survey
============================================================

# Q1 2026 Customer Satisfaction Report