Scenario
Your marketing personas were built in a workshop, not from data. This job pulls contacts from Salesforce via SOQL, groups them by title and industry, then creates Mavera personas grounded in your actual buyer base. The result is a persona library that mirrors who really buys from you.Architecture
Code
import os, requests
from collections import defaultdict
SF = os.environ["SALESFORCE_INSTANCE"]
SF_T = os.environ["SALESFORCE_ACCESS_TOKEN"]
MV_K = os.environ["MAVERA_API_KEY"]
SF_HEADERS = {"Authorization": f"Bearer {SF_T}"}
MV_HEADERS = {"Authorization": f"Bearer {MV_K}", "Content-Type": "application/json"}
soql = (
"SELECT Name, Title, Industry, Description "
"FROM Contact WHERE Industry = 'Technology'"
)
resp = requests.get(
f"https://{SF}/services/data/v66.0/query",
headers=SF_HEADERS,
params={"q": soql},
)
resp.raise_for_status()
contacts = resp.json()["records"]
segments = defaultdict(list)
for c in contacts:
key = (c.get("Title", "Unknown"), c.get("Industry", "Unknown"))
segments[key].append(c)
created = []
for (title, industry), members in segments.items():
if len(members) < 3:
continue
descs = [m.get("Description", "") for m in members if m.get("Description")]
r = requests.post(
"https://app.mavera.io/api/v1/personas",
headers=MV_HEADERS,
json={
"name": f"{title} — {industry}",
"description": (
f"Derived from {len(members)} Salesforce contacts. "
f"Role: {title}. Industry: {industry}. "
f"Sample notes: {'; '.join(descs[:3])}"
),
},
)
r.raise_for_status()
created.append(r.json())
print(f"Created {len(created)} personas from {len(contacts)} contacts")
const SF = process.env.SALESFORCE_INSTANCE;
const SF_T = process.env.SALESFORCE_ACCESS_TOKEN;
const MV_K = process.env.MAVERA_API_KEY;
const soql = encodeURIComponent(
"SELECT Name, Title, Industry, Description FROM Contact WHERE Industry = 'Technology'"
);
const { records: contacts } = await fetch(
`https://${SF}/services/data/v66.0/query?q=${soql}`,
{ headers: { Authorization: `Bearer ${SF_T}` } }
).then((r) => r.json());
const segments = {};
for (const c of contacts) {
const key = `${c.Title || "Unknown"}|${c.Industry || "Unknown"}`;
(segments[key] ??= []).push(c);
}
const created = [];
for (const [key, members] of Object.entries(segments)) {
if (members.length < 3) continue;
const [title, industry] = key.split("|");
const descs = members.map((m) => m.Description).filter(Boolean).slice(0, 3);
const res = await fetch("https://app.mavera.io/api/v1/personas", {
method: "POST",
headers: { Authorization: `Bearer ${MV_K}`, "Content-Type": "application/json" },
body: JSON.stringify({
name: `${title} — ${industry}`,
description:
`Derived from ${members.length} Salesforce contacts. ` +
`Role: ${title}. Industry: ${industry}. ` +
`Sample notes: ${descs.join("; ")}`,
}),
});
created.push(await res.json());
}
console.log(`Created ${created.length} personas from ${contacts.length} contacts`);
Example Output
{
"created_count": 5,
"personas": [
{ "id": "per_8xK2m", "name": "VP Engineering — Technology" },
{ "id": "per_3jR9n", "name": "Director of Product — Technology" },
{ "id": "per_1qW4p", "name": "CTO — Technology" },
{ "id": "per_6zL7s", "name": "Engineering Manager — Technology" },
{ "id": "per_9tY0v", "name": "Head of Data — Technology" }
]
}
SOQL returns a maximum of 2,000 records per page. For large orgs, follow
nextRecordsUrl to paginate. Batch persona creation in groups of 10 to stay within Mavera rate limits.Salesforce Overview
Back to all 8 Salesforce jobs
Deal-Stage Focus Group
Next: Win/loss analysis via synthetic focus groups