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

# CRM-to-Persona Pipeline

> Pull contacts from Salesforce via SOQL, group by title and industry, then create Mavera personas grounded in your actual buyer base

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

```mermaid theme={"dark"}
flowchart LR
    A["Salesforce SOQL (Contacts)"] --> B["Group by title/industry"] --> C["POST /api/v1/personas"] --> D[Mavera Persona Library]
```

## Code

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

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

## Example Output

```json theme={"dark"}
{
  "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" }
  ]
}
```

<Warning>
  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.
</Warning>

***

<CardGroup cols={2}>
  <Card title="Salesforce Overview" icon="salesforce" href="/integrations/salesforce">
    Back to all 8 Salesforce jobs
  </Card>

  <Card title="Deal-Stage Focus Group" icon="comments" href="/integrations/salesforce/deal-stage-focus-group">
    Next: Win/loss analysis via synthetic focus groups
  </Card>
</CardGroup>
