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

# Employee Advocacy Content Generation

> Pull company updates from LinkedIn, create a conversational Brand Voice, and generate employee-ready post variants for personal sharing

## Scenario

Your company publishes polished updates, but employees don't reshare them — the posts sound corporate. This job pulls recent company updates, creates or reuses a conversational Brand Voice, then generates employee-ready versions of each post. The rewrites swap corporate tone for personal, first-person language that employees can paste directly into their feeds. Each variant is tailored for individual sharing: shorter, more conversational, with a personal take that makes the reshare feel authentic.

## Architecture

```mermaid theme={"dark"}
flowchart LR
    A["LinkedIn GET /posts (company updates)"] --> B["Select shareable posts"]
    B --> C["Mavera POST /brand-voices (employee voice)"]
    C --> D["POST /generations per post"]
    D --> E["Employee-ready variants"]
```

## Code

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

  LI = os.environ["LINKEDIN_ACCESS_TOKEN"]
  MV = os.environ["MAVERA_API_KEY"]
  LI_BASE = "https://api.linkedin.com/rest"
  MV_BASE = "https://app.mavera.io/api/v1"
  LI_H = {"Authorization": f"Bearer {LI}", "LinkedIn-Version": "202401", "X-Restli-Protocol-Version": "2.0.0"}
  MV_H = {"Authorization": f"Bearer {MV}", "Content-Type": "application/json"}

  ORG_URN = "urn:li:organization:12345678"

  # 1. Pull recent company posts
  r = requests.get(f"{LI_BASE}/posts",
      headers=LI_H,
      params={"q": "author", "author": ORG_URN, "count": 20, "sortBy": "LAST_MODIFIED"})
  if r.status_code == 429:
      time.sleep(int(r.headers.get("Retry-After", 60)))
      r = requests.get(f"{LI_BASE}/posts", headers=LI_H,
          params={"q": "author", "author": ORG_URN, "count": 20, "sortBy": "LAST_MODIFIED"})
  r.raise_for_status()
  posts = r.json().get("elements", [])

  # 2. Filter to shareable posts (skip internal-only or short updates)
  shareable = []
  for post in posts:
      commentary = post.get("commentary", "")
      visibility = post.get("visibility", "")
      if not commentary or len(commentary) < 50:
          continue
      shareable.append({
          "urn": post.get("id", ""),
          "commentary": commentary,
          "content_type": post.get("content", {}).get("contentType", "NONE"),
          "media_url": post.get("content", {}).get("media", {}).get("id", ""),
      })

  if not shareable:
      raise SystemExit("No shareable posts found.")

  # 3. Create conversational Brand Voice for employee shares
  employee_voice_samples = """
  I've been at [Company] for two years now, and this is the kind of work that
  makes me proud to be here. We just shipped something that actually changes
  how our customers work — not incrementally, but fundamentally.

  ---

  Hot take: most marketing analytics tools are built for dashboards, not
  decisions. We built the opposite. Here's what I mean.

  ---

  Three things I learned this quarter working with our customers:
  1. The data isn't the problem — it's getting from data to action
  2. Speed matters more than precision in most marketing decisions
  3. Teams that automate reporting spend 60% more time on strategy

  This is why I love what we're building.
  """

  bv = requests.post(f"{MV_BASE}/brand-voices", headers=MV_H, json={
      "name": "Employee Advocacy Voice — Conversational",
      "samples": [employee_voice_samples],
  }).json()
  voice_id = bv["id"]
  print(f"Brand Voice: {voice_id}")

  # 4. Generate employee-ready variants for each post
  all_variants = []
  for i, post in enumerate(shareable[:5]):
      gen = requests.post(f"{MV_BASE}/generations", headers=MV_H, json={
          "brand_voice_id": voice_id,
          "prompt": f"""Rewrite this LinkedIn company post for individual employees to share on their personal profiles.

  ORIGINAL COMPANY POST:
  {post['commentary'][:600]}

  Rules:
  - Write in first person ("I", "we", "my team")
  - Add a personal take or reaction (not just a reshare)
  - Keep under 200 words (LinkedIn mobile truncation)
  - Open with a hook — not "Excited to announce" or "Thrilled to share"
  - End with a question or invitation to discuss
  - Sound like a real person, not a press release
  - Generate 3 variants with different angles: (1) personal story, (2) hot take, (3) lesson learned

  CONTENT TYPE: {post['content_type']}""",
          "count": 3,
      }).json()

      variants = gen.get("results", [gen])
      all_variants.append({
          "original": post["commentary"][:200],
          "urn": post["urn"],
          "variants": [v.get("content", v.get("text", ""))[:500] for v in variants],
      })
      time.sleep(0.5)

  # 5. Output
  for entry in all_variants:
      print(f"\n{'='*60}")
      print(f"ORIGINAL: {entry['original'][:120]}...")
      print(f"{'='*60}")
      for j, variant in enumerate(entry["variants"]):
          labels = ["Personal Story", "Hot Take", "Lesson Learned"]
          print(f"\n  [{labels[j] if j < len(labels) else f'Variant {j+1}'}]")
          print(f"  {variant}")

  print(f"\n--- Generated {sum(len(e['variants']) for e in all_variants)} employee variants for {len(all_variants)} posts ---")
  print(f"Brand Voice: {voice_id}")
  ```

  ```javascript JavaScript theme={"dark"}
  const LI = process.env.LINKEDIN_ACCESS_TOKEN;
  const MV = process.env.MAVERA_API_KEY;
  const LI_BASE = "https://api.linkedin.com/rest";
  const MV_BASE = "https://app.mavera.io/api/v1";
  const LI_H = { Authorization: `Bearer ${LI}`, "LinkedIn-Version": "202401", "X-Restli-Protocol-Version": "2.0.0" };
  const MV_H = { Authorization: `Bearer ${MV}`, "Content-Type": "application/json" };

  const ORG_URN = "urn:li:organization:12345678";

  // 1. Pull recent company posts
  let res = await fetch(
    `${LI_BASE}/posts?q=author&author=${encodeURIComponent(ORG_URN)}&count=20&sortBy=LAST_MODIFIED`,
    { headers: LI_H }
  );
  if (res.status === 429) {
    await new Promise(r => setTimeout(r, parseInt(res.headers.get("Retry-After") || "60", 10) * 1000));
    res = await fetch(
      `${LI_BASE}/posts?q=author&author=${encodeURIComponent(ORG_URN)}&count=20&sortBy=LAST_MODIFIED`,
      { headers: LI_H }
    );
  }
  if (!res.ok) throw new Error(`LinkedIn ${res.status}`);
  const posts = (await res.json()).elements || [];

  // 2. Filter shareable
  const shareable = posts
    .filter(p => p.commentary && p.commentary.length >= 50)
    .map(p => ({
      urn: p.id, commentary: p.commentary,
      content_type: p.content?.contentType || "NONE",
    }));

  if (!shareable.length) throw new Error("No shareable posts found.");

  // 3. Conversational Brand Voice
  const voiceSamples = `I've been at [Company] for two years now, and this is the kind of work that makes me proud. We just shipped something that actually changes how our customers work.\n\n---\n\nHot take: most marketing analytics tools are built for dashboards, not decisions. We built the opposite.\n\n---\n\nThree things I learned this quarter:\n1. The data isn't the problem — it's getting from data to action\n2. Speed matters more than precision\n3. Teams that automate reporting spend 60% more time on strategy`;

  const bv = await fetch(`${MV_BASE}/brand-voices`, {
    method: "POST", headers: MV_H,
    body: JSON.stringify({ name: "Employee Advocacy Voice — Conversational", samples: [voiceSamples] }),
  }).then(r => r.json());
  console.log(`Brand Voice: ${bv.id}`);

  // 4. Generate employee variants
  const allVariants = [];
  for (const post of shareable.slice(0, 5)) {
    const gen = await fetch(`${MV_BASE}/generations`, {
      method: "POST", headers: MV_H,
      body: JSON.stringify({
        brand_voice_id: bv.id,
        prompt: `Rewrite this company post for employees to share personally.\n\nORIGINAL:\n${post.commentary.slice(0, 600)}\n\nRules:\n- First person ("I", "we", "my team")\n- Personal take, not just reshare\n- Under 200 words\n- Hook first line — no "Excited to announce"\n- End with question\n- 3 variants: (1) personal story, (2) hot take, (3) lesson learned`,
        count: 3,
      }),
    }).then(r => r.json());

    allVariants.push({
      original: post.commentary.slice(0, 200),
      urn: post.urn,
      variants: (gen.results || [gen]).map(v => (v.content || v.text || "").slice(0, 500)),
    });
    await new Promise(r => setTimeout(r, 500));
  }

  // 5. Output
  const labels = ["Personal Story", "Hot Take", "Lesson Learned"];
  for (const entry of allVariants) {
    console.log(`\n${"=".repeat(60)}`);
    console.log(`ORIGINAL: ${entry.original.slice(0, 120)}...`);
    console.log("=".repeat(60));
    entry.variants.forEach((v, j) => {
      console.log(`\n  [${labels[j] || `Variant ${j + 1}`}]`);
      console.log(`  ${v}`);
    });
  }

  const total = allVariants.reduce((s, e) => s + e.variants.length, 0);
  console.log(`\n--- Generated ${total} employee variants for ${allVariants.length} posts ---`);
  ```
</CodeGroup>

## Example Output

```text theme={"dark"}
Brand Voice: bv_emp_adv_7x3k

