{
  "name": "Give slow sellers fresh imagery monthly - instead of a discount",
  "nodes": [
    {
      "parameters": {
        "rule": {
          "interval": [
            {
              "field": "cronExpression",
              "expression": "0 9 1 * *"
            }
          ]
        }
      },
      "id": "57437ca5-e5ae-49fe-bb95-484668bfe11f",
      "name": "Monthly (1st, 09:00)",
      "type": "n8n-nodes-base.scheduleTrigger",
      "typeVersion": 1.2,
      "position": [
        -256,
        0
      ]
    },
    {
      "parameters": {
        "authentication": "accessToken",
        "operation": "getAll",
        "limit": 250,
        "options": {
          "status": "any"
        }
      },
      "id": "b47db044-db2f-4e67-925e-43d3c2eac15a",
      "name": "Get Recent Orders",
      "type": "n8n-nodes-base.shopify",
      "typeVersion": 1,
      "position": [
        -32,
        0
      ]
    },
    {
      "parameters": {
        "authentication": "accessToken",
        "resource": "product",
        "operation": "getAll",
        "returnAll": true,
        "additionalFields": {}
      },
      "id": "0ed34b35-2761-4676-a586-d514af344049",
      "name": "Get Products",
      "type": "n8n-nodes-base.shopify",
      "typeVersion": 1,
      "position": [
        192,
        0
      ],
      "executeOnce": true
    },
    {
      "parameters": {
        "jsCode": "const cutoff = Date.now() - 30*24*3600*1000;\nconst sold = new Set();\nfor (const item of $('Get Recent Orders').all()) {\n  const o = item.json;\n  if (new Date(o.created_at).getTime() < cutoff) continue;\n  for (const li of (o.line_items || [])) if (li.product_id) sold.add(String(li.product_id));\n}\nconst slow = $('Get Products').all()\n  .map(i => i.json)\n  .filter(p => !sold.has(String(p.id)) && (p.images || []).length > 0)\n  .slice(0, 5);\nreturn slow.map(p => ({ json: p }));"
      },
      "id": "20efc644-d484-4ef5-abfb-8faba2f2e32f",
      "name": "Find Slow Movers",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        416,
        0
      ]
    },
    {
      "parameters": {
        "authentication": "oAuth2",
        "select": "channel",
        "channelId": {
          "__rl": true,
          "mode": "list",
          "value": ""
        },
        "text": "Slow-mover refresh complete — up to 5 products with no sales in 30 days got fresh on-model imagery.",
        "otherOptions": {}
      },
      "id": "d0b5a8cd-0e04-4d38-afe6-e74d6d131208",
      "name": "Refresh Complete",
      "type": "n8n-nodes-base.slack",
      "typeVersion": 2.5,
      "position": [
        1168,
        -368
      ]
    },
    {
      "parameters": {
        "authentication": "apiKey",
        "talentId": "b2c80190-4a00-4718-9d3f-c531472d5984",
        "shotCodes": [
          "model_front_women"
        ],
        "frontImageUrl": "={{ $json.images[0].src }}",
        "outputFormat": "jpeg",
        "outputAspectRatio": 5,
        "callbackUrl": "={{ $execution.resumeUrl }}",
        "operation": "generateModelShots"
      },
      "id": "449c5e56-6ff6-408f-9f0c-c51edb72f54e",
      "name": "Generate Fresh On-Model",
      "type": "n8n-nodes-dreem.dreem",
      "typeVersion": 1,
      "position": [
        1152,
        16
      ]
    },
    {
      "parameters": {
        "resume": "webhook",
        "httpMethod": "POST",
        "limitWaitTime": true,
        "resumeAmount": 20,
        "resumeUnit": "minutes",
        "options": {}
      },
      "id": "f6defd08-b4fb-403c-8018-8beb2ded81f0",
      "name": "Wait for Render",
      "type": "n8n-nodes-base.wait",
      "typeVersion": 1.1,
      "position": [
        1360,
        16
      ]
    },
    {
      "parameters": {
        "conditions": {
          "options": {
            "caseSensitive": true,
            "leftValue": "",
            "typeValidation": "loose",
            "version": 1
          },
          "conditions": [
            {
              "leftValue": "={{ $json.body?.status ?? $json.status }}",
              "operator": {
                "type": "string",
                "operation": "equals"
              },
              "rightValue": "completed"
            }
          ],
          "combinator": "and"
        },
        "options": {}
      },
      "id": "db20386f-6213-4cb0-8a86-af204e8fc3c1",
      "name": "Is Complete?",
      "type": "n8n-nodes-base.if",
      "typeVersion": 2.2,
      "position": [
        1568,
        16
      ]
    },
    {
      "parameters": {
        "authentication": "accessToken",
        "resource": "product",
        "operation": "update",
        "productId": "={{ $('Loop Over Slow Movers').item.json.id }}",
        "updateFields": {
          "images": "={{ ($('Loop Over Slow Movers').item.json.images || []).map(i => ({ id: i.id })).concat(($('Wait for Render').item.json.body.outputs || []).map(o => ({ src: o.files[0].url }))) }}"
        }
      },
      "id": "732217cb-e4f5-4eec-a598-7421e2427df4",
      "name": "Publish to Shopify",
      "type": "n8n-nodes-base.shopify",
      "typeVersion": 1,
      "position": [
        1792,
        16
      ]
    },
    {
      "parameters": {
        "options": {}
      },
      "id": "8c5c44ff-c3de-40ba-9094-13f74bcdc87b",
      "name": "Loop Over Slow Movers",
      "type": "n8n-nodes-base.splitInBatches",
      "typeVersion": 3,
      "position": [
        624,
        0
      ]
    },
    {
      "parameters": {
        "authentication": "oAuth2",
        "select": "channel",
        "channelId": {
          "__rl": true,
          "mode": "list",
          "value": ""
        },
        "text": "=Slow-mover refresh skipped *{{ $('Loop Over Slow Movers').item.json.title }}*.",
        "otherOptions": {}
      },
      "id": "62f5bbdd-0b72-4c14-bb22-f19005c711e8",
      "name": "Skipped",
      "type": "n8n-nodes-base.slack",
      "typeVersion": 2.5,
      "position": [
        2176,
        288
      ]
    },
    {
      "parameters": {
        "content": "## 🟡 Slow movers → fresh imagery\nMonthly: finds products with **no sales in 30 days** (from the last 250 orders), takes up to **5**, and generates a fresh on-model shot for each — re-market dead stock instead of discounting.\n\n**Do:** create + pick your credentials (Settings → Credentials) — **Dreem API** (your `dreem_pk_...` key) on *Generate Fresh On-Model* · **Shopify Access Token API** on *Get Recent Orders*, *Get Products* + *Publish to Shopify* · **Slack OAuth2** (on n8n Cloud just press *Connect*; or a *Slack API* bot token — then switch each Slack node's **Authentication** to *Access Token*) on the two Slack nodes. Then set your **model + pose** on the Generate node, pick your Slack **channel** on the two Slack nodes, toggle **Active**. Adjust the batch size (5) in Find Slow Movers.\n\nℹ️ A product that keeps not selling gets a fresh image added **each month** (images accumulate on the product).\n\n⚠️ Your Shopify app needs the **read_orders** scope approved (plus read/write_products) — the orders pull is how slow movers are found.",
        "height": 384,
        "width": 576,
        "color": 7
      },
      "id": "4368cd22-7821-4cdd-b943-2d0d48826f5a",
      "name": "Setup — Start Here",
      "type": "n8n-nodes-base.stickyNote",
      "typeVersion": 1,
      "position": [
        -176,
        240
      ]
    },
    {
      "parameters": {
        "content": "### 🧥 Generate on-model\n**Do:** pick your **model + pose** on this node — `talentId` + `shotCodes` (poses are gendered: `..._men` / `..._women`). Browse all talents & poses at [dreem.ai](https://dreem.ai).\n\nThe product's first image is used as the front automatically.\n\nOptional, on this node:\n- **Output aspect ratio**\n- **Styling Image URLs** — add garment image URLs to style the look (fresh styling can revive a slow mover). **Leave empty and Dreem styles the outfit itself.**",
        "height": 480,
        "width": 340,
        "color": 4
      },
      "id": "619e5d38-0b11-44a3-b758-d227c78f121d",
      "name": "Note — Generate",
      "type": "n8n-nodes-base.stickyNote",
      "typeVersion": 1,
      "position": [
        1056,
        240
      ]
    }
  ],
  "connections": {
    "Get Recent Orders": {
      "main": [
        [
          {
            "node": "Get Products",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Get Products": {
      "main": [
        [
          {
            "node": "Find Slow Movers",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Find Slow Movers": {
      "main": [
        [
          {
            "node": "Loop Over Slow Movers",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Wait for Render": {
      "main": [
        [
          {
            "node": "Is Complete?",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Is Complete?": {
      "main": [
        [
          {
            "node": "Publish to Shopify",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Skipped",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Loop Over Slow Movers": {
      "main": [
        [
          {
            "node": "Refresh Complete",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Generate Fresh On-Model",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Skipped": {
      "main": [
        [
          {
            "node": "Loop Over Slow Movers",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Publish to Shopify": {
      "main": [
        [
          {
            "node": "Loop Over Slow Movers",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Generate Fresh On-Model": {
      "main": [
        [
          {
            "node": "Wait for Render",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Monthly (1st, 09:00)": {
      "main": [
        [
          {
            "node": "Get Recent Orders",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  },
  "settings": {
    "executionOrder": "v1",
    "binaryMode": "separate"
  }
}