{
  "name": "Show every new Shopify product on a virtual model - automatically",
  "nodes": [
    {
      "parameters": {
        "authentication": "accessToken",
        "topic": "products/create"
      },
      "id": "72f61d6a-8238-46af-8a21-0e2e45c59cf9",
      "name": "New Shopify Product",
      "type": "n8n-nodes-base.shopifyTrigger",
      "typeVersion": 1,
      "position": [
        -1264,
        -16
      ]
    },
    {
      "parameters": {
        "authentication": "apiKey",
        "talentId": "b2c80190-4a00-4718-9d3f-c531472d5984",
        "shotCodes": [
          "model_front_women"
        ],
        "frontImageUrl": "={{ $('New Shopify Product').first().json.images[0].src }}",
        "backImageUrl": "={{ $('New Shopify Product').first().json.images?.[1]?.src ?? '' }}",
        "callbackUrl": "={{ $execution.resumeUrl }}",
        "operation": "generateModelShots"
      },
      "id": "060040f1-a340-4ab9-a7e4-70defc65ae6c",
      "name": "Generate On-Model",
      "type": "n8n-nodes-dreem.dreem",
      "typeVersion": 1,
      "position": [
        -848,
        -16
      ],
      "executeOnce": false
    },
    {
      "parameters": {
        "resume": "webhook",
        "httpMethod": "POST",
        "limitWaitTime": true,
        "resumeAmount": 20,
        "resumeUnit": "minutes",
        "options": {}
      },
      "id": "cf3e322b-cc50-46d6-9871-02622009c437",
      "name": "Wait for Render",
      "type": "n8n-nodes-base.wait",
      "typeVersion": 1.1,
      "position": [
        -624,
        0
      ]
    },
    {
      "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": "38fb3872-6769-465d-bf8f-af8a96b7f98f",
      "name": "Is Complete?",
      "type": "n8n-nodes-base.if",
      "typeVersion": 2.2,
      "position": [
        -400,
        0
      ]
    },
    {
      "parameters": {
        "authentication": "oAuth2",
        "operation": "sendAndWait",
        "select": "channel",
        "channelId": {
          "__rl": true,
          "mode": "list",
          "value": ""
        },
        "message": "=Approve the on-model shot above for *{{ $('New Shopify Product').first().json.title }}*? *Approve & publish* adds it to the product; *Reject* skips it. (Link stays valid ~12 hours.)",
        "approvalOptions": {
          "values": {
            "approvalType": "double",
            "approveLabel": "Approve & publish",
            "disapproveLabel": "Reject"
          }
        },
        "options": {
          "limitWaitTime": {
            "values": {
              "resumeAmount": 12,
              "resumeUnit": "hours"
            }
          }
        }
      },
      "id": "36cec573-bbf6-40b1-97ee-a6b563d0ced7",
      "name": "Approve in Slack",
      "type": "n8n-nodes-base.slack",
      "typeVersion": 2.5,
      "position": [
        -64,
        -144
      ],
      "disabled": true
    },
    {
      "parameters": {
        "conditions": {
          "options": {
            "caseSensitive": true,
            "leftValue": "",
            "typeValidation": "loose",
            "version": 1
          },
          "conditions": [
            {
              "leftValue": "={{ $json.data.approved }}",
              "operator": {
                "type": "boolean",
                "operation": "equals"
              },
              "rightValue": true
            }
          ],
          "combinator": "and"
        },
        "options": {}
      },
      "id": "f3d49082-59dc-4f0d-9468-ebf6e8b5db8b",
      "name": "Is Approved?",
      "type": "n8n-nodes-base.if",
      "typeVersion": 2.2,
      "position": [
        176,
        -144
      ],
      "disabled": true
    },
    {
      "parameters": {
        "authentication": "oAuth2",
        "select": "channel",
        "channelId": {
          "__rl": true,
          "mode": "list",
          "value": ""
        },
        "text": "=Dreem on-model render timed out for *{{ $('New Shopify Product').first().json.title }}*. Nothing was published. Check the Dreem dashboard and retry.",
        "otherOptions": {}
      },
      "id": "8f0c0b0d-4f91-457d-9056-c06c27ca3bcd",
      "name": "Timed Out",
      "type": "n8n-nodes-base.slack",
      "typeVersion": 2.5,
      "position": [
        -64,
        160
      ],
      "disabled": true
    },
    {
      "parameters": {
        "content": "## 🟡 Setup — start here\n\nTurns every **new Shopify product** into an **on-model shot** — on the Dreem model you pick — and adds it back to the product (with optional Slack approval).\n\n### 1. Add credentials  (Settings → Credentials)\nThe template ships **without credentials** — create these, then select them on the nodes:\n- **Dreem API** — your `dreem_pk_...` key → select on **Generate On-Model**\n- **Shopify Access Token API** — shop + Admin token (scopes `read_products`, `write_products`) → select on **New Shopify Product** + **Publish to Shopify**\n- **Slack** — create a **Slack OAuth2** credential (on n8n Cloud just press *Connect*) → select + pick your channel on **Post Shot to Slack**, **Approve in Slack** + **Timed Out** if you enable them. (Prefer a bot token? Use a *Slack API* credential and switch each Slack node's **Authentication** to *Access Token*.)\n\n### 2. Pick your model on the **Generate On-Model** node — set `talentId` + `shotCodes` (poses are gendered: `..._men` / `..._women`). Browse all talents & poses at [dreem.ai](https://dreem.ai).\n### 3. Toggle **Active**. Every new product with a photo now gets an on-model shot.\n\n### ⚠️ A few things to be aware of\n- **The product needs at least one photo** — products created without an image are skipped.\n- **Front / back** — the 1st product image is the front; a 2nd image is used as the back where a pose needs it.\n- **Auto-publish by default** — shots go straight to Shopify. Enable **Approve in Slack** for a human check first.\n- **Styling** — Dreem styles the outfit itself; add garment URLs on the Generate node to control it (see the styling note).",
        "height": 636,
        "width": 1620,
        "color": 7
      },
      "id": "8e1e4eda-5635-4a11-ad0e-ca57a6c5b0bf",
      "name": "Setup — Start Here",
      "type": "n8n-nodes-base.stickyNote",
      "typeVersion": 1,
      "position": [
        -1056,
        -992
      ]
    },
    {
      "parameters": {
        "content": "### 1️⃣ New product\nStarts automatically when a **new product** is created in Shopify. **Has Image?** skips products that were created without a photo.\n\n**Do:** select your **Shopify** credential on this node.",
        "height": 308,
        "width": 288,
        "color": 4
      },
      "id": "49546d8a-e2d4-48a6-b168-7d60fb547899",
      "name": "Note 1 — Trigger",
      "type": "n8n-nodes-base.stickyNote",
      "typeVersion": 1,
      "position": [
        -1312,
        176
      ]
    },
    {
      "parameters": {
        "content": "### 2️⃣ 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\nFront image is used automatically (+ back image if the product has a 2nd photo).\n\nOptional, on this node:\n- **Output aspect ratio**\n- **Styling Image URLs** (see styling note)",
        "height": 432,
        "width": 296,
        "color": 4
      },
      "id": "b21c7d78-a501-457a-8ba9-c3e45a6e2e0b",
      "name": "Note 2 — Generate",
      "type": "n8n-nodes-base.stickyNote",
      "typeVersion": 1,
      "position": [
        -960,
        224
      ]
    },
    {
      "parameters": {
        "content": "### 3️⃣ Wait for the result\nDreem renders in the background and calls back when ready (up to **20 min**). **Wait for Render** pauses until then; **Is Complete?** checks it finished.\n\n**Do:** nothing — automatic. Optional: enable the **Timed Out** node (needs the Slack credential) to get an alert if a render times out.",
        "height": 242,
        "width": 566,
        "color": 5
      },
      "id": "95fe15fb-e4e4-43f5-a4dc-b714c33f8fa3",
      "name": "Note 3 — Poll",
      "type": "n8n-nodes-base.stickyNote",
      "typeVersion": 1,
      "position": [
        -640,
        192
      ]
    },
    {
      "parameters": {
        "content": "### 4️⃣ Approve in Slack (optional)\n**Off by default** → images publish straight to Shopify.\n\n**For a human check:** right-click **Post Shot to Slack**, **Approve in Slack** + **Is Approved?** → **Activate**, and pick your **channel** on the two Slack nodes. The shot link posts first; the approval card follows with **Approve / Reject**.",
        "height": 384,
        "width": 360,
        "color": 3
      },
      "id": "06c46530-6c9c-4002-8003-fe84d75b16a8",
      "name": "Note 4 — Approve",
      "type": "n8n-nodes-base.stickyNote",
      "typeVersion": 1,
      "position": [
        -112,
        -608
      ]
    },
    {
      "parameters": {
        "content": "### 5️⃣ Publish to Shopify\nAdds the finished on-model shot to the product, **keeping existing photos**.\n\n**Do:** select your **Shopify** credential on this node (the same one as on the trigger).",
        "height": 170,
        "width": 260,
        "color": 6
      },
      "id": "0a213a91-0cc8-4ce5-b491-7c651cc1ecce",
      "name": "Note 5 — Publish",
      "type": "n8n-nodes-base.stickyNote",
      "typeVersion": 1,
      "position": [
        336,
        -400
      ]
    },
    {
      "parameters": {
        "authentication": "accessToken",
        "resource": "product",
        "operation": "update",
        "productId": "={{ $('New Shopify Product').first().json.id }}",
        "updateFields": {
          "images": "={{ ($('New Shopify Product').first().json.images || []).map(i => ({ id: i.id })).concat([{ src: $('Wait for Render').first().json.body.outputs[0].files[0].url }]) }}"
        }
      },
      "id": "a4ffd8d5-15b4-4125-88ae-43870a548609",
      "name": "Publish to Shopify",
      "type": "n8n-nodes-base.shopify",
      "typeVersion": 1,
      "position": [
        416,
        -144
      ]
    },
    {
      "parameters": {
        "content": "### 🧥 Styling (optional)\n**Styling Image URLs** on the Generate node: add garment image URLs to style the look with (e.g. pair with another product). **Leave empty and Dreem styles the outfit itself.**\n\nBrowse all talents & poses at [dreem.ai](https://dreem.ai).",
        "height": 232,
        "width": 404,
        "color": 5
      },
      "id": "65896a5c-e3f3-46f2-9159-0da0b86f45b0",
      "name": "Note — Styling",
      "type": "n8n-nodes-base.stickyNote",
      "typeVersion": 1,
      "position": [
        -350,
        512
      ]
    },
    {
      "parameters": {
        "conditions": {
          "options": {
            "caseSensitive": true,
            "leftValue": "",
            "typeValidation": "strict",
            "version": 2
          },
          "conditions": [
            {
              "id": "has-image-1",
              "leftValue": "={{ $json.images?.[0]?.src ?? '' }}",
              "rightValue": "",
              "operator": {
                "type": "string",
                "operation": "notEmpty",
                "singleValue": true
              }
            }
          ],
          "combinator": "and"
        },
        "options": {}
      },
      "id": "138d011f-f170-4bcf-897f-1e20521889ee",
      "name": "Has Image?",
      "type": "n8n-nodes-base.if",
      "typeVersion": 2.2,
      "position": [
        -1072,
        -16
      ]
    },
    {
      "parameters": {
        "authentication": "oAuth2",
        "select": "channel",
        "channelId": {
          "__rl": true,
          "mode": "list",
          "value": ""
        },
        "text": "=*New Dreem on-model shot* for *{{ $('New Shopify Product').first().json.title }}*\n{{ $('Wait for Render').first().json.body?.outputs?.[0]?.files?.[0]?.url ?? $('Wait for Render').first().json.outputs?.[0]?.files?.[0]?.url }}",
        "otherOptions": {}
      },
      "id": "b8bc36e6-9d69-522f-b2f8-11e805d3e47c",
      "name": "Post Shot to Slack",
      "type": "n8n-nodes-base.slack",
      "typeVersion": 2.5,
      "position": [
        -304,
        -320
      ],
      "disabled": true
    }
  ],
  "connections": {
    "Is Complete?": {
      "main": [
        [
          {
            "node": "Post Shot to Slack",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Timed Out",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Approve in Slack": {
      "main": [
        [
          {
            "node": "Is Approved?",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Wait for Render": {
      "main": [
        [
          {
            "node": "Is Complete?",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Is Approved?": {
      "main": [
        [
          {
            "node": "Publish to Shopify",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "New Shopify Product": {
      "main": [
        [
          {
            "node": "Has Image?",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Has Image?": {
      "main": [
        [
          {
            "node": "Generate On-Model",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Generate On-Model": {
      "main": [
        [
          {
            "node": "Wait for Render",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Post Shot to Slack": {
      "main": [
        [
          {
            "node": "Approve in Slack",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  },
  "settings": {
    "executionOrder": "v1",
    "binaryMode": "separate"
  }
}
