Scenario
Pull active customers with subscriptions, calculate MRR, and segment into enterprise (10K+/mo),mid−market(1K–10K),andSMB(<1K) tiers. Each tier becomes a Mavera persona enriched with revenue context.Architecture
Code
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)
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)`);
}
}
})();
Example Output
{
"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
Stripe: Rate limit exceeded (429)
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)).Mavera: Invalid persona attributes (422)
Mavera: Invalid persona attributes (422)
Nested objects deeper than 3 levels and arrays over 100 items are rejected. Flatten complex structures before posting.