{
  "name": "Give every new Shopify product studio photos + an on-model shot",
  "nodes": [
    {
      "parameters": {
        "authentication": "accessToken",
        "topic": "products/create"
      },
      "id": "23170400-b084-44aa-883a-29048fa6e6a6",
      "name": "New Shopify Product",
      "type": "n8n-nodes-base.shopifyTrigger",
      "typeVersion": 1,
      "position": [
        -432,
        0
      ]
    },
    {
      "parameters": {
        "authentication": "apiKey",
        "operation": "generateProductShots",
        "shotCodes": [
          "flat_lay_front",
          "invisible_mannequin_front"
        ],
        "frontImageUrl": "={{ $json.images[0].src }}",
        "backImageUrl": "={{ $json.images?.[1]?.src ?? '' }}",
        "outputFormat": "jpeg",
        "outputAspectRatio": 5,
        "callbackUrl": "={{ $execution.resumeUrl }}"
      },
      "id": "1407f84e-a568-42ec-af04-778ac3571cd6",
      "name": "Generate Front Shots",
      "type": "n8n-nodes-dreem.dreem",
      "typeVersion": 1,
      "position": [
        16,
        0
      ]
    },
    {
      "parameters": {
        "resume": "webhook",
        "httpMethod": "POST",
        "limitWaitTime": true,
        "resumeAmount": 20,
        "resumeUnit": "minutes",
        "options": {}
      },
      "id": "5a8c6e75-41a3-417e-ad89-decda5429be4",
      "name": "Wait Product Shots",
      "type": "n8n-nodes-base.wait",
      "typeVersion": 1.1,
      "position": [
        240,
        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": "4001152d-9b3f-4e16-9892-dff2d904acee",
      "name": "Product Shots Done?",
      "type": "n8n-nodes-base.if",
      "typeVersion": 2.2,
      "position": [
        464,
        0
      ]
    },
    {
      "parameters": {
        "authentication": "apiKey",
        "talentId": "b2c80190-4a00-4718-9d3f-c531472d5984",
        "shotCodes": [
          "model_front_women"
        ],
        "frontImageUrl": "={{ $('Wait Product Shots').first().json.body.outputs[0].files[0].url }}",
        "backImageUrl": "={{ $('New Shopify Product').first().json.images?.[1]?.src ?? '' }}",
        "outputFormat": "jpeg",
        "outputAspectRatio": 5,
        "callbackUrl": "={{ $execution.resumeUrl }}",
        "operation": "generateModelShots"
      },
      "id": "e560f9af-cdef-41b4-bb48-83d5b5766efe",
      "name": "Generate On-Model",
      "type": "n8n-nodes-dreem.dreem",
      "typeVersion": 1,
      "position": [
        688,
        0
      ]
    },
    {
      "parameters": {
        "resume": "webhook",
        "httpMethod": "POST",
        "limitWaitTime": true,
        "resumeAmount": 20,
        "resumeUnit": "minutes",
        "options": {}
      },
      "id": "5449b3f5-01b2-4b6f-a5a9-d7e3e833199d",
      "name": "Wait Model Shots",
      "type": "n8n-nodes-base.wait",
      "typeVersion": 1.1,
      "position": [
        912,
        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": "535c74c8-bb1b-4b47-aa59-278f3d08be9a",
      "name": "Model Shots Done?",
      "type": "n8n-nodes-base.if",
      "typeVersion": 2.2,
      "position": [
        1136,
        0
      ]
    },
    {
      "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(($('Wait Product Shots').first().json.body.outputs || []).map(o => ({ src: o.files[0].url }))).concat(($('Wait Model Shots').first().json.body.outputs || []).map(o => ({ src: o.files[0].url }))) }}"
        }
      },
      "id": "d4f34376-de2e-4dfd-90b7-56c4658aea1f",
      "name": "Publish to Shopify",
      "type": "n8n-nodes-base.shopify",
      "typeVersion": 1,
      "position": [
        1808,
        -144
      ]
    },
    {
      "parameters": {
        "authentication": "oAuth2",
        "select": "channel",
        "channelId": {
          "__rl": true,
          "mode": "list",
          "value": ""
        },
        "text": "=⚠️ Dreem render timed out for *{{ $('New Shopify Product').first().json.title }}*. Nothing was published. Check the Dreem dashboard and retry.",
        "otherOptions": {}
      },
      "id": "64150b63-273d-44f7-8294-21d08c2bc770",
      "name": "Timed Out",
      "type": "n8n-nodes-base.slack",
      "typeVersion": 2.5,
      "position": [
        1360,
        224
      ],
      "disabled": true
    },
    {
      "parameters": {
        "authentication": "apiKey",
        "operation": "generateProductShots",
        "shotCodes": [
          "flat_lay_back",
          "invisible_mannequin_back"
        ],
        "frontImageUrl": "={{ $('New Shopify Product').first().json.images[0].src }}",
        "backImageUrl": "={{ $('New Shopify Product').first().json.images?.[1]?.src ?? '' }}",
        "outputFormat": "jpeg",
        "outputAspectRatio": 5,
        "callbackUrl": "={{ $execution.resumeUrl }}"
      },
      "id": "d5318889-c39a-4a64-87f2-344e65195a5a",
      "name": "Generate Back Shots",
      "type": "n8n-nodes-dreem.dreem",
      "typeVersion": 1,
      "position": [
        1808,
        320
      ],
      "disabled": true
    },
    {
      "parameters": {
        "resume": "webhook",
        "httpMethod": "POST",
        "limitWaitTime": true,
        "resumeAmount": 20,
        "resumeUnit": "minutes",
        "options": {}
      },
      "id": "32703da9-1927-4b54-aeef-450bfded3bda",
      "name": "Wait Back",
      "type": "n8n-nodes-base.wait",
      "typeVersion": 1.1,
      "position": [
        2032,
        320
      ],
      "disabled": true
    },
    {
      "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": "fff1102e-3f74-4d5e-9303-d8d59b639ef6",
      "name": "Back Done?",
      "type": "n8n-nodes-base.if",
      "typeVersion": 2.2,
      "position": [
        2256,
        320
      ],
      "disabled": true
    },
    {
      "parameters": {
        "authentication": "accessToken",
        "resource": "product",
        "operation": "update",
        "productId": "={{ $('New Shopify Product').first().json.id }}",
        "updateFields": {
          "images": "={{ ($('Publish to Shopify').first().json.images || []).map(i => ({ id: i.id })).concat(($('Wait Back').first().json.body.outputs || []).map(o => ({ src: o.files[0].url }))) }}"
        }
      },
      "id": "bfc13c9b-c8e1-4ca6-b1fd-28c63d438750",
      "name": "Publish Back Shots",
      "type": "n8n-nodes-base.shopify",
      "typeVersion": 1,
      "position": [
        2480,
        320
      ],
      "disabled": true
    },
    {
      "parameters": {
        "content": "### 🧥 Styling (optional)\n**Styling Image URLs** on the Generate On-Model 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": 260,
        "width": 380,
        "color": 5
      },
      "id": "cfb6ac6b-8613-471f-8d81-551be6a079d8",
      "name": "Note — Styling",
      "type": "n8n-nodes-base.stickyNote",
      "typeVersion": 1,
      "position": [
        736,
        656
      ]
    },
    {
      "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": "0be936fd-972f-48cc-8408-db45b3ca8025",
      "name": "Has Image?",
      "type": "n8n-nodes-base.if",
      "typeVersion": 2.2,
      "position": [
        -208,
        0
      ]
    },
    {
      "parameters": {
        "authentication": "oAuth2",
        "operation": "sendAndWait",
        "select": "channel",
        "channelId": {
          "__rl": true,
          "mode": "list",
          "value": ""
        },
        "message": "=Approve the imagery above for *{{ $('New Shopify Product').first().json.title }}*? *Approve & publish* adds the product shots + on-model shot to the product; *Reject* skips them. (Links stay valid ~12 hours.)",
        "approvalOptions": {
          "values": {
            "approvalType": "double",
            "approveLabel": "Approve & publish",
            "disapproveLabel": "Reject"
          }
        },
        "options": {
          "limitWaitTime": {
            "values": {
              "resumeAmount": 12,
              "resumeUnit": "hours"
            }
          }
        }
      },
      "id": "97548ef2-5c84-4d56-af52-81cf43d07c46",
      "name": "Approve in Slack",
      "type": "n8n-nodes-base.slack",
      "typeVersion": 2.5,
      "position": [
        1360,
        -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": "cec9f933-8a1b-4a4a-b51e-4ff89b60541e",
      "name": "Is Approved?",
      "type": "n8n-nodes-base.if",
      "typeVersion": 2.2,
      "position": [
        1584,
        -144
      ],
      "disabled": true
    },
    {
      "parameters": {
        "content": "## 🟡 Setup — start here\n\nTurns every **new Shopify product** into **full imagery**: **Product Shots** (studio images of the product only) plus an **on-model shot** — on the Dreem model you pick — all added 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 Front Shots** + **Generate On-Model** (+ **Generate Back Shots** if enabled)\n- **Shopify Access Token API** — shop + Admin token (scopes `read_products`, `write_products`) → select on **New Shopify Product** + **Publish to Shopify** (+ **Publish Back Shots** if enabled)\n- **Slack** — create a **Slack OAuth2** credential (on n8n Cloud just press *Connect*) → select + pick your channel on **Post Images 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 shot types on **Generate Front Shots** (`shotCodes`) — see the 📸 **Shot types** note for the full menu.\n### 3. 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### 4. Toggle **Active**. Every new product with a photo now gets product shots + 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 product's **1st image** is the front, its **2nd image** the back. Product Shots are unisex — gender only applies to the on-model shot.\n- **The model wears your fresh render** — the on-model shot uses the first generated product shot as its garment input, not your raw upload.\n- **Aspect ratio** — set the output shape on the Generate nodes (e.g. 4:5 for PDP).\n- **Auto-publish by default** — images go straight to Shopify. Enable **Approve in Slack** for a human check first.",
        "height": 760,
        "width": 840,
        "color": 7
      },
      "id": "5cef5639-3dc1-4021-8bda-800737cc25d3",
      "name": "Setup — Start Here",
      "type": "n8n-nodes-base.stickyNote",
      "typeVersion": 1,
      "position": [
        -1440,
        -896
      ]
    },
    {
      "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": 320,
        "width": 300,
        "color": 4
      },
      "id": "1305a2c3-7c85-4770-85a0-1d8dbe252031",
      "name": "Note 1 — Trigger",
      "type": "n8n-nodes-base.stickyNote",
      "typeVersion": 1,
      "position": [
        -480,
        176
      ]
    },
    {
      "parameters": {
        "content": "### 2️⃣ Product shots first\n**Generate Front Shots** renders studio images of the product (no model) from its **1st image**. Pick codes from the 📸 **Shot types** note. Defaults: `flat_lay_front` + `invisible_mannequin_front`.\n\nBack-facing shots are optional — see the **Back shots** row at the end.",
        "height": 340,
        "width": 300,
        "color": 4
      },
      "id": "cae672c0-833e-4e8d-9d59-957857ca10ec",
      "name": "Note 2 — Product Shots",
      "type": "n8n-nodes-base.stickyNote",
      "typeVersion": 1,
      "position": [
        -32,
        176
      ]
    },
    {
      "parameters": {
        "content": "### ⏳ Wait for the result\nDreem renders in the background and calls back when ready (up to **20 min** per render). The **Wait** nodes pause; the **Done?** nodes check it finished.\n\n**Do:** nothing — automatic. Optional: enable **Timed Out** (needs the Slack credential) to get an alert if a render times out.",
        "height": 280,
        "width": 400,
        "color": 5
      },
      "id": "5bc467cb-5492-4994-b918-73ba5b13f4b9",
      "name": "Note — Wait",
      "type": "n8n-nodes-base.stickyNote",
      "typeVersion": 1,
      "position": [
        304,
        176
      ]
    },
    {
      "parameters": {
        "content": "### 3️⃣ 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 model wears your **freshly generated product shot** (the first front shot) — a clean studio input instead of your raw upload.\n\nOptional, on this node:\n- **Output aspect ratio**\n- **Styling Image URLs** (see styling note)",
        "height": 444,
        "width": 348,
        "color": 4
      },
      "id": "e67380b3-ce6b-47e6-8cc8-9229b03bb21d",
      "name": "Note 3 — On-Model",
      "type": "n8n-nodes-base.stickyNote",
      "typeVersion": 1,
      "position": [
        736,
        176
      ]
    },
    {
      "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 Images to Slack**, **Approve in Slack** + **Is Approved?** → **Activate**, and pick your **channel** on the two Slack nodes. Links to every generated image post first; the approval card follows with **Approve / Reject**.",
        "height": 384,
        "width": 360,
        "color": 3
      },
      "id": "a80837a5-4f9c-4ff1-9f64-47a7d89215f8",
      "name": "Note 4 — Approve",
      "type": "n8n-nodes-base.stickyNote",
      "typeVersion": 1,
      "position": [
        1264,
        -560
      ]
    },
    {
      "parameters": {
        "content": "### 5️⃣ Publish to Shopify\nAdds all finished images — product shots + the 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": 300,
        "width": 400,
        "color": 6
      },
      "id": "0154e6a3-377c-4a98-bf9b-6eeab21b6da0",
      "name": "Note 5 — Publish",
      "type": "n8n-nodes-base.stickyNote",
      "typeVersion": 1,
      "position": [
        1680,
        -560
      ]
    },
    {
      "parameters": {
        "content": "### Back shots (optional, OFF)\nTo also get **back-facing product shots**: enable all 4 nodes in this row (Generate Back Shots → Wait Back → Back Done? → Publish Back Shots) and make sure the product has a **back image as its 2nd image**.",
        "height": 300,
        "width": 460,
        "color": 6
      },
      "id": "be187494-1c6b-480e-9293-23281da576bb",
      "name": "Note — Back Shots",
      "type": "n8n-nodes-base.stickyNote",
      "typeVersion": 1,
      "position": [
        2736,
        320
      ]
    },
    {
      "parameters": {
        "content": "### 📸 Shot types (`shotCodes`) — the full menu\n\n**Garments**\n- `flat_lay_front` — laid flat, front\n- `flat_lay_back` — laid flat, back\n- `invisible_mannequin_front` — 3D \"ghost mannequin\", front\n- `invisible_mannequin_back` — ghost mannequin, back\n- `invisible_mannequin_side` — ghost mannequin, side\n- `side` — side profile\n\n**Footwear**\n- `footwear_34_view` — 3/4 hero angle\n- `footwear_lateral_side_view` — side profile\n- `footwear_back_view` — rear\n- `footwear_top_down_multi_view` — top-down angles\n- `footwear_detail_macro_view` — close-up details\n\n**Rules of thumb:** front codes use the product's **1st image**, back codes its **2nd image**. Product Shots are **unisex** — gender only applies to on-model shots. Browse examples at [dreem.ai](https://dreem.ai).",
        "height": 640,
        "width": 528,
        "color": 4
      },
      "id": "0760f147-5377-41f2-94ac-5d570fee3630",
      "name": "Note — Shot Types",
      "type": "n8n-nodes-base.stickyNote",
      "typeVersion": 1,
      "position": [
        -1440,
        -64
      ]
    },
    {
      "parameters": {
        "authentication": "oAuth2",
        "select": "channel",
        "channelId": {
          "__rl": true,
          "mode": "list",
          "value": ""
        },
        "text": "=*New Dreem imagery* for *{{ $('New Shopify Product').first().json.title }}*\nProduct shots:\n{{ ($('Wait Product Shots').first().json.body?.outputs ?? []).map(o => o.files[0].url).join('\\n') }}\nOn-model:\n{{ ($('Wait Model Shots').first().json.body?.outputs ?? []).map(o => o.files[0].url).join('\\n') }}",
        "otherOptions": {}
      },
      "id": "3590ed9f-eaf8-5c9c-805b-8d2b72c39afb",
      "name": "Post Images to Slack",
      "type": "n8n-nodes-base.slack",
      "typeVersion": 2.5,
      "position": [
        1120,
        -320
      ],
      "disabled": true
    }
  ],
  "connections": {
    "Wait Product Shots": {
      "main": [
        [
          {
            "node": "Product Shots Done?",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Product Shots Done?": {
      "main": [
        [
          {
            "node": "Generate On-Model",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Timed Out",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Wait Model Shots": {
      "main": [
        [
          {
            "node": "Model Shots Done?",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Model Shots Done?": {
      "main": [
        [
          {
            "node": "Post Images to Slack",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Timed Out",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Generate Front Shots": {
      "main": [
        [
          {
            "node": "Wait Product Shots",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Publish to Shopify": {
      "main": [
        [
          {
            "node": "Generate Back Shots",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Generate Back Shots": {
      "main": [
        [
          {
            "node": "Wait Back",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Wait Back": {
      "main": [
        [
          {
            "node": "Back Done?",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Back Done?": {
      "main": [
        [
          {
            "node": "Publish Back Shots",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Timed Out",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "New Shopify Product": {
      "main": [
        [
          {
            "node": "Has Image?",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Has Image?": {
      "main": [
        [
          {
            "node": "Generate Front Shots",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Approve in Slack": {
      "main": [
        [
          {
            "node": "Is Approved?",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Is Approved?": {
      "main": [
        [
          {
            "node": "Publish to Shopify",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Generate On-Model": {
      "main": [
        [
          {
            "node": "Wait Model Shots",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Post Images to Slack": {
      "main": [
        [
          {
            "node": "Approve in Slack",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  },
  "settings": {
    "executionOrder": "v1",
    "binaryMode": "separate"
  }
}