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

# Seasonal Sales → Campaign Planning

> Use Shopify historical order data with Mavera to generate data-driven seasonal campaign calendars

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

```mermaid theme={"dark"}
flowchart LR
A["GraphQL: historical orders"] --> B["Aggregate by month"] --> C["POST /api/v1/mave/chat"] --> D["Seasonal campaign calendar"]
```

### Code

<CodeGroup>
  ```python Python theme={"dark"}
  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']}")
  ```

  ```javascript JavaScript theme={"dark"}
  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);
  })();
  ```
</CodeGroup>

### Example Output

```text theme={"dark"}
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

<AccordionGroup>
  <Accordion title="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.
  </Accordion>

  <Accordion title="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.
  </Accordion>
</AccordionGroup>
