> ## 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.

# Response Data → Generate Reports

> Generate branded executive summary reports from SurveyMonkey response data using Mavera Generate with brand voice

### 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

```mermaid theme={"dark"}
flowchart LR
A["Bulk Responses"] --> B["Statistical summaries"] --> C["GET or POST /api/v1/brand-voices"] --> D["POST /api/v1/generations"] --> E["Branded executive report"]
```

### Code

<CodeGroup>
  ```python Python theme={"dark"}
  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])
  ```

  ```javascript JavaScript theme={"dark"}
  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));
  ```
</CodeGroup>

### Example Output

```text theme={"dark"}
============================================================
EXECUTIVE SUMMARY: Q1 Customer Satisfaction Survey
============================================================

# Q1 2026 Customer Satisfaction Report
```
