{
  "name": "Shopify new product to AI product video ad with Sisif",
  "nodes": [
    {
      "id": "c96440ae-fa40-44f0-97c4-24e8a7bef91a",
      "name": "Setup Instructions",
      "type": "n8n-nodes-base.stickyNote",
      "typeVersion": 1,
      "position": [
        -1500,
        -700
      ],
      "parameters": {
        "content": "## Turn new Shopify products into AI product video ads with Sisif\n\n### Who it's for\nShopify merchants and e-commerce teams who want a short motion video on every new product page without a video shoot.\n\n### How it works\n1. **Shopify Trigger** fires when a product is created.\n2. The main product image and copy are extracted. Products without an image are skipped.\n3. An AI model writes a short camera/motion prompt for that product.\n4. **Sisif** animates the product photo into a 5-second portrait MP4 (image-to-video).\n5. The workflow polls every 30 s until the video is `READY`, stops on `ERROR`/`REFUNDED`, and times out after 40 checks.\n6. The MP4 is uploaded to Shopify with a staged upload and added to the product as media (Admin GraphQL API). If any Shopify step fails, the MP4 is saved to Google Drive instead.\n7. A Slack message reports the result.\n\n### Setup\n1. Create a Sisif API key at https://sisif.ai/users/api-keys/ and add it in n8n as a **Bearer Auth** credential. Select it on **Generate Video from Image** and **Check Video Status**.\n2. Create a Shopify custom app with `read_products` and `write_products` scopes, then add a **Shopify Access Token** credential. Select it on the trigger, **Create Staged Upload** and **Attach Video to Product**. If your app is new, also add the `write_files` scope.\n3. Open **Workflow Config** and set `shop_subdomain` (the part before `.myshopify.com`), `shopify_api_version` (a supported Admin API version, default `2026-07`), `drive_folder_id` and `slack_channel`.\n4. Add OpenAI (or swap in any chat model), Google Drive and Slack credentials.\n5. Create a test product with an image, check the run, then activate.\n\n### Customize\n- Edit the prompt in **Write Motion Prompt** to change style or tone.\n- Change the poll interval in **Wait 30s**.\n- Each image clip costs one Sisif clip; duration and resolution are fixed by Sisif for photo clips.",
        "width": 620,
        "height": 900
      }
    },
    {
      "id": "4ac6c8fc-c8e5-492b-85cd-e391995ad2ff",
      "name": "Note: Generate and Poll",
      "type": "n8n-nodes-base.stickyNote",
      "typeVersion": 1,
      "position": [
        -180,
        -420
      ],
      "parameters": {
        "content": "### Sisif render loop\nThe photo URL is sent as `image` with the motion `prompt`. Sisif fixes duration and resolution for photo clips. The loop checks `/api/videos/{id}/status/` every 30 s, exits on `READY`, `ERROR` or `REFUNDED`, and gives up after 40 checks (about 20 minutes).",
        "width": 1100,
        "height": 200,
        "color": 7
      }
    },
    {
      "id": "ce86c5d6-e4e8-4fa5-b053-b89b52b73e32",
      "name": "Note: Attach or Fallback",
      "type": "n8n-nodes-base.stickyNote",
      "typeVersion": 1,
      "position": [
        1100,
        -420
      ],
      "parameters": {
        "content": "### Deliver the video to Shopify\nShopify does not accept an external video URL. The MP4 is downloaded and measured, `stagedUploadsCreate` (resource `VIDEO`, method `POST`) returns an upload target, and **Upload to Staged Target** posts a multipart form with Shopify's parameters in their original order and the file last. Up to 12 parameters are supported; unused slots are sent as `x-ignore-*` fields, which Google Cloud Storage ignores. `productUpdate` then adds the video to the product using the returned `resourceUrl`, and Shopify processes it for a few minutes. If any step fails, the MP4 goes to Google Drive and Slack gets the link.",
        "width": 2600,
        "height": 200,
        "color": 7
      }
    },
    {
      "id": "cfed78fd-79ed-47f5-8e9c-77f3d48fe366",
      "name": "Shopify Trigger",
      "type": "n8n-nodes-base.shopifyTrigger",
      "typeVersion": 1,
      "position": [
        -840,
        0
      ],
      "parameters": {
        "topic": "products/create",
        "authentication": "accessToken"
      },
      "credentials": {
        "shopifyAccessTokenApi": {
          "id": "",
          "name": "Shopify Access Token"
        }
      },
      "webhookId": "6c08f99e-9032-4abe-a5b7-553b56e94363"
    },
    {
      "id": "1941d80e-b92e-4414-a54d-26335045639c",
      "name": "Workflow Config",
      "type": "n8n-nodes-base.set",
      "typeVersion": 3.4,
      "position": [
        -640,
        0
      ],
      "parameters": {
        "assignments": {
          "assignments": [
            {
              "id": "e4f3ddbb-9ba7-49c6-acf3-2eb5bef3a022",
              "name": "shop_subdomain",
              "value": "your-store",
              "type": "string"
            },
            {
              "id": "8e5635bb-df83-4f99-a671-7daf37d9af44",
              "name": "shopify_api_version",
              "value": "2026-07",
              "type": "string"
            },
            {
              "id": "7220a392-6d5f-4440-87cd-d90a5e7de9c1",
              "name": "drive_folder_id",
              "value": "",
              "type": "string"
            },
            {
              "id": "da4b9099-4f03-4117-b653-a5ae62c199f4",
              "name": "slack_channel",
              "value": "#product-videos",
              "type": "string"
            }
          ]
        },
        "options": {}
      }
    },
    {
      "id": "2d581750-0386-499d-b984-34445648bba1",
      "name": "Extract Product Data",
      "type": "n8n-nodes-base.set",
      "typeVersion": 3.4,
      "position": [
        -440,
        0
      ],
      "parameters": {
        "assignments": {
          "assignments": [
            {
              "id": "8186cc19-46a8-4797-b795-725d8c7ddba3",
              "name": "product_gid",
              "value": "={{ $('Shopify Trigger').item.json.admin_graphql_api_id }}",
              "type": "string"
            },
            {
              "id": "473f0288-8eeb-4c29-ae65-33a200de13b9",
              "name": "title",
              "value": "={{ $('Shopify Trigger').item.json.title }}",
              "type": "string"
            },
            {
              "id": "abdedc11-9218-4ba7-8b9c-47056b94a428",
              "name": "description",
              "value": "={{ ($('Shopify Trigger').item.json.body_html || '').replace(/<[^>]*>/g, ' ').slice(0, 800) }}",
              "type": "string"
            },
            {
              "id": "c81069bc-762b-4c21-96df-dfc7b525ecf9",
              "name": "product_type",
              "value": "={{ $('Shopify Trigger').item.json.product_type }}",
              "type": "string"
            },
            {
              "id": "a6d53d07-76a8-471a-8cd0-5799592f2ccb",
              "name": "image_url",
              "value": "={{ $('Shopify Trigger').item.json.image?.src || $('Shopify Trigger').item.json.images?.[0]?.src || '' }}",
              "type": "string"
            }
          ]
        },
        "options": {}
      }
    },
    {
      "id": "2fbdc20c-6744-478a-9a05-132033b03825",
      "name": "Has Main Image?",
      "type": "n8n-nodes-base.if",
      "typeVersion": 1,
      "position": [
        -240,
        0
      ],
      "parameters": {
        "conditions": {
          "string": [
            {
              "value1": "={{ $json.image_url }}",
              "operation": "startsWith",
              "value2": "https://"
            }
          ]
        }
      }
    },
    {
      "id": "625aa320-e77e-4ea8-b847-dce0857f6643",
      "name": "Write Motion Prompt",
      "type": "@n8n/n8n-nodes-langchain.chainLlm",
      "typeVersion": 1.5,
      "position": [
        -20,
        0
      ],
      "parameters": {
        "promptType": "define",
        "text": "=You write prompts for an image-to-video model that animates a single product photo into a 5-second portrait ad clip.\n\nProduct: {{ $json.title }}\nType: {{ $json.product_type }}\nDescription: {{ $json.description }}\n\nWrite ONE prompt under 60 words describing subtle camera motion (slow push-in, orbit, parallax), lighting and ambient movement that makes the product look premium. Keep the product unchanged and centered. No text overlays, no people unless already in the photo. Return only the prompt."
      }
    },
    {
      "id": "97141a9f-2b82-45f4-9cb8-7524aa4e8589",
      "name": "OpenAI Chat Model",
      "type": "@n8n/n8n-nodes-langchain.lmChatOpenAi",
      "typeVersion": 1.2,
      "position": [
        -20,
        200
      ],
      "parameters": {
        "model": {
          "__rl": true,
          "mode": "list",
          "value": "gpt-4o-mini"
        },
        "options": {}
      },
      "credentials": {
        "openAiApi": {
          "id": "",
          "name": "OpenAI account"
        }
      }
    },
    {
      "id": "b4397c13-5a16-482f-8187-ae9eaa1bcd9e",
      "name": "Generate Video from Image",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [
        340,
        0
      ],
      "parameters": {
        "url": "https://sisif.ai/api/videos/generate/",
        "method": "POST",
        "sendBody": true,
        "authentication": "genericCredentialType",
        "genericAuthType": "httpBearerAuth",
        "bodyParameters": {
          "parameters": [
            {
              "name": "prompt",
              "value": "={{ $json.text.trim() }}"
            },
            {
              "name": "image",
              "value": "={{ $('Extract Product Data').item.json.image_url }}"
            }
          ]
        },
        "options": {}
      },
      "credentials": {
        "httpBearerAuth": {
          "id": "",
          "name": "Sisif API (Bearer)"
        }
      }
    },
    {
      "id": "f6072956-3d64-4861-adb5-4aa8380205a4",
      "name": "Wait 30s",
      "type": "n8n-nodes-base.wait",
      "typeVersion": 1,
      "position": [
        560,
        0
      ],
      "parameters": {
        "amount": 30,
        "unit": "seconds"
      },
      "webhookId": "0e16ea94-d7c2-420f-96cd-8e85aee7e48f"
    },
    {
      "id": "c9e828c1-ae59-4fc8-94a7-edc66443d0d8",
      "name": "Check Video Status",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [
        780,
        0
      ],
      "parameters": {
        "url": "=https://sisif.ai/api/videos/{{ $json.id }}/status/",
        "authentication": "genericCredentialType",
        "genericAuthType": "httpBearerAuth",
        "options": {}
      },
      "credentials": {
        "httpBearerAuth": {
          "id": "",
          "name": "Sisif API (Bearer)"
        }
      }
    },
    {
      "id": "b6d2bbcd-c75a-46a5-b438-c90734ae1e6b",
      "name": "Video Ready?",
      "type": "n8n-nodes-base.if",
      "typeVersion": 1,
      "position": [
        1000,
        0
      ],
      "parameters": {
        "conditions": {
          "string": [
            {
              "value1": "={{ $json.status }}",
              "value2": "READY"
            }
          ]
        }
      }
    },
    {
      "id": "2e3b42d1-93d0-40a6-bd82-f323981140d3",
      "name": "Render Failed?",
      "type": "n8n-nodes-base.if",
      "typeVersion": 1,
      "position": [
        1220,
        160
      ],
      "parameters": {
        "conditions": {
          "string": [
            {
              "value1": "={{ $json.status }}",
              "value2": "^(ERROR|REFUNDED)$",
              "operation": "regex"
            }
          ]
        }
      }
    },
    {
      "id": "6e459360-20e9-4e7e-986c-d2b20dd21724",
      "name": "Attached to Shopify?",
      "type": "n8n-nodes-base.if",
      "typeVersion": 1,
      "position": [
        3200,
        -260
      ],
      "parameters": {
        "conditions": {
          "boolean": [
            {
              "value1": "={{ !$json.error && !$json.errors && Array.isArray($json.data?.productUpdate?.userErrors) && $json.data.productUpdate.userErrors.length === 0 }}",
              "value2": true
            }
          ]
        }
      }
    },
    {
      "id": "6206a471-c87b-4945-b0f5-3ff7ba5d2850",
      "name": "Notify Slack: Attached",
      "type": "n8n-nodes-base.slack",
      "typeVersion": 2.2,
      "position": [
        3420,
        -360
      ],
      "parameters": {
        "select": "channel",
        "channelId": {
          "__rl": true,
          "mode": "name",
          "value": "={{ $('Workflow Config').item.json.slack_channel }}"
        },
        "text": "=New product video attached in Shopify: *{{ $('Extract Product Data').item.json.title }}*\nVideo: {{ $('Check Video Status').item.json.video_url }}",
        "otherOptions": {}
      },
      "credentials": {
        "slackApi": {
          "id": "",
          "name": "Slack account"
        }
      },
      "webhookId": "ae1dcb47-3107-45ea-8b9b-9a777881e953"
    },
    {
      "id": "0be8f236-a536-48be-b00c-2f3169b3e15d",
      "name": "Upload to Google Drive",
      "type": "n8n-nodes-base.googleDrive",
      "typeVersion": 3,
      "position": [
        3640,
        -40
      ],
      "parameters": {
        "name": "={{ $('Extract Product Data').item.json.title }} - sisif.mp4",
        "driveId": {
          "__rl": true,
          "mode": "list",
          "value": "My Drive"
        },
        "folderId": {
          "__rl": true,
          "mode": "id",
          "value": "={{ $('Workflow Config').item.json.drive_folder_id }}"
        },
        "options": {}
      },
      "credentials": {
        "googleDriveOAuth2Api": {
          "id": "",
          "name": "Google Drive account"
        }
      }
    },
    {
      "id": "be265b07-cff7-478e-af99-ea6c6da62550",
      "name": "Notify Slack: Saved to Drive",
      "type": "n8n-nodes-base.slack",
      "typeVersion": 2.2,
      "position": [
        3860,
        -40
      ],
      "parameters": {
        "select": "channel",
        "channelId": {
          "__rl": true,
          "mode": "name",
          "value": "={{ $('Workflow Config').item.json.slack_channel }}"
        },
        "text": "=Shopify did not accept the video for *{{ $('Extract Product Data').item.json.title }}*, so it was saved to Google Drive: {{ $json.webViewLink }}\nSisif URL: {{ $('Check Video Status').item.json.video_url }}",
        "otherOptions": {}
      },
      "credentials": {
        "slackApi": {
          "id": "",
          "name": "Slack account"
        }
      },
      "webhookId": "0406b38e-49eb-4710-aadc-1f1c067ae42b"
    },
    {
      "id": "65109212-1aae-4160-b1c7-099703712378",
      "name": "Notify Slack: Render Failed",
      "type": "n8n-nodes-base.slack",
      "typeVersion": 2.2,
      "position": [
        1540,
        200
      ],
      "parameters": {
        "select": "channel",
        "channelId": {
          "__rl": true,
          "mode": "name",
          "value": "={{ $('Workflow Config').item.json.slack_channel }}"
        },
        "text": "=Sisif could not render a video for *{{ $('Extract Product Data').item.json.title }}* (status {{ $json.status }}): {{ $json.error_message || 'no details' }}",
        "otherOptions": {}
      },
      "credentials": {
        "slackApi": {
          "id": "",
          "name": "Slack account"
        }
      },
      "webhookId": "0a5e405f-413e-4597-b375-dc082d9d5f2c"
    },
    {
      "id": "86c99d60-bc33-4181-8031-73b6bbd8999e",
      "name": "Max Attempts Reached?",
      "type": "n8n-nodes-base.if",
      "typeVersion": 1,
      "position": [
        1100,
        180
      ],
      "parameters": {
        "conditions": {
          "number": [
            {
              "value1": "={{ $runIndex + 1 }}",
              "operation": "largerEqual",
              "value2": 40
            }
          ]
        }
      }
    },
    {
      "id": "23fd6001-455d-4bf9-b6c4-f3d9b9681e3c",
      "name": "Mark Timed Out",
      "type": "n8n-nodes-base.set",
      "typeVersion": 3.4,
      "position": [
        1320,
        300
      ],
      "parameters": {
        "assignments": {
          "assignments": [
            {
              "id": "aea1caf4-dd5d-4be9-a4a6-f781279eb01c",
              "name": "status",
              "value": "TIMEOUT",
              "type": "string"
            },
            {
              "id": "ff7b3d94-43b5-46f6-92f3-740291cfdcf2",
              "name": "error_message",
              "value": "Video not ready after 40 status checks (about 20 minutes)",
              "type": "string"
            }
          ]
        },
        "includeOtherFields": true,
        "options": {}
      }
    },
    {
      "id": "b58026b8-4a2e-4204-9218-9184af15f53d",
      "name": "Download Video",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [
        1220,
        -160
      ],
      "parameters": {
        "url": "={{ $json.video_url }}",
        "options": {
          "response": {
            "response": {
              "responseFormat": "file"
            }
          }
        }
      }
    },
    {
      "id": "a4983b66-5d5c-4638-9498-9d15e06f630c",
      "name": "Measure Video File",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        1440,
        -160
      ],
      "parameters": {
        "jsCode": "// Shopify needs the exact byte size of a VIDEO before it issues a staged upload target.\nconst out = [];\nfor (let i = 0; i < $input.all().length; i++) {\n  const buf = await this.helpers.getBinaryDataBuffer(i, 'data');\n  const product = $('Extract Product Data').item.json;\n  out.push({ json: {\n    video_url: $('Check Video Status').item.json.video_url,\n    file_size: String(buf.length),\n    filename: (product.title || 'product').replace(/[^a-z0-9]+/gi, '-').toLowerCase() + '-sisif.mp4',\n  } });\n}\nreturn out;"
      }
    },
    {
      "id": "2cb2ae16-a0ec-4220-a9c5-36649479184d",
      "name": "Create Staged Upload",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [
        1660,
        -160
      ],
      "onError": "continueRegularOutput",
      "parameters": {
        "method": "POST",
        "url": "=https://{{ $('Workflow Config').item.json.shop_subdomain }}.myshopify.com/admin/api/{{ $('Workflow Config').item.json.shopify_api_version }}/graphql.json",
        "authentication": "predefinedCredentialType",
        "nodeCredentialType": "shopifyAccessTokenApi",
        "sendBody": true,
        "specifyBody": "json",
        "jsonBody": "={{ JSON.stringify({ query: 'mutation stagedUploadsCreate($input: [StagedUploadInput!]!) { stagedUploadsCreate(input: $input) { stagedTargets { url resourceUrl parameters { name value } } userErrors { field message } } }', variables: { input: [{ resource: 'VIDEO', filename: $json.filename, mimeType: 'video/mp4', fileSize: $json.file_size, httpMethod: 'POST' }] } }) }}",
        "options": {}
      },
      "credentials": {
        "shopifyAccessTokenApi": {
          "id": "",
          "name": "Shopify Access Token"
        }
      }
    },
    {
      "id": "369415ee-c928-4d9f-98e9-cfeeed96d0ab",
      "name": "Upload Succeeded?",
      "type": "n8n-nodes-base.if",
      "typeVersion": 1,
      "position": [
        2760,
        -160
      ],
      "parameters": {
        "conditions": {
          "boolean": [
            {
              "value1": "={{ !$json.error && $json.statusCode >= 200 && $json.statusCode < 300 }}",
              "value2": true
            }
          ]
        }
      }
    },
    {
      "id": "8ff16c0c-d450-4304-9d0f-5f5199ed39c5",
      "name": "Attach Video to Product",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [
        2980,
        -260
      ],
      "onError": "continueRegularOutput",
      "parameters": {
        "method": "POST",
        "url": "=https://{{ $('Workflow Config').item.json.shop_subdomain }}.myshopify.com/admin/api/{{ $('Workflow Config').item.json.shopify_api_version }}/graphql.json",
        "authentication": "predefinedCredentialType",
        "nodeCredentialType": "shopifyAccessTokenApi",
        "sendBody": true,
        "specifyBody": "json",
        "jsonBody": "={{ JSON.stringify({ query: 'mutation productUpdate($product: ProductUpdateInput!, $media: [CreateMediaInput!]) { productUpdate(product: $product, media: $media) { product { id media(first: 1, sortKey: POSITION, reverse: true) { nodes { id status mediaContentType } } } userErrors { field message } } }', variables: { product: { id: $('Extract Product Data').item.json.product_gid }, media: [{ originalSource: $('Prepare Staged Upload').item.json.resource_url, mediaContentType: 'VIDEO', alt: $('Extract Product Data').item.json.title + ' product video' }] } }) }}",
        "options": {}
      },
      "credentials": {
        "shopifyAccessTokenApi": {
          "id": "",
          "name": "Shopify Access Token"
        }
      }
    },
    {
      "id": "1599f3d9-9e13-4851-942e-51fa155a8f60",
      "name": "Download Video for Drive",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [
        3420,
        -40
      ],
      "parameters": {
        "url": "={{ $('Check Video Status').item.json.video_url }}",
        "options": {
          "response": {
            "response": {
              "responseFormat": "file"
            }
          }
        }
      }
    },
    {
      "id": "30475f64-a4f0-4e81-b59e-ab8381b082e3",
      "name": "Download Video for Upload",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [
        1880,
        -160
      ],
      "parameters": {
        "url": "={{ $('Measure Video File').item.json.video_url }}",
        "options": {
          "response": {
            "response": {
              "responseFormat": "file"
            }
          }
        }
      }
    },
    {
      "id": "6355ca43-33e3-49d3-920b-495c4a7ad965",
      "name": "Prepare Staged Upload",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        2100,
        -160
      ],
      "parameters": {
        "jsCode": "// Read the staged target Shopify returned and pass the downloaded MP4 through.\n// The next node posts Shopify's parameters in order, then the file last.\nconst res = $('Create Staged Upload').item.json;\nconst target = res.data?.stagedUploadsCreate?.stagedTargets?.[0];\nconst userErrors = res.data?.stagedUploadsCreate?.userErrors || [];\nif (!target || userErrors.length) {\n  return [{ json: { upload_ready: false, error: JSON.stringify(userErrors.length ? userErrors : (res.errors || res.error || res)) } }];\n}\nif (target.parameters.length > 12) {\n  return [{ json: { upload_ready: false, error: `Shopify returned ${target.parameters.length} upload parameters; add slots to Upload to Staged Target` } }];\n}\nreturn [{\n  json: { upload_ready: true, upload_url: target.url, resource_url: target.resourceUrl, params: target.parameters },\n  binary: $input.first().binary,\n}];"
      }
    },
    {
      "id": "fd0fee66-781d-465a-8589-198c6e5a9f61",
      "name": "Staged Target Ready?",
      "type": "n8n-nodes-base.if",
      "typeVersion": 1,
      "position": [
        2320,
        -160
      ],
      "parameters": {
        "conditions": {
          "boolean": [
            {
              "value1": "={{ $json.upload_ready === true }}",
              "value2": true
            }
          ]
        }
      }
    },
    {
      "id": "e1f22d94-2282-4645-ad4b-6155c1272288",
      "name": "Upload to Staged Target",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [
        2540,
        -220
      ],
      "onError": "continueRegularOutput",
      "parameters": {
        "method": "POST",
        "url": "={{ $json.upload_url }}",
        "sendBody": true,
        "contentType": "multipart-form-data",
        "bodyParameters": {
          "parameters": [
            {
              "name": "={{ $json.params[0]?.name ?? 'x-ignore-unused-0' }}",
              "value": "={{ $json.params[0]?.value ?? '' }}"
            },
            {
              "name": "={{ $json.params[1]?.name ?? 'x-ignore-unused-1' }}",
              "value": "={{ $json.params[1]?.value ?? '' }}"
            },
            {
              "name": "={{ $json.params[2]?.name ?? 'x-ignore-unused-2' }}",
              "value": "={{ $json.params[2]?.value ?? '' }}"
            },
            {
              "name": "={{ $json.params[3]?.name ?? 'x-ignore-unused-3' }}",
              "value": "={{ $json.params[3]?.value ?? '' }}"
            },
            {
              "name": "={{ $json.params[4]?.name ?? 'x-ignore-unused-4' }}",
              "value": "={{ $json.params[4]?.value ?? '' }}"
            },
            {
              "name": "={{ $json.params[5]?.name ?? 'x-ignore-unused-5' }}",
              "value": "={{ $json.params[5]?.value ?? '' }}"
            },
            {
              "name": "={{ $json.params[6]?.name ?? 'x-ignore-unused-6' }}",
              "value": "={{ $json.params[6]?.value ?? '' }}"
            },
            {
              "name": "={{ $json.params[7]?.name ?? 'x-ignore-unused-7' }}",
              "value": "={{ $json.params[7]?.value ?? '' }}"
            },
            {
              "name": "={{ $json.params[8]?.name ?? 'x-ignore-unused-8' }}",
              "value": "={{ $json.params[8]?.value ?? '' }}"
            },
            {
              "name": "={{ $json.params[9]?.name ?? 'x-ignore-unused-9' }}",
              "value": "={{ $json.params[9]?.value ?? '' }}"
            },
            {
              "name": "={{ $json.params[10]?.name ?? 'x-ignore-unused-10' }}",
              "value": "={{ $json.params[10]?.value ?? '' }}"
            },
            {
              "name": "={{ $json.params[11]?.name ?? 'x-ignore-unused-11' }}",
              "value": "={{ $json.params[11]?.value ?? '' }}"
            },
            {
              "parameterType": "formBinaryData",
              "name": "file",
              "inputDataFieldName": "data"
            }
          ]
        },
        "options": {
          "response": {
            "response": {
              "responseFormat": "text",
              "fullResponse": true
            }
          }
        }
      }
    }
  ],
  "connections": {
    "Shopify Trigger": {
      "main": [
        [
          {
            "node": "Workflow Config",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Workflow Config": {
      "main": [
        [
          {
            "node": "Extract Product Data",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Extract Product Data": {
      "main": [
        [
          {
            "node": "Has Main Image?",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Has Main Image?": {
      "main": [
        [
          {
            "node": "Write Motion Prompt",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Write Motion Prompt": {
      "main": [
        [
          {
            "node": "Generate Video from Image",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Generate Video from Image": {
      "main": [
        [
          {
            "node": "Wait 30s",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Wait 30s": {
      "main": [
        [
          {
            "node": "Check Video Status",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Check Video Status": {
      "main": [
        [
          {
            "node": "Video Ready?",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Video Ready?": {
      "main": [
        [
          {
            "node": "Download Video",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Render Failed?",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Render Failed?": {
      "main": [
        [
          {
            "node": "Notify Slack: Render Failed",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Max Attempts Reached?",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Attached to Shopify?": {
      "main": [
        [
          {
            "node": "Notify Slack: Attached",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Download Video for Drive",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Upload to Google Drive": {
      "main": [
        [
          {
            "node": "Notify Slack: Saved to Drive",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "OpenAI Chat Model": {
      "ai_languageModel": [
        [
          {
            "node": "Write Motion Prompt",
            "type": "ai_languageModel",
            "index": 0
          }
        ]
      ]
    },
    "Max Attempts Reached?": {
      "main": [
        [
          {
            "node": "Mark Timed Out",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Wait 30s",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Mark Timed Out": {
      "main": [
        [
          {
            "node": "Notify Slack: Render Failed",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Download Video": {
      "main": [
        [
          {
            "node": "Measure Video File",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Measure Video File": {
      "main": [
        [
          {
            "node": "Create Staged Upload",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Create Staged Upload": {
      "main": [
        [
          {
            "node": "Download Video for Upload",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Upload Succeeded?": {
      "main": [
        [
          {
            "node": "Attach Video to Product",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Download Video for Drive",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Attach Video to Product": {
      "main": [
        [
          {
            "node": "Attached to Shopify?",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Download Video for Drive": {
      "main": [
        [
          {
            "node": "Upload to Google Drive",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Download Video for Upload": {
      "main": [
        [
          {
            "node": "Prepare Staged Upload",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Prepare Staged Upload": {
      "main": [
        [
          {
            "node": "Staged Target Ready?",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Staged Target Ready?": {
      "main": [
        [
          {
            "node": "Upload to Staged Target",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Download Video for Drive",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Upload to Staged Target": {
      "main": [
        [
          {
            "node": "Upload Succeeded?",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  },
  "pinData": {},
  "settings": {
    "executionOrder": "v1"
  },
  "meta": {
    "templateCredsSetupCompleted": false
  }
}