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}")