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

# Brand Voice → Full Content Library

> Create a brand voice from your website, then systematically run every Generate app with the same voice to produce a complete, on-brand content library in one sitting

## Scenario

You have a website and a product launch coming up. You need a blog post, a LinkedIn ad, an email sequence, social captions, a product description, and ad copy — all in the same voice. Normally you'd brief a writer, wait days, review for tone consistency, and iterate.

This playbook creates a brand voice from your existing website pages, then fires every relevant Generate app against that voice. In one script run you get a full content library — every piece on-brand by construction.

<Info>
  **Mavera-only.** No external API, no CMS integration, no third-party auth. Just Brand Voice + Generate + the Mavera API.
</Info>

***

## Architecture

```mermaid theme={"dark"}
flowchart LR
    A["Website URLs"] --> B["Brand Voice API"]
    B --> C["GET /generation-apps"]
    C --> D["POST /generations"]
    D --> D1["Blog Post"]
    D --> D2["LinkedIn Ad"]
    D --> D3["Email Sequence"]
    D --> D4["Social Captions"]
    D --> D5["Product Description"]
    D --> D6["Ad Copy Variants"]
```

***

## What You Need

| Requirement                        | Details                                                                                              |
| ---------------------------------- | ---------------------------------------------------------------------------------------------------- |
| **Mavera API key**                 | Starts with `mvra_live_`. Get one at [Developer Settings](https://app.mavera.io/settings/developer). |
| **Workspace ID**                   | From your dashboard URL (`ws_...`).                                                                  |
| **2–5 website URLs**               | Public pages that represent your brand voice (about page, blog, homepage).                           |
| **Product brief**                  | Topic, audience, and key points for the content you want to generate.                                |
| **Credits**                        | \~200–400 total. See [Credits Estimate](#credits-estimate).                                          |
| **Python 3.8+** or **Node.js 18+** | `requests` for Python; native `fetch` for Node.                                                      |

```
MAVERA_API_KEY=mvra_live_your_key_here
MAVERA_WORKSPACE_ID=ws_your_workspace_id
```

***

## The Flow

<Steps>
  <Step title="Create brand voice from website URLs">
    `POST /brand-voices` with 2–5 public URLs. Mavera scrapes them and extracts tone, vocabulary, sentence style, and formality. Poll until `status` is `READY`.
  </Step>

  <Step title="Discover available generation apps">
    `GET /generation-apps` returns every template with its `app_id` and required `input_data` fields. Pick the apps that match your content plan.
  </Step>

  <Step title="Generate content for each app">
    Loop through your chosen apps. Every `POST /generations` call passes the same `brand_voice_id`, ensuring consistent voice across blog posts, emails, ads, and social content.
  </Step>

  <Step title="Collect and review">
    Each generation returns `output` (text) and `usage.credits_used`. Collect everything into a content library — ready for review, editing, and publishing.
  </Step>
</Steps>

***

## Stage 1 — Create Brand Voice from URLs

<CodeGroup>
  ```python Python theme={"dark"}
  import os
  import time
  import json
  import requests

  API_KEY = os.environ["MAVERA_API_KEY"]
  WORKSPACE_ID = os.environ["MAVERA_WORKSPACE_ID"]
  BASE = "https://app.mavera.io/api/v1"
  HEADERS = {
      "Authorization": f"Bearer {API_KEY}",
      "Content-Type": "application/json",
  }

  BRAND_URLS = [
      "https://yourbrand.com/about",
      "https://yourbrand.com/blog/why-we-exist",
      "https://yourbrand.com/blog/our-approach",
  ]

  bv_resp = requests.post(
      f"{BASE}/brand-voices",
      headers=HEADERS,
      json={
          "label": "Launch Voice — Website",
          "usage_context": "Product launch content across blog, email, social, and ads",
          "urls": BRAND_URLS,
          "workspace_id": WORKSPACE_ID,
      },
  )
  bv_resp.raise_for_status()
  brand_voice = bv_resp.json()
  voice_id = brand_voice["id"]
  print(f"Brand voice created: {voice_id} (status: {brand_voice['status']})")


  def wait_for_voice(bv_id, max_wait=300):
      """Poll until brand voice is READY."""
      for _ in range(max_wait // 10):
          resp = requests.get(f"{BASE}/brand-voices/{bv_id}", headers=HEADERS)
          data = resp.json()
          if data.get("status") == "READY":
              return data
          time.sleep(10)
      raise TimeoutError(f"Brand voice {bv_id} not ready after {max_wait}s")


  voice = wait_for_voice(voice_id)
  print(f"Voice ready: {voice.get('voice_summary', '')[:120]}...")
  print(f"Tone: {voice.get('tone_adjectives', [])}")
  ```

  ```javascript JavaScript theme={"dark"}
  const API_KEY = process.env.MAVERA_API_KEY;
  const WORKSPACE_ID = process.env.MAVERA_WORKSPACE_ID;
  const BASE = "https://app.mavera.io/api/v1";
  const HEADERS = {
    Authorization: `Bearer ${API_KEY}`,
    "Content-Type": "application/json",
  };

  const BRAND_URLS = [
    "https://yourbrand.com/about",
    "https://yourbrand.com/blog/why-we-exist",
    "https://yourbrand.com/blog/our-approach",
  ];

  const bvResp = await fetch(`${BASE}/brand-voices`, {
    method: "POST",
    headers: HEADERS,
    body: JSON.stringify({
      label: "Launch Voice — Website",
      usage_context: "Product launch content across blog, email, social, and ads",
      urls: BRAND_URLS,
      workspace_id: WORKSPACE_ID,
    }),
  });
  const brandVoice = await bvResp.json();
  const voiceId = brandVoice.id;
  console.log(`Brand voice created: ${voiceId} (status: ${brandVoice.status})`);

  async function waitForVoice(bvId, maxWait = 300) {
    for (let elapsed = 0; elapsed < maxWait; elapsed += 10) {
      const resp = await fetch(`${BASE}/brand-voices/${bvId}`, { headers: HEADERS });
      const data = await resp.json();
      if (data.status === "READY") return data;
      await new Promise((r) => setTimeout(r, 10000));
    }
    throw new Error(`Brand voice ${bvId} not ready after ${maxWait}s`);
  }

  const voice = await waitForVoice(voiceId);
  console.log(`Voice ready: ${voice.voice_summary?.slice(0, 120)}...`);
  console.log("Tone:", voice.tone_adjectives);
  ```
</CodeGroup>

***

## Stage 2 — Discover Generation Apps

<CodeGroup>
  ```python Python theme={"dark"}
  apps_resp = requests.get(f"{BASE}/generation-apps", headers=HEADERS)
  apps_resp.raise_for_status()
  all_apps = apps_resp.json()["data"]

  for app in all_apps:
      print(f"  {app['id']:35s}  {app.get('name', '')}")

  CONTENT_PLAN = [
      {
          "app_id": "blog_post_generator",
          "title": "Launch Blog Post",
          "input_data": {
              "topic": "Introducing Our New Product Line",
              "target_audience": "Small business owners looking for workflow automation",
              "tone": "professional yet approachable",
              "length": "1200 words",
              "key_points": [
                  "What the product does",
                  "Three key features",
                  "Customer pain points it solves",
                  "Getting started steps",
              ],
          },
      },
      {
          "app_id": "linkedin_ad_generator",
          "title": "Launch LinkedIn Ad",
          "input_data": {
              "product": "Workflow Automation Suite",
              "target_audience": "Operations managers at 50-500 person companies",
              "value_proposition": "Cut manual processes by 60%",
              "cta": "Start free trial",
          },
      },
      {
          "app_id": "email_sequence_generator",
          "title": "Launch Email Nurture",
          "input_data": {
              "sequence_goal": "Convert free trial signups to paid customers",
              "emails_count": 5,
              "target_audience": "Trial users who signed up in the last 7 days",
              "key_points": [
                  "Welcome and quick-start guide",
                  "Feature highlight: automation builder",
                  "Customer success story",
                  "Pricing and upgrade benefits",
                  "Last chance / trial ending",
              ],
          },
      },
      {
          "app_id": "social_post_generator",
          "title": "Launch Social Captions",
          "input_data": {
              "topic": "Product launch announcement",
              "platform": "Instagram",
              "tone": "exciting, conversational",
              "count": 5,
          },
      },
      {
          "app_id": "product_description",
          "title": "Product Page Copy",
          "input_data": {
              "product_name": "Workflow Automation Suite",
              "features": [
                  "Drag-and-drop automation builder",
                  "200+ integrations",
                  "Real-time analytics dashboard",
              ],
              "target_audience": "Small business owners",
              "tone": "clear, benefit-focused",
          },
      },
      {
          "app_id": "ad_copy_generator",
          "title": "Launch Ad Copy Variants",
          "input_data": {
              "product": "Workflow Automation Suite",
              "audience": "SMB operations teams",
              "goal": "Drive demo signups",
              "variants": 3,
          },
      },
  ]
  ```

  ```javascript JavaScript theme={"dark"}
  const appsResp = await fetch(`${BASE}/generation-apps`, { headers: HEADERS });
  const allApps = (await appsResp.json()).data;
  allApps.forEach((app) => console.log(`  ${app.id.padEnd(35)} ${app.name || ""}`));

  const CONTENT_PLAN = [
    {
      app_id: "blog_post_generator",
      title: "Launch Blog Post",
      input_data: {
        topic: "Introducing Our New Product Line",
        target_audience: "Small business owners looking for workflow automation",
        tone: "professional yet approachable",
        length: "1200 words",
        key_points: [
          "What the product does",
          "Three key features",
          "Customer pain points it solves",
          "Getting started steps",
        ],
      },
    },
    {
      app_id: "linkedin_ad_generator",
      title: "Launch LinkedIn Ad",
      input_data: {
        product: "Workflow Automation Suite",
        target_audience: "Operations managers at 50-500 person companies",
        value_proposition: "Cut manual processes by 60%",
        cta: "Start free trial",
      },
    },
    {
      app_id: "email_sequence_generator",
      title: "Launch Email Nurture",
      input_data: {
        sequence_goal: "Convert free trial signups to paid customers",
        emails_count: 5,
        target_audience: "Trial users who signed up in the last 7 days",
        key_points: [
          "Welcome and quick-start guide",
          "Feature highlight: automation builder",
          "Customer success story",
          "Pricing and upgrade benefits",
          "Last chance / trial ending",
        ],
      },
    },
    {
      app_id: "social_post_generator",
      title: "Launch Social Captions",
      input_data: {
        topic: "Product launch announcement",
        platform: "Instagram",
        tone: "exciting, conversational",
        count: 5,
      },
    },
    {
      app_id: "product_description",
      title: "Product Page Copy",
      input_data: {
        product_name: "Workflow Automation Suite",
        features: ["Drag-and-drop automation builder", "200+ integrations", "Real-time analytics dashboard"],
        target_audience: "Small business owners",
        tone: "clear, benefit-focused",
      },
    },
    {
      app_id: "ad_copy_generator",
      title: "Launch Ad Copy Variants",
      input_data: {
        product: "Workflow Automation Suite",
        audience: "SMB operations teams",
        goal: "Drive demo signups",
        variants: 3,
      },
    },
  ];
  ```
</CodeGroup>

***

## Stage 3 — Generate the Full Library

Every generation passes the same `brand_voice_id`. The voice rules constrain tone, vocabulary, and sentence style across all output — blog posts read like your website, emails read like your blog, ads read like your emails.

<CodeGroup>
  ```python Python theme={"dark"}
  def generate_content(app_id, title, input_data, brand_voice_id):
      """Run one generation app with the shared brand voice."""
      resp = requests.post(
          f"{BASE}/generations",
          headers=HEADERS,
          json={
              "app_id": app_id,
              "title": title,
              "brand_voice_id": brand_voice_id,
              "input_data": input_data,
              "workspace_id": WORKSPACE_ID,
          },
      )
      resp.raise_for_status()
      gen = resp.json()

      if gen.get("status") in ("PENDING", "RUNNING"):
          gen = wait_for_generation(gen["id"])

      return gen


  def wait_for_generation(gen_id, max_wait=300):
      """Poll until generation completes."""
      for _ in range(max_wait // 10):
          resp = requests.get(f"{BASE}/generations/{gen_id}", headers=HEADERS)
          data = resp.json()
          if data.get("status") == "COMPLETED":
              return data
          time.sleep(10)
      raise TimeoutError(f"Generation {gen_id} timed out")


  library = []
  total_credits = 0

  for item in CONTENT_PLAN:
      print(f"Generating: {item['title']} ({item['app_id']})...")
      gen = generate_content(
          app_id=item["app_id"],
          title=item["title"],
          input_data=item["input_data"],
          brand_voice_id=voice_id,
      )
      credits = gen.get("usage", {}).get("credits_used", 0)
      total_credits += credits

      library.append({
          "title": item["title"],
          "app": item["app_id"],
          "output": gen.get("output", ""),
          "credits": credits,
      })
      print(f"  ✓ {credits} credits | {len(gen.get('output', ''))} chars")

  print(f"\n{'='*50}")
  print(f"Library complete: {len(library)} pieces | {total_credits} total credits")
  ```

  ```javascript JavaScript theme={"dark"}
  async function generateContent(appId, title, inputData, brandVoiceId) {
    const resp = await fetch(`${BASE}/generations`, {
      method: "POST",
      headers: HEADERS,
      body: JSON.stringify({
        app_id: appId,
        title,
        brand_voice_id: brandVoiceId,
        input_data: inputData,
        workspace_id: WORKSPACE_ID,
      }),
    });
    let gen = await resp.json();

    if (gen.status === "PENDING" || gen.status === "RUNNING") {
      gen = await waitForGeneration(gen.id);
    }
    return gen;
  }

  async function waitForGeneration(genId, maxWait = 300) {
    for (let elapsed = 0; elapsed < maxWait; elapsed += 10) {
      const resp = await fetch(`${BASE}/generations/${genId}`, { headers: HEADERS });
      const data = await resp.json();
      if (data.status === "COMPLETED") return data;
      await new Promise((r) => setTimeout(r, 10000));
    }
    throw new Error(`Generation ${genId} timed out`);
  }

  const library = [];
  let totalCredits = 0;

  for (const item of CONTENT_PLAN) {
    console.log(`Generating: ${item.title} (${item.app_id})...`);
    const gen = await generateContent(item.app_id, item.title, item.input_data, voiceId);
    const credits = gen.usage?.credits_used || 0;
    totalCredits += credits;

    library.push({
      title: item.title,
      app: item.app_id,
      output: gen.output || "",
      credits,
    });
    console.log(`  ✓ ${credits} credits | ${(gen.output || "").length} chars`);
  }

  console.log(`\nLibrary complete: ${library.length} pieces | ${totalCredits} total credits`);
  ```
</CodeGroup>

***

## Variations

<AccordionGroup>
  <Accordion title="Multiple brand voices for audience segments">
    Create separate brand voices for different audiences (e.g. enterprise vs SMB), then run the same content plan against each voice. Compare outputs side by side:

    ```python theme={"dark"}
    voices = {
        "enterprise": create_voice(["https://yourbrand.com/enterprise"]),
        "smb": create_voice(["https://yourbrand.com/small-business"]),
    }
    for segment, vid in voices.items():
        for item in CONTENT_PLAN:
            gen = generate_content(item["app_id"], f"{segment} — {item['title']}", item["input_data"], vid)
    ```
  </Accordion>

  <Accordion title="Incremental library updates">
    Store the voice ID and re-run only new apps when new templates become available:

    ```python theme={"dark"}
    existing_apps = {p["app"] for p in manifest["pieces"]}
    new_apps = [a for a in all_apps if a["id"] not in existing_apps]
    for app in new_apps:
        gen = generate_content(app["id"], app["name"], default_input, voice_id)
        library.append(gen)
    ```
  </Accordion>

  <Accordion title="Voice consistency scoring">
    After generating the library, score each piece against the voice rules using Chat with `response_format`. Flag any pieces that drift:

    ```python theme={"dark"}
    from openai import OpenAI
    mavera = OpenAI(api_key=API_KEY, base_url=BASE)

    for piece in library:
        resp = mavera.responses.create(
            model="mavera-1",
            input=[
                {"role": "system", "content": f"Score brand voice consistency 1-10:\n{json.dumps(voice.get('tone_adjectives', []))}"},
                {"role": "user", "content": piece["output"][:2000]},
            ],
        )
        print(f"{piece['title']}: {resp.output[0].content[0].text}")
    ```
  </Accordion>

  <Accordion title="Parallel generation for speed">
    Each generation call is independent — use `asyncio.gather` (Python) or `Promise.all` (JS) to run all 6 apps concurrently instead of sequentially.
  </Accordion>
</AccordionGroup>

***

## Credits Estimate

| Operation                  | Typical Cost          | Notes                              |
| -------------------------- | --------------------- | ---------------------------------- |
| Brand voice creation       | 50 credits            | One-time per voice profile         |
| Blog post generation       | 15–30 credits         | Depends on length (500–1500 words) |
| LinkedIn ad generation     | 10–20 credits         | Short-form                         |
| Email sequence (5 emails)  | 20–40 credits         | Multi-part output                  |
| Social captions (5 posts)  | 10–20 credits         | Short-form batch                   |
| Product description        | 10–25 credits         | Medium-form                        |
| Ad copy variants (3)       | 10–20 credits         | Short-form batch                   |
| **Total (voice + 6 apps)** | **\~125–205 credits** |                                    |

<Tip>
  The brand voice is the most durable investment — create once, reuse across hundreds of generations. The 50-credit extraction pays for itself after 2–3 content runs.
</Tip>

***

## What's Next

<CardGroup cols={2}>
  <Card title="Content Repurposing Pipeline" icon="recycle" href="/playbooks/content-repurposing-pipeline">
    Turn one blog post into 5+ content formats
  </Card>

  <Card title="A/B Copy Production" icon="clone" href="/playbooks/ab-copy-production">
    Same brief, different voices — ready-to-test variants
  </Card>

  <Card title="Brand Voice Extraction & Audit" icon="palette" href="/cookbooks/brand-voice-extraction-audit">
    Score content consistency against extracted voice rules
  </Card>

  <Card title="Content Generation" icon="wand-magic-sparkles" href="/features/content-generation">
    Full API reference for generation apps
  </Card>

  <Card title="Brand Voice" icon="bullhorn" href="/features/brand-voice">
    Create and manage brand voice profiles
  </Card>

  <Card title="Credits & Budget" icon="coins" href="/cookbooks/credits-budget-alerts">
    Usage tracking and cost estimation
  </Card>
</CardGroup>
