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

# Inventory-Aware Content Prioritization

> Generate urgency-driven marketing copy for high-stock low-velocity Shopify products with Mavera

### Scenario

Products sitting in warehouses need a sales push. You pull inventory levels from Shopify's GraphQL API, identify high-stock / low-velocity items, and generate marketing copy for those products with urgency-appropriate messaging.

### Architecture

```mermaid theme={"dark"}
flowchart LR
A["GraphQL: inventoryLevels"] --> B["Filter: high stock + low velocity"] --> C["POST /api/v1/generations"] --> D["Urgency-driven marketing copy"]
```

### Code

<CodeGroup>
  ```python Python theme={"dark"}
  import os, requests, time

  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 = """{
    productVariants(first: 100) {
      edges { node {
        title product { title productType priceRangeV2 { minVariantPrice { amount currencyCode } } }
        inventoryItem { inventoryLevels(first: 5) { edges { node { available } } } }
      }}
    }
  }"""

  resp = requests.post(SH, json={"query": QUERY}, headers=SH_H)
  resp.raise_for_status()
  variants = []
  for e in resp.json()["data"]["productVariants"]["edges"]:
      n = e["node"]
      stock = sum(l["node"]["available"] for l in n["inventoryItem"]["inventoryLevels"]["edges"])
      if stock >= 50:
          vel = max(1, stock // 48)
          if vel <= 2:
              variants.append({"product": n["product"]["title"], "variant": n["title"], "type": n["product"]["productType"],
                  "price": n["product"]["priceRangeV2"]["minVariantPrice"]["amount"],
                  "currency": n["product"]["priceRangeV2"]["minVariantPrice"]["currencyCode"],
                  "stock": stock, "velocity": vel, "weeks": stock // max(vel, 1)})
  variants.sort(key=lambda x: -x["stock"])
  print(f"{len(variants)} priority items")
  for v in variants[:5]:
      gen = requests.post(f"{MB}/generations", json={"prompt":
          f"Product needing sales push:\n{v['product']} — {v['variant']}\nType: {v['type']}\nPrice: {v['price']} {v['currency']}\nStock: {v['stock']} units, ~{v['velocity']}/wk\n\nWrite: 1) Urgency description (2 sentences) 2) Social ad with CTA 3) Flash sale email subject 4) Banner headline"
      }, headers=MH)
      gen.raise_for_status()
      print(f"\n--- {v['product']} ({v['variant']}) — {v['stock']} units ---\n{gen.json()['text']}")
      time.sleep(0.3)
  ```

  ```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 = `{ productVariants(first:100) { edges { node { title product { title productType priceRangeV2 { minVariantPrice { amount currencyCode } } } inventoryItem { inventoryLevels(first:5) { edges { node { available } } } } } } } }`;

  (async () => {
    const resp = await fetch(SH, { method: "POST", headers: { "X-Shopify-Access-Token": TOKEN, "Content-Type": "application/json" }, body: JSON.stringify({ query: QUERY }) });
    const variants = (await resp.json()).data.productVariants.edges.map(e => {
      const n = e.node, stock = n.inventoryItem.inventoryLevels.edges.reduce((s, l) => s + l.node.available, 0);
      return { product: n.product.title, variant: n.title, type: n.product.productType, price: n.product.priceRangeV2.minVariantPrice.amount, currency: n.product.priceRangeV2.minVariantPrice.currencyCode, stock };
    }).filter(v => v.stock >= 50).map(v => {
      const vel = Math.max(1, Math.floor(v.stock / 48));
      return { ...v, velocity: vel, weeks: Math.floor(v.stock / vel) };
    }).filter(v => v.velocity <= 2).sort((a, b) => b.stock - a.stock);

    console.log(`${variants.length} priority items`);
    for (const v of variants.slice(0, 5)) {
      const gen = await fetch(`${MB}/generations`, { method: "POST", headers: MH, body: JSON.stringify({
        prompt: `Product needing push:\n${v.product} — ${v.variant}\nType: ${v.type}\nPrice: ${v.price} ${v.currency}\nStock: ${v.stock}, ~${v.velocity}/wk\n\nWrite: 1) Urgency description 2) Social ad 3) Flash sale subject 4) Banner headline`
      }) });
      console.log(`\n--- ${v.product} (${v.variant}) — ${v.stock} units ---\n${(await gen.json()).text}`);
      await new Promise(r => setTimeout(r, 300));
    }
  })();
  ```
</CodeGroup>

### Example Output

```text theme={"dark"}
12 priority items

--- Wool Blend Cardigan (Charcoal / L) — 340 units ---
1. The layering piece you'll reach for every cool morning — at a price that won't last. Italian merino-nylon for warmth without bulk.
2. Still searching for the perfect fall layer? Premium merino, relaxed fit, timeless charcoal. Shop now → [link]
3. 72 hours only: The cardigan everyone's eyeing is 25% off
4. Layer Up for Less — Wool Blend Cardigan, Limited-Time Price
```

### Error Handling

<AccordionGroup>
  <Accordion title="Inventory levels require fulfillment scopes">
    `inventoryLevels` requires `read_inventory` scope. Update in Shopify Admin → Settings → Apps → your app → API scopes. Changes take effect immediately.
  </Accordion>

  <Accordion title="Velocity estimation is approximate">
    The code estimates velocity from current stock divided by an assumed time window. For accurate velocity, query order line items per product over 90 days and divide by weeks.
  </Accordion>
</AccordionGroup>
