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 → MaveraPOST /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])
const SM = process.env.SURVEYMONKEY_TOKEN;
const MV = process.env.MAVERA_API_KEY;
const SM_BASE = "https://api.surveymonkey.com/v3";
const MB = "https://app.mavera.io/api/v1";
const smH = { Authorization: `Bearer ${SM}` };
const mvH = { Authorization: `Bearer ${MV}`, "Content-Type": "application/json" };
const SURVEY_ID = process.env.SURVEY_ID || "your_survey_id";
let brandVoiceId = process.env.BRAND_VOICE_ID || "";
// 1. Survey structure
const survey = await fetch(`${SM_BASE}/surveys/${SURVEY_ID}/details`,
{ headers: smH }).then(r => r.json());
const questions = {};
const choiceLabels = {};
for (const page of survey.pages || []) {
for (const q of page.questions || []) {
questions[q.id] = { title: q.headings?.[0]?.heading || "", type: q.family || "" };
for (const c of q.answers?.choices || []) choiceLabels[c.id] = c.text || "";
for (const r of q.answers?.rows || []) choiceLabels[r.id] = r.text || "";
for (const c of q.answers?.columns || []) choiceLabels[c.id] = c.text || c.label || "";
}
}
// 2. Pull responses
const allResponses = [];
let pageNum = 1;
while (true) {
let res = await fetch(`${SM_BASE}/surveys/${SURVEY_ID}/responses/bulk?page=${pageNum}&per_page=100`,
{ headers: smH });
if (res.status === 429) { await new Promise(r => setTimeout(r, 60000)); continue; }
const data = await res.json();
allResponses.push(...(data.data || []));
if (allResponses.length >= (data.total || 0) || !(data.data || []).length) break;
pageNum++;
await new Promise(r => setTimeout(r, 600));
}
// 3. Aggregate
const qaData = {};
for (const resp of allResponses) {
for (const pg of resp.pages || []) {
for (const q of pg.questions || []) {
(qaData[q.id] ??= []);
for (const ans of q.answers || []) {
if (ans.text) qaData[q.id].push(ans.text);
else if (ans.choice_id) {
let label = choiceLabels[ans.choice_id] || "?";
if (ans.row_id) label = `${choiceLabels[ans.row_id] || ""}: ${label}`;
qaData[q.id].push(label);
}
}
}
}
}
// 4. Report data
const reportData = [];
for (const [qid, answers] of Object.entries(qaData)) {
const q = questions[qid] || {};
if (["single_choice", "multiple_choice"].includes(q.type)) {
const counts = {};
answers.forEach(a => { counts[a] = (counts[a] || 0) + 1; });
const dist = Object.fromEntries(
Object.entries(counts).sort(([, a], [, b]) => b - a).slice(0, 10)
.map(([k, v]) => [k, `${v} (${(v / answers.length * 100).toFixed(0)}%)`]));
reportData.push({ question: q.title, type: q.type, n: answers.length, distribution: dist });
} else if (q.type === "open_ended") {
reportData.push({ question: q.title, type: "open_ended", n: answers.length, samples: answers.slice(0, 10) });
} else {
const nums = answers.map(Number).filter(n => !isNaN(n));
if (nums.length) reportData.push({ question: q.title, type: "numeric", n: nums.length,
mean: nums.reduce((s, n) => s + n, 0) / nums.length, min: Math.min(...nums), max: Math.max(...nums) });
}
}
// 5. Ensure brand voice
if (!brandVoiceId) {
const bv = await fetch(`${MB}/brand-voices`, { method: "POST", headers: mvH,
body: JSON.stringify({ name: "Research Report Voice",
samples: ["Executive Summary: Our Q4 survey reveals strong product-market fit with friction in onboarding. 78% daily usage, 34% cite documentation gaps."] }),
}).then(r => r.json());
brandVoiceId = bv.id;
await new Promise(r => setTimeout(r, 2000));
}
// 6. Generate report
const gen = await fetch(`${MB}/generations`, { method: "POST", headers: mvH,
body: JSON.stringify({
brand_voice_id: brandVoiceId,
prompt: `Create executive summary for this survey.
SURVEY: ${survey.title} | RESPONSES: ${allResponses.length}
DATA:\n${JSON.stringify(reportData, null, 2).slice(0, 5000)}
Structure: 1) Executive Summary 2) Methodology 3) Key Findings (top 5) 4) Detailed Results 5) Recommendations 6) Appendix
Professional tone. Specific numbers. Data first, then implication.`,
}),
}).then(r => r.json());
console.log(`\n${"=".repeat(60)}\nEXECUTIVE SUMMARY: ${survey.title}\n${"=".repeat(60)}`);
console.log((gen.output || gen.content || gen.text || "").slice(0, 3000));
Example Output
============================================================
EXECUTIVE SUMMARY: Q1 Customer Satisfaction Survey
============================================================
# Q1 2026 Customer Satisfaction Report