Skip to main content

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.

Scenario

Your 50+ published blog posts represent your established voice. Instead of writing a brand guide manually, you pull blog URLs from HubSpot CMS, pass them into Mavera’s Brand Voice endpoint, and get a voice profile for all future content generation.

Architecture

Code

import os, requests, time
from openai import OpenAI

HS = os.environ["HUBSPOT_ACCESS_TOKEN"]
MV = os.environ["MAVERA_API_KEY"]
MB = "https://app.mavera.io/api/v1"

# 1. Published blog posts
posts = requests.get("https://api.hubapi.com/cms/v3/blogs/posts",
    headers={"Authorization": f"Bearer {HS}"},
    params={"state": "PUBLISHED", "sort": "-publishDate", "limit": 30,
            "property": "name,url,postSummary,postBody"},
).json().get("results", [])

urls = [p["url"] for p in posts if p.get("url")]
samples = [f"Title: {p.get('name','')}\n{p.get('postSummary','') or p.get('postBody','')[:500]}"
           for p in posts if p.get("postSummary") or p.get("postBody")]

# 2. Create Brand Voice
payload = {"name": "HubSpot Blog Voice", "urls": urls[:15]}
if samples:
    payload["samples"] = ["\n\n---\n\n".join(samples[:10])]

bv = requests.post(f"{MB}/brand-voices",
    headers={"Authorization": f"Bearer {MV}", "Content-Type": "application/json"},
    json=payload).json()
print(f"Brand Voice: {bv['id']}")

# 3. Verify status
time.sleep(3)
detail = requests.get(f"{MB}/brand-voices/{bv['id']}",
    headers={"Authorization": f"Bearer {MV}"}).json()
print(f"Status: {detail.get('status','unknown')}")

# 4. Test generation
mavera = OpenAI(api_key=MV, base_url=MB)
test = mavera.responses.create(model="mavera-1",
    input=[{"role": "user", "content": "Write a 100-word blog intro about AI in marketing."}],
    extra_body={"brand_voice_id": bv["id"]})
print(f"\n{test.output[0].content[0].text}")

Example Output

Brand Voice: bv_blog_8k2m (status: ready)

AI isn't coming for your marketing job — it's coming for the busywork that
keeps you from doing it well. We've seen teams go from 60% reporting to 60%
strategy. That's not marginal — it's fundamental. Here's what we're seeing.

Error Handling

Blogs endpoint needs content scope. Add in HubSpot Settings → Private Apps → Scopes if you get 403.
Mavera can’t crawl protected pages. Pass postBody HTML as samples text instead of URLs.

HubSpot Integration

Brand Voice API