{
  "name": "Dreem — New Product to Product Shots",
  "nodes": [
    {
      "parameters": {
        "authentication": "accessToken",
        "topic": "products/create"
      },
      "id": "47b9aca0-e4bc-4e41-bcc2-204c9633e197",
      "name": "New Shopify Product",
      "type": "n8n-nodes-base.shopifyTrigger",
      "typeVersion": 1,
      "position": [
        -176,
        0
      ],
      "credentials": {
        "shopifyAccessTokenApi": {
          "name": "Shopify account"
        }
      }
    },
    {
      "parameters": {
        "resume": "webhook",
        "httpMethod": "POST",
        "limitWaitTime": true,
        "resumeAmount": 20,
        "resumeUnit": "minutes",
        "options": {}
      },
      "id": "57a4a1e5-e075-43c5-b91b-cb61a5ebaa8d",
      "name": "Wait for Render",
      "type": "n8n-nodes-base.wait",
      "typeVersion": 1.1,
      "position": [
        480,
        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": "dc6e7d8a-de12-42b0-8ef7-4d695290f590",
      "name": "Is Complete?",
      "type": "n8n-nodes-base.if",
      "typeVersion": 2.2,
      "position": [
        720,
        0
      ]
    },
    {
      "parameters": {
        "authentication": "oAuth2",
        "operation": "sendAndWait",
        "select": "channel",
        "channelId": {
          "__rl": true,
          "value": "",
          "mode": "id"
        },
        "message": "=*New Dreem product shots ready to publish*\nProduct: {{ $('New Shopify Product').item.json.title }}\n{{ $('Wait for Render').item.json.body?.outputs?.[0]?.files?.[0]?.url ?? $('Wait for Render').item.json.outputs?.[0]?.files?.[0]?.url }}",
        "approvalOptions": {
          "values": {
            "approvalType": "double",
            "approveLabel": "Approve & publish",
            "disapproveLabel": "Reject"
          }
        },
        "options": {
          "limitWaitTime": {
            "values": {
              "resumeAmount": 12
            }
          }
        }
      },
      "id": "c7c2e732-aaa0-41fd-8444-65896387b8a6",
      "name": "Approve in Slack",
      "type": "n8n-nodes-base.slack",
      "typeVersion": 2.5,
      "position": [
        1200,
        -144
      ],
      "credentials": {
        "slackOAuth2Api": {
          "name": "Slack account"
        }
      },
      "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": "5fce0c73-4822-4915-8ec8-50cf0be80c95",
      "name": "Is Approved?",
      "type": "n8n-nodes-base.if",
      "typeVersion": 2.2,
      "position": [
        1440,
        -144
      ],
      "disabled": true
    },
    {
      "parameters": {
        "content": "## 🟡 Setup — start here\n\nTurns every **new Shopify product** into **Product Shots** (studio images of the product only — no model), and adds them back to the product (optional Slack approval).\n\n### 1. Add credentials  (Settings → Credentials)\n- **Dreem API** — your `dreem_pk_...` key\n- **Shopify Access Token API** — shop + Admin token (scopes `read_products`, `write_products`)\n- **Slack API** — bot token with `chat:write` (only for optional approval / timeout alerts)\n\n### 2. Pick your shot types on **Generate Front Shots** (`shotCodes`) — see the 📸 **Shot types** note for the full menu. Defaults: `flat_lay_front` + `invisible_mannequin_front`.\n### 3. Toggle **Active**. Every new product with a photo now gets product shots.\n\n### ⚠️ A few things to be aware of\n- **Match the shot to your photo** — every shot code is **front, back, or side**. The product's **1st image** is used as the front, its **2nd image** as the back.\n- **Garment vs footwear** — `flat_lay_*` / `invisible_mannequin_*` are for garments; shoes use the `footwear_*` codes.\n- **Product needs at least one photo** — image-less products are skipped.\n- **Aspect ratio** — set the output shape on the Generate node (e.g. 4:5 for PDP).\n- **Approve or direct** — by default images post **straight to Shopify**. Enable **Approve in Slack** to review each first.",
        "height": 688,
        "width": 820,
        "color": 7
      },
      "id": "7cc27f0e-5df6-4f0f-a1a7-e70676a768ba",
      "name": "Setup — Start Here",
      "type": "n8n-nodes-base.stickyNote",
      "typeVersion": 1,
      "position": [
        -528,
        -992
      ]
    },
    {
      "parameters": {
        "content": "### 1️⃣ New product\nStarts automatically when a **new product** is created in Shopify. **Has Image?** skips products created without a photo.\n\n**Do:** select your **Shopify** credential here.",
        "height": 296,
        "width": 300,
        "color": 4
      },
      "id": "bbdf2b8c-f479-4b15-b3ce-9718621c496b",
      "name": "Note 1 — Trigger",
      "type": "n8n-nodes-base.stickyNote",
      "typeVersion": 1,
      "position": [
        -448,
        176
      ]
    },
    {
      "parameters": {
        "content": "### 2️⃣ Generate — front + back rows\n- **Generate Front Shots** (ON) — front-facing codes; uses the product's **1st image**.\n- **Generate Back Shots** (OFF) — back-facing codes; needs the product's **2nd image** (the back). Enable all 4 nodes in that row to use it.\n\nPick codes from the 📸 **Shot types** note below. The back row runs after the front shots publish.",
        "height": 404,
        "width": 444,
        "color": 4
      },
      "id": "64511d77-f99e-4eb4-a48f-a80af5190e53",
      "name": "Note 2 — Generate",
      "type": "n8n-nodes-base.stickyNote",
      "typeVersion": 1,
      "position": [
        336,
        784
      ]
    },
    {
      "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; **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": 200,
        "width": 680,
        "color": 5
      },
      "id": "2c03d6e3-20bf-467a-8065-51fbbca634ba",
      "name": "Note 3 — Poll",
      "type": "n8n-nodes-base.stickyNote",
      "typeVersion": 1,
      "position": [
        368,
        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 **Approve in Slack** + **Is Approved?** → **Activate**, and set your **Channel ID**. Then each render waits for **Approve / Reject**.",
        "height": 342,
        "width": 336,
        "color": 3
      },
      "id": "f1d881d2-5a8c-4e0e-b7c0-ee1283ab1be6",
      "name": "Note 4 — Approve",
      "type": "n8n-nodes-base.stickyNote",
      "typeVersion": 1,
      "position": [
        1072,
        -528
      ]
    },
    {
      "parameters": {
        "content": "### 5️⃣ Publish to Shopify\nAdds the finished shots to the product, **keeping existing photos**.\n\n**Do:** nothing — the Shopify credential is already set.",
        "height": 260,
        "width": 456,
        "color": 6
      },
      "id": "5d1959f4-f8b5-430d-bdf2-fa1cef57b36d",
      "name": "Note 5 — Publish",
      "type": "n8n-nodes-base.stickyNote",
      "typeVersion": 1,
      "position": [
        1472,
        -480
      ]
    },
    {
      "parameters": {
        "authentication": "oAuth2",
        "select": "channel",
        "channelId": {
          "__rl": true,
          "value": "",
          "mode": "id"
        },
        "text": "=⚠️ Dreem render timed out for *{{ $('New Shopify Product').item.json.title }}*. Nothing was published. Check the Dreem dashboard and retry.",
        "otherOptions": {}
      },
      "id": "7557aaa8-3874-475e-a1d3-47253568187c",
      "name": "Timed Out",
      "type": "n8n-nodes-base.slack",
      "typeVersion": 2.5,
      "position": [
        1440,
        160
      ],
      "credentials": {
        "slackOAuth2Api": {
          "name": "Slack account"
        }
      },
      "disabled": true
    },
    {
      "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": "07b61e65-d973-432f-93e7-1df5339e964d",
      "name": "Generate Front Shots",
      "type": "n8n-nodes-dreem.dreem",
      "typeVersion": 1,
      "position": [
        240,
        0
      ],
      "credentials": {
        "dreemApi": {
          "name": "Dreem API"
        }
      }
    },
    {
      "parameters": {
        "authentication": "accessToken",
        "resource": "product",
        "operation": "update",
        "productId": "={{ $('New Shopify Product').item.json.id }}",
        "updateFields": {
          "images": "={{ ($('New Shopify Product').item.json.images || []).map(i => ({ id: i.id })).concat(($('Wait for Render').item.json.body.outputs || []).map(o => ({ src: o.files[0].url }))) }}"
        }
      },
      "id": "f7dea8f9-7677-437c-ba9e-5064d83b713a",
      "name": "Publish to Shopify",
      "type": "n8n-nodes-base.shopify",
      "typeVersion": 1,
      "position": [
        1680,
        -144
      ],
      "credentials": {
        "shopifyAccessTokenApi": {
          "name": "Shopify account"
        }
      }
    },
    {
      "parameters": {
        "authentication": "apiKey",
        "operation": "generateProductShots",
        "shotCodes": [
          "flat_lay_back",
          "invisible_mannequin_back"
        ],
        "frontImageUrl": "={{ $('New Shopify Product').item.json.images[0].src }}",
        "backImageUrl": "={{ $('New Shopify Product').item.json.images?.[1]?.src ?? '' }}",
        "outputFormat": "jpeg",
        "outputAspectRatio": 5,
        "callbackUrl": "={{ $execution.resumeUrl }}"
      },
      "id": "03b7cff5-b99e-48d4-900c-4c92af019ef9",
      "name": "Generate Back Shots",
      "type": "n8n-nodes-dreem.dreem",
      "typeVersion": 1,
      "position": [
        208,
        496
      ],
      "credentials": {
        "dreemApi": {
          "name": "Dreem API"
        }
      },
      "disabled": true
    },
    {
      "parameters": {
        "resume": "webhook",
        "httpMethod": "POST",
        "limitWaitTime": true,
        "resumeAmount": 20,
        "resumeUnit": "minutes",
        "options": {}
      },
      "id": "cbdd35e3-aec0-4ae5-ada6-7eefb485585c",
      "name": "Wait Back",
      "type": "n8n-nodes-base.wait",
      "typeVersion": 1.1,
      "position": [
        448,
        496
      ],
      "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": "763f631a-e168-4902-b2f3-bc2d9607a7b9",
      "name": "Back Done?",
      "type": "n8n-nodes-base.if",
      "typeVersion": 2.2,
      "position": [
        688,
        496
      ],
      "disabled": true
    },
    {
      "parameters": {
        "authentication": "accessToken",
        "resource": "product",
        "operation": "update",
        "productId": "={{ $('New Shopify Product').item.json.id }}",
        "updateFields": {
          "images": "={{ ($('Publish to Shopify').item.json.images || []).map(i => ({ id: i.id })).concat(($('Wait Back').item.json.body.outputs || []).map(o => ({ src: o.files[0].url }))) }}"
        }
      },
      "id": "8a316f5c-3d14-450c-be92-5e13611a93ee",
      "name": "Publish Back Shots",
      "type": "n8n-nodes-base.shopify",
      "typeVersion": 1,
      "position": [
        928,
        496
      ],
      "credentials": {
        "shopifyAccessTokenApi": {
          "name": "Shopify account"
        }
      },
      "disabled": true
    },
    {
      "parameters": {
        "content": "### Back shots (optional, OFF)\nTo also get **back-facing 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": 404,
        "width": 572,
        "color": 6
      },
      "id": "b1ac211d-ce27-4c9d-b6a3-b6057b80a38b",
      "name": "Note — Back Shots",
      "type": "n8n-nodes-base.stickyNote",
      "typeVersion": 1,
      "position": [
        1104,
        496
      ]
    },
    {
      "parameters": {
        "conditions": {
          "options": {
            "caseSensitive": true,
            "leftValue": "",
            "typeValidation": "loose",
            "version": 2
          },
          "conditions": [
            {
              "id": "has-image-1",
              "leftValue": "={{ $json.images?.[0]?.src ?? '' }}",
              "rightValue": "",
              "operator": {
                "type": "string",
                "operation": "notEmpty",
                "singleValue": true
              }
            }
          ],
          "combinator": "and"
        },
        "options": {}
      },
      "id": "4dc81be7-b15b-466f-92d7-77c02c99f5cb",
      "name": "Has Image?",
      "type": "n8n-nodes-base.if",
      "typeVersion": 2.2,
      "position": [
        32,
        0
      ]
    },
    {
      "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": "9d8136a7-9129-4a13-a6e6-7447d67b9873",
      "name": "Note — Shot Types",
      "type": "n8n-nodes-base.stickyNote",
      "typeVersion": 1,
      "position": [
        -432,
        720
      ]
    }
  ],
  "connections": {
    "Is Complete?": {
      "main": [
        [
          {
            "node": "Approve in 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
          }
        ]
      ]
    },
    "Generate Front Shots": {
      "main": [
        [
          {
            "node": "Wait for Render",
            "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
          }
        ]
      ]
    }
  },
  "active": false,
  "settings": {
    "executionOrder": "v1"
  }
}
