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

# Revenue Segment → Persona Tiering

> Segment Stripe customers by MRR into enterprise, mid-market, and SMB tiers as Mavera personas

### Scenario

Pull active customers with subscriptions, calculate MRR, and segment into enterprise ($10K+/mo), mid-market ($1K–$10K), and SMB (<$1K) tiers. Each tier becomes a Mavera persona enriched with revenue context.

### Architecture

```mermaid theme={"dark"}
flowchart LR
A["GET /v1/customers with subscriptions"] --> B["Calculate MRR per customer"] --> C["Segment: Enterprise / Mid-market / SMB"] --> D["POST /api/v1/personas per tier"]
```

### 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 fetch_customers_with_mrr():
      tiers = {"enterprise": [], "mid_market": [], "smb": []}
      customers = stripe.Customer.list(limit=100, expand=["data.subscriptions"])
      for cust in customers.auto_paging_iter():
          mrr = 0
          for sub in (cust.subscriptions.data if cust.subscriptions else []):
              if sub.status == "active":
                  for item in sub["items"].data:
                      mrr += item.price.unit_amount * item.quantity / 100
          bucket = "enterprise" if mrr >= 10000 else "mid_market" if mrr >= 1000 else "smb"
          tiers[bucket].append({"id": cust.id, "email": cust.email, "mrr": mrr})
      return tiers

  def create_persona(tier_name, customers):
      avg_mrr = sum(c["mrr"] for c in customers) / len(customers) if customers else 0
      resp = requests.post(f"{MAVERA_BASE}/personas", json={
          "name": f"{tier_name.replace('_', ' ').title()} Customer",
          "description": f"Revenue tier: {tier_name}. {len(customers)} customers, avg MRR ${avg_mrr:,.0f}.",
          "attributes": {"revenue_tier": tier_name, "customer_count": len(customers),
                          "avg_mrr": round(avg_mrr, 2), "sample_ids": [c["id"] for c in customers[:5]]},
      }, headers={"Authorization": f"Bearer {MAVERA_API_KEY}"})
      resp.raise_for_status()
      return resp.json()

  tiers = fetch_customers_with_mrr()
  for tier_name, customers in tiers.items():
      if customers:
          result = create_persona(tier_name, customers)
          print(f"Created persona: {result['id']} ({tier_name}, {len(customers)} customers)")
          time.sleep(0.2)
  ```

  ```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 fetchCustomersWithMRR() {
    const tiers = { enterprise: [], mid_market: [], smb: [] };
    const data = await stripeGet("customers", { limit: "100", "expand[]": "data.subscriptions" });
    for (const cust of data.data) {
      let mrr = 0;
      for (const sub of cust.subscriptions?.data || []) {
        if (sub.status === "active")
          for (const item of sub.items.data) mrr += (item.price.unit_amount * item.quantity) / 100;
      }
      tiers[mrr >= 10000 ? "enterprise" : mrr >= 1000 ? "mid_market" : "smb"]
        .push({ id: cust.id, email: cust.email, mrr });
    }
    return tiers;
  }

  async function createPersona(tierName, customers) {
    const avgMrr = customers.reduce((s, c) => s + c.mrr, 0) / customers.length;
    const res = await fetch(`${MAVERA_BASE}/personas`, {
      method: "POST",
      headers: { Authorization: `Bearer ${MAVERA_API_KEY}`, "Content-Type": "application/json" },
      body: JSON.stringify({
        name: `${tierName.replace("_", " ")} Customer`,
        description: `Revenue tier: ${tierName}. ${customers.length} customers, avg MRR $${avgMrr.toFixed(0)}.`,
        attributes: { revenue_tier: tierName, customer_count: customers.length,
          avg_mrr: Math.round(avgMrr * 100) / 100, sample_ids: customers.slice(0, 5).map((c) => c.id) },
      }),
    });
    if (!res.ok) throw new Error(`Mavera ${res.status}: ${await res.text()}`);
    return res.json();
  }

  (async () => {
    const tiers = await fetchCustomersWithMRR();
    for (const [tierName, customers] of Object.entries(tiers)) {
      if (customers.length) {
        const result = await createPersona(tierName, customers);
        console.log(`Created persona: ${result.id} (${tierName}, ${customers.length} customers)`);
      }
    }
  })();
  ```
</CodeGroup>

### Example Output

```json theme={"dark"}
{
  "id": "per_a1b2c3d4",
  "name": "Enterprise Customer",
  "description": "Revenue tier: enterprise. 34 customers, avg MRR $28,450.",
  "attributes": { "revenue_tier": "enterprise", "customer_count": 34, "avg_mrr": 28450.0 },
  "created_at": "2026-03-17T14:22:08Z"
}
```

### Error Handling

<AccordionGroup>
  <Accordion title="Stripe: Rate limit exceeded (429)">
    Stripe returns `429` at 25 req/sec. The Python library retries automatically. In JavaScript, read `Retry-After` header and `await new Promise(r => setTimeout(r, wait * 1000))`.
  </Accordion>

  <Accordion title="Mavera: Invalid persona attributes (422)">
    Nested objects deeper than 3 levels and arrays over 100 items are rejected. Flatten complex structures before posting.
  </Accordion>
</AccordionGroup>