============================================================
ORIGINAL: We're proud to announce our Series B funding of $45M led by...
============================================================

  [Personal Story]
  Two years ago I joined a 12-person team with a big bet on marketing
  intelligence. Today we announced our Series B — $45M to keep building.

  What convinced me to stay wasn't the funding. It was watching a customer
  cancel three other tools after one month with us. That's the kind of
  product-market fit you can feel.

  If you're building in MarTech, I'd love to hear — what made you stay at
  your company past year one?

  [Hot Take]
  $45M is great. But here's what matters more than the number:

  We're not raising to find product-market fit. We're raising because
  customers keep asking us to do more. 200+ teams. 94% retention. That's
  the story behind the press release.

  Funding announcements are noise. Retention is signal. What metrics do
  you actually care about when evaluating a vendor?

  [Lesson Learned]
  Three things I've learned on the road to Series B:
  1. Customers who churned taught us more than customers who stayed
  2. The feature nobody asked for became our top differentiator
  3. "Move fast and break things" is wrong — move fast and fix things

  We just raised $45M to keep doing exactly this. What's the most
  counterintuitive lesson from your company's growth?
```

## Error Handling

<AccordionGroup>
  <Accordion title="Brand Voice sample quality">The employee voice samples define the output tone. Generic samples produce generic rewrites. Include 3–5 real examples of how your best employees already post on LinkedIn.</Accordion>
  <Accordion title="Post length for mobile">LinkedIn truncates posts at \~210 characters on mobile with a "see more" fold. The prompt targets under 200 words total, but the hook (first line) should be under 150 characters to display fully.</Accordion>
  <Accordion title="Compliance and legal review">Employee advocacy content should be reviewed by legal/comms before distribution, especially for regulated industries (finance, healthcare). Add a review step before publishing.</Accordion>
  <Accordion title="Reusing an existing Brand Voice">To avoid creating duplicate voices, check first: `GET /api/v1/brand-voices?search=Employee+Advocacy`. If one exists, pass its `id` directly to the generation call.</Accordion>
</AccordionGroup>

***

<CardGroup cols={2}>
  <Card title="LinkedIn Content Integration" icon="arrow-left" href="/integrations/linkedin-content" />

  <Card title="Brand Voice" icon="microphone" href="/features/brand-voice" />
</CardGroup>
