> ## Documentation Index
> Fetch the complete documentation index at: https://docs.presenton.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Generate customer QBR decks from CRM data

> Turn a CRM account export into one decision-ready quarterly business review per customer.

This tutorial creates a customer QBR presentation for every account in a CSV export. Each deck summarizes commercial context, adoption, delivered value, renewal risk, and the next-quarter success plan.

## Business outcome

Customer-success teams often spend hours copying CRM and product-usage data into slides. This workflow keeps the metrics deterministic while letting Presenton turn them into a clear executive narrative.

```mermaid theme={null}
flowchart LR
  CRM[Export account data] --> Validate[Validate business metrics]
  Validate --> Prompt[Build one QBR brief per account]
  Prompt --> Presenton[Generate branded QBR decks]
  Presenton --> Review[CSM review and delivery]
```

## Before you start

* Create a Presenton Cloud API key.
* Export approved account and product-usage fields from your CRM or warehouse.
* Install Python 3.10 or later.
* Store the API key outside source control:

```bash theme={null}
export PRESENTON_API_KEY=YOUR_API_KEY
python -m pip install pandas requests
```

## 1. Prepare the account export

Save this example as `accounts.csv`:

```csv theme={null}
Account,Industry,ARR,Renewal Date,Health Score,Weekly Active Users,Adoption Rate,Executive Sponsor,Primary Outcome,Open Risk,Next Milestone
Northstar Logistics,Logistics,185000,2026-10-31,82,438,76%,Maya Chen,"Reduced dispatch planning time by 31%","Analytics adoption is limited to two regions","Roll out analytics to all regional managers"
Vertex Health Systems,Healthcare,260000,2026-09-15,68,712,61%,Daniel Ortiz,"Standardized intake workflow across 14 clinics","SSO migration is behind schedule","Complete SSO rollout and train clinic admins"
BluePeak Manufacturing,Manufacturing,145000,2026-12-01,91,286,84%,Priya Raman,"Improved production issue response time by 24%","No active commercial risk","Launch supplier collaboration workspace"
```

Use fields your team can verify. Do not send confidential notes, personal data, or contractual details that should not appear in a customer-facing deck.

## 2. Generate the QBRs

Save as `generate_qbrs.py`:

```python theme={null}
import os
from pathlib import Path

import pandas as pd
import requests

API_URL = "https://api.presenton.ai/api/v3/presentation/generate"
API_KEY = os.environ["PRESENTON_API_KEY"]
OUTPUT_DIR = Path("qbr-decks")
OUTPUT_DIR.mkdir(exist_ok=True)


def money(value: float) -> str:
    return f"${value:,.0f}"


def safe_filename(value: str) -> str:
    return "".join(
        character if character.isalnum() or character in "-_" else "_"
        for character in value
    ).strip("_")


def build_qbr_brief(account: pd.Series) -> str:
    return f"""
Create an executive quarterly business review for {account['Account']}.

Verified account context:
- Industry: {account['Industry']}
- Annual recurring revenue: {money(account['ARR'])}
- Renewal date: {account['Renewal Date']}
- Customer health score: {account['Health Score']}/100
- Weekly active users: {account['Weekly Active Users']}
- Feature adoption: {account['Adoption Rate']}
- Executive sponsor: {account['Executive Sponsor']}
- Primary business outcome: {account['Primary Outcome']}
- Open risk: {account['Open Risk']}
- Next milestone: {account['Next Milestone']}

Build a six-slide QBR:
1. Executive account snapshot
2. Business outcomes delivered
3. Adoption and engagement
4. Risks and mitigation plan
5. Renewal readiness
6. Agreed next-quarter actions with owners

Preserve every supplied number and date exactly. Do not invent ROI, usage,
commitments, owners, or customer quotes. Label recommendations clearly.
""".strip()


def generate_qbr(account: pd.Series) -> None:
    response = requests.post(
        API_URL,
        headers={
            "Authorization": f"Bearer {API_KEY}",
            "Content-Type": "application/json",
        },
        json={
            "content": build_qbr_brief(account),
            "instructions": "Write for an executive customer audience and keep each slide concise.",
            "n_slides": 6,
            "language": "English",
            "tone": "professional",
            "verbosity": "concise",
            "standard_template": "neo-modern",
            "theme": "professional-blue",
            "export_as": "pptx",
        },
        timeout=600,
    )
    response.raise_for_status()
    result = response.json()

    output_path = OUTPUT_DIR / f"{safe_filename(account['Account'])}_QBR.pptx"
    download = requests.get(
        result["path"],
        headers={"Authorization": f"Bearer {API_KEY}"},
        timeout=120,
    )
    download.raise_for_status()
    output_path.write_bytes(download.content)
    print(f"Created {output_path} — review at {result['edit_path']}")


def main() -> None:
    accounts = pd.read_csv("accounts.csv")
    required = {
        "Account", "Industry", "ARR", "Renewal Date", "Health Score",
        "Weekly Active Users", "Adoption Rate", "Executive Sponsor",
        "Primary Outcome", "Open Risk", "Next Milestone",
    }
    missing = required - set(accounts.columns)
    if missing:
        raise ValueError(f"Missing CRM columns: {sorted(missing)}")

    for _, account in accounts.iterrows():
        try:
            generate_qbr(account)
        except requests.RequestException as error:
            print(f"Failed for {account['Account']}: {error}")


if __name__ == "__main__":
    main()
```

## 3. Review before sharing

The account owner should verify:

* ARR, renewal date, health score, and adoption metrics.
* Whether the stated outcome is approved for customer-facing use.
* Risk wording and the mitigation plan.
* Owners and dates added during review.
* Branding, customer logo rights, and presentation tone.

## Operationalize the workflow

* Use the account ID and reporting period as an idempotency key.
* Generate drafts in a background queue for large account portfolios.
* Store the returned presentation ID in the CRM activity record.
* Require CSM approval before a deck is sent externally.
* Regenerate only when verified source data changes.

<Card title="Generate asynchronously" icon="clock-rotate-left" href="/cloud/guides/async-generation">
  Queue larger QBR batches and monitor each task reliably.
</Card>
