Skip to main content

Scenario

Your BigCommerce store has hundreds of product reviews across your catalog. You pull reviews for your top products, batch them through Mavera Chat with a customer persona and structured JSON output, and get sentiment scores, recurring themes, and actionable recommendations — ready for a brand health dashboard. Flow: BigCommerce GET /v3/catalog/products/{id}/reviews → Paginate across products → Batch into Mavera Chat (structured output) → Sentiment, themes, recommendations

Architecture

Code

import os, json, requests, time
from openai import OpenAI

STORE = os.environ["BIGCOMMERCE_STORE_HASH"]
BC_TOKEN = os.environ["BIGCOMMERCE_ACCESS_TOKEN"]
MV = os.environ["MAVERA_API_KEY"]
BC = f"https://api.bigcommerce.com/stores/{STORE}/v3"
BC_HEADERS = {"X-Auth-Token": BC_TOKEN, "Content-Type": "application/json", "Accept": "application/json"}

products = requests.get(f"{BC}/catalog/products",
    headers=BC_HEADERS,
    params={"sort": "total_sold", "direction": "desc", "limit": 10},
).json().get("data", [])

all_reviews = []
for prod in products:
    page = 1
    while True:
        r = requests.get(f"{BC}/catalog/products/{prod['id']}/reviews",
            headers=BC_HEADERS, params={"page": page, "limit": 50})
        if r.status_code == 429:
            time.sleep(2); continue
        r.raise_for_status()
        batch = r.json().get("data", [])
        for rev in batch:
            all_reviews.append({
                "product": prod["name"], "rating": rev["rating"],
                "title": rev.get("title", ""), "text": rev.get("text", "")[:300],
            })
        if len(batch) < 50: break
        page += 1
        time.sleep(0.2)

mavera = OpenAI(api_key=MV, base_url="https://app.mavera.io/api/v1")
schema = {"type": "json_schema", "json_schema": {"name": "brand_health", "strict": True, "schema": {
    "type": "object", "required": ["overall_sentiment", "themes", "recommendations"],
    "properties": {
        "overall_sentiment": {"type": "number"},
        "themes": {"type": "array", "items": {"type": "object",
            "required": ["theme", "frequency", "avg_sentiment", "sample_quote"],
            "properties": {"theme": {"type": "string"}, "frequency": {"type": "number"},
                "avg_sentiment": {"type": "number"}, "sample_quote": {"type": "string"}}}},
        "recommendations": {"type": "array", "items": {"type": "string"}},
    }}}}

review_block = "\n".join(f"[{r['rating']}/5] {r['product']}: {r['title']}{r['text']}"
    for r in all_reviews[:80])

result = mavera.responses.create(model="mavera-1",
    input=[{"role": "user", "content": f"Analyze {len(all_reviews)} product reviews for brand health.\n\n{review_block}"}],
    extra_body={"persona_id": os.environ.get("CUSTOMER_PERSONA_ID", ""), "response_format": schema})

health = json.loads(result.output[0].content[0].text)
print(f"Overall sentiment: {health['overall_sentiment']}/10")
for t in health["themes"][:5]:
    print(f"  {t['theme']} (n={t['frequency']}, sentiment={t['avg_sentiment']})")
for rec in health["recommendations"]:
    print(f"  → {rec}")

Example Output

{
  "overall_sentiment": 7.4,
  "themes": [
    { "theme": "Product quality", "frequency": 38, "avg_sentiment": 8.1, "sample_quote": "Build quality exceeded expectations at this price point" },
    { "theme": "Shipping speed", "frequency": 24, "avg_sentiment": 6.2, "sample_quote": "Took 12 days to arrive, expected faster for the premium tier" },
    { "theme": "Sizing accuracy", "frequency": 19, "avg_sentiment": 5.8, "sample_quote": "Runs a full size small — had to exchange twice" },
    { "theme": "Customer support", "frequency": 14, "avg_sentiment": 8.6, "sample_quote": "Support team resolved my issue within hours" }
  ],
  "recommendations": [
    "Add detailed sizing guide with measurements to product pages — sizing complaints drive 30% of negative reviews",
    "Highlight shipping timelines on checkout page to set expectations",
    "Feature customer support responsiveness in marketing — 8.6 avg sentiment is a differentiator"
  ]
}

Error Handling

Not all products have reviews enabled. Filter with reviews_count > 0 on the catalog products endpoint before fetching reviews.
BigCommerce returns X-Rate-Limit-Time-Reset-Ms in response headers. Use this for precise retry timing instead of fixed sleeps.