Scenario
Your store has years of order history with seasonal patterns — holiday spikes, summer slowdowns, back-to-school surges. You pull historical orders, aggregate revenue and order count by month, then feed that data to Mave Agent for a campaign calendar with timing, messaging themes, and budget allocation.Architecture
Code
import os, requests
from collections import defaultdict
STORE = os.environ["SHOPIFY_STORE"]
TOKEN = os.environ["SHOPIFY_ACCESS_TOKEN"]
MV = os.environ["MAVERA_API_KEY"]
SH = f"https://{STORE}.myshopify.com/admin/api/2024-10/graphql.json"
SH_H = {"X-Shopify-Access-Token": TOKEN, "Content-Type": "application/json"}
MB = "https://app.mavera.io/api/v1"
MH = {"Authorization": f"Bearer {MV}", "Content-Type": "application/json"}
QUERY = """query ($cursor: String) {
orders(first: 250, after: $cursor, sortKey: CREATED_AT, query: "created_at:>2023-01-01") {
edges { node { createdAt totalPriceSet { shopMoney { amount } } lineItems(first: 3) { edges { node { title quantity } } } } }
pageInfo { hasNextPage endCursor }
}
}"""
orders, cursor = [], None
while True:
resp = requests.post(SH, json={"query": QUERY, "variables": {"cursor": cursor} if cursor else {}}, headers=SH_H)
resp.raise_for_status()
data = resp.json()["data"]["orders"]
orders.extend(e["node"] for e in data["edges"])
if not data["pageInfo"]["hasNextPage"]: break
cursor = data["pageInfo"]["endCursor"]
monthly = defaultdict(lambda: {"revenue": 0, "orders": 0, "items": defaultdict(int)})
for o in orders:
k = o["createdAt"][:7]
monthly[k]["revenue"] += float(o["totalPriceSet"]["shopMoney"]["amount"])
monthly[k]["orders"] += 1
for li in o["lineItems"]["edges"]:
monthly[k]["items"][li["node"]["title"]] += li["node"]["quantity"]
lines = ["Month | Orders | Revenue | AOV | Top Product", "------|--------|---------|-----|------------"]
for m, d in sorted(monthly.items()):
top = max(d["items"], key=d["items"].get) if d["items"] else "N/A"
lines.append(f"{m} | {d['orders']} | ${d['revenue']:.0f} | ${d['revenue']/d['orders']:.0f} | {top}")
summary = "\n".join(lines)
print(summary)
plan = requests.post(f"{MB}/mave/chat", json={"input": [
{"role": "system", "content": "Senior marketing strategist. Given monthly sales data, create a 12-month campaign calendar. Per campaign: timing, theme, audience, messaging, budget share (%)."},
{"role": "user", "content": f"Sales data:\n\n{summary}\n\nCreate campaign calendar for next 12 months."},
]}, headers=MH)
plan.raise_for_status()
print(f"\n--- Campaign Plan ---\n{plan.json()['choices'][0]['message']['content']}")
const STORE = process.env.SHOPIFY_STORE, TOKEN = process.env.SHOPIFY_ACCESS_TOKEN, MV = process.env.MAVERA_API_KEY;
const SH = `https://${STORE}.myshopify.com/admin/api/2024-10/graphql.json`;
const MB = "https://app.mavera.io/api/v1";
const MH = { Authorization: `Bearer ${MV}`, "Content-Type": "application/json" };
const QUERY = `query($cursor:String){orders(first:250,after:$cursor,sortKey:CREATED_AT,query:"created_at:>2023-01-01"){edges{node{createdAt totalPriceSet{shopMoney{amount}} lineItems(first:3){edges{node{title quantity}}}}} pageInfo{hasNextPage endCursor}}}`;
(async () => {
const orders = []; let cursor = null;
while (true) {
const resp = await fetch(SH, { method: "POST", headers: { "X-Shopify-Access-Token": TOKEN, "Content-Type": "application/json" }, body: JSON.stringify({ query: QUERY, variables: cursor ? { cursor } : {} }) });
const data = (await resp.json()).data.orders;
for (const e of data.edges) orders.push(e.node);
if (!data.pageInfo.hasNextPage) break;
cursor = data.pageInfo.endCursor;
}
const monthly = {};
for (const o of orders) {
const k = o.createdAt.slice(0, 7);
monthly[k] ??= { revenue: 0, orders: 0, items: {} };
monthly[k].revenue += parseFloat(o.totalPriceSet.shopMoney.amount);
monthly[k].orders += 1;
for (const li of o.lineItems.edges) monthly[k].items[li.node.title] = (monthly[k].items[li.node.title] || 0) + li.node.quantity;
}
const lines = ["Month | Orders | Revenue | AOV | Top Product", "------|--------|---------|-----|------------"];
for (const [m, d] of Object.entries(monthly).sort()) {
const top = Object.entries(d.items).sort((a, b) => b[1] - a[1])[0]?.[0] || "N/A";
lines.push(`${m} | ${d.orders} | $${d.revenue.toFixed(0)} | $${(d.revenue / d.orders).toFixed(0)} | ${top}`);
}
const summary = lines.join("\n");
console.log(summary);
const plan = await fetch(`${MB}/mave/chat`, { method: "POST", headers: MH, body: JSON.stringify({ input: [
{ role: "system", content: "Senior marketing strategist. Given monthly sales, create 12-month campaign calendar. Per campaign: timing, theme, audience, messaging, budget share (%)." },
{ role: "user", content: `Sales data:\n\n${summary}\n\nCreate campaign calendar.` }
] }) });
console.log("\n--- Campaign Plan ---\n" + (await plan.json()).output[0].content[0].text);
})();
Example Output
Month | Orders | Revenue | AOV | Top Product
------|--------|---------|-----|------------
2024-01 | 285 | $34200 | $120 | Merino Base Layer
2024-11 | 487 | $72100 | $148 | Down Expedition Parka
2024-12 | 623 | $99680 | $160 | Gift Card Bundle
--- Campaign Plan ---
## Q4: Peak Season (Nov–Dec) — 40% budget
- Nov 1–15: Early bird holiday sale — VIP first access
- BFCM: Best-sellers with bundle offers
- Dec 1–20: Gift guide segmented by price range
Error Handling
Query cost for large order histories
Query cost for large order histories
Fetching 250 orders with line items costs 20–30 query points per request. Monitor
extensions.cost.throttleStatus.currentlyAvailable. For 50k+ orders, filter by quarterly date ranges or use Shopify Bulk Operations.Mave Agent response truncated
Mave Agent response truncated
If the summary exceeds the context window, aggregate quarterly instead of monthly and limit to top 3 products per period. Split into two calls — pattern identification, then campaign planning.