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

# Invoice Data → Case Study Generation

> Draft case study narratives from Stripe invoice growth trajectories using Mavera chat

### Scenario

Find long-term customers (12+ months of invoices, growing amounts) and use Mavera's chat endpoint to draft case study narratives from their payment trajectory.

### Architecture

```mermaid theme={"dark"}
flowchart LR
A["GET /v1/customers + invoices"] --> B["Filter: 12+ invoices, 20%+ growth"] --> C["POST /api/v1/mave/chat"] --> D["Draft case study per customer"]
```

### Code

<CodeGroup>
  ```python Python theme={"dark"}
  import os, time, stripe, requests

  stripe.api_key = os.environ["STRIPE_API_KEY"]
  MAVERA_API_KEY = os.environ["MAVERA_API_KEY"]
  MAVERA_BASE = "https://app.mavera.io/api/v1"

  def find_growth_customers(min_months=12):
      candidates = []
      for cust in stripe.Customer.list(limit=100).auto_paging_iter():
          paid = sorted(stripe.Invoice.list(customer=cust.id, limit=100, status="paid").data,
                         key=lambda i: i.created)
          if len(paid) < min_months:
              continue
          first, latest = paid[0].amount_paid / 100, paid[-1].amount_paid / 100
          if latest > first * 1.2:
              candidates.append({"name": cust.name or cust.email, "months_active": len(paid),
                  "first_invoice": first, "latest_invoice": latest,
                  "growth_pct": round((latest - first) / first * 100, 1)})
          time.sleep(0.05)
      return sorted(candidates, key=lambda c: -c["growth_pct"])[:10]

  def draft_case_study(d):
      resp = requests.post(f"{MAVERA_BASE}/mave/chat", json={
          "input": [
              {"role": "system", "content": "You are a B2B SaaS marketing writer."},
              {"role": "user", "content": f"Draft a 200-word case study for {d['name']}. "
                  f"Started at ${d['first_invoice']}/mo, grew to ${d['latest_invoice']}/mo over "
                  f"{d['months_active']} months ({d['growth_pct']}% growth). "
                  "Include headline, challenge, solution, results."},
          ],
          "max_tokens": 1000,
      }, headers={"Authorization": f"Bearer {MAVERA_API_KEY}"})
      resp.raise_for_status()
      return resp.json()

  for cust in find_growth_customers()[:3]:
      result = draft_case_study(cust)
      print(f"\n--- {cust['name']} ---\n{result['choices'][0]['message']['content']}")
      time.sleep(0.5)
  ```

  ```javascript JavaScript theme={"dark"}
  const STRIPE_API_KEY = process.env.STRIPE_API_KEY;
  const MAVERA_API_KEY = process.env.MAVERA_API_KEY;
  const MAVERA_BASE = "https://app.mavera.io/api/v1";

  async function stripeGet(path, params = {}) {
    const url = new URL(`https://api.stripe.com/v1/${path}`);
    Object.entries(params).forEach(([k, v]) => url.searchParams.append(k, v));
    const res = await fetch(url, { headers: { Authorization: `Bearer ${STRIPE_API_KEY}` } });
    if (!res.ok) throw new Error(`Stripe ${res.status}: ${await res.text()}`);
    return res.json();
  }

  async function findGrowthCustomers(minMonths = 12) {
    const candidates = [];
    const customers = await stripeGet("customers", { limit: "100" });
    for (const cust of customers.data) {
      const invoices = await stripeGet("invoices", { customer: cust.id, limit: "100", status: "paid" });
      const paid = invoices.data.sort((a, b) => a.created - b.created);
      if (paid.length < minMonths) continue;
      const first = paid[0].amount_paid / 100, latest = paid[paid.length - 1].amount_paid / 100;
      if (latest > first * 1.2) candidates.push({
        name: cust.name || cust.email, months_active: paid.length,
        first_invoice: first, latest_invoice: latest,
        growth_pct: Math.round(((latest - first) / first) * 1000) / 10,
      });
    }
    return candidates.sort((a, b) => b.growth_pct - a.growth_pct).slice(0, 10);
  }

  async function draftCaseStudy(d) {
    const res = await fetch(`${MAVERA_BASE}/mave/chat`, {
      method: "POST",
      headers: { Authorization: `Bearer ${MAVERA_API_KEY}`, "Content-Type": "application/json" },
      body: JSON.stringify({
        input: [
          { role: "system", content: "You are a B2B SaaS marketing writer." },
          { role: "user", content: `Draft a 200-word case study for ${d.name}. Started at $${d.first_invoice}/mo, grew to $${d.latest_invoice}/mo over ${d.months_active} months (${d.growth_pct}% growth). Include headline, challenge, solution, results.` },
        ],
        max_tokens: 1000,
      }),
    });
    if (!res.ok) throw new Error(`Mavera ${res.status}: ${await res.text()}`);
    return res.json();
  }

  (async () => {
    for (const cust of (await findGrowthCustomers()).slice(0, 3)) {
      const result = await draftCaseStudy(cust);
      console.log(`\n--- ${cust.name} ---\n${result.output[0].content[0].text}`);
    }
  })();
  ```
</CodeGroup>

### Example Output

```text theme={"dark"}
--- Acme Corp ---
Headline: How Acme Corp Scaled from $500/mo to $4,200/mo in 18 Months
Challenge: 12-person startup managing customers with spreadsheets. Sales
team spent 60% of time on admin tasks.
Solution: Automated customer lifecycle — lead scoring to renewals. Expanded
from Starter to Enterprise across three departments.
Results: 740% usage growth over 18 months. Response time dropped 68%, team
handles 4x volume with same headcount.
```

### Error Handling

<AccordionGroup>
  <Accordion title="Stripe: Invoice pagination limits">
    Returns up to 100 per call. Python auto-paging handles this; in JavaScript, loop with `starting_after` set to the last invoice ID.
  </Accordion>

  <Accordion title="Mavera: Chat response truncated">
    Increase `max_tokens` (up to 4,096) or split into two calls and concatenate.
  </Accordion>
</AccordionGroup>
