{
  "meta": {
    "templateCredsSetupCompleted": true
  },
  "nodes": [
    {
      "id": "7fae5006-335a-4721-a2ea-16dc02ecaedb",
      "name": "Webhook",
      "type": "n8n-nodes-base.webhook",
      "position": [
        -1120,
        96
      ],
      "parameters": {
        "path": "create-ugc-video",
        "options": {},
        "httpMethod": "POST",
        "responseMode": "lastNode"
      },
      "typeVersion": 2
    },
    {
      "id": "de4fb004-b472-48c0-85f4-dd6b47962a0c",
      "name": "Nano Banana",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        -896,
        96
      ],
      "parameters": {
        "url": "=https://generativelanguage.googleapis.com/v1beta/models/gemini-2.5-flash-image:generateContent?key={{ $json.body.geminiApiKey }}",
        "method": "POST",
        "options": {},
        "jsonBody": "={\n  \"contents\": [{\n    \"parts\": [{\n      \"text\": \"{{ $json.body.productPrompt }}\"\n    }]\n  }]\n}",
        "sendBody": true,
        "specifyBody": "json"
      },
      "typeVersion": 4.2
    },
    {
      "id": "977bca7d-e89f-4f80-9c9e-4fce547bd6dc",
      "name": "Extract Image",
      "type": "n8n-nodes-base.code",
      "position": [
        -688,
        96
      ],
      "parameters": {
        "jsCode": "// Extract image from Nano Banana response\nconst data = $input.first().json;\nconst imageData = data.candidates[0].content.parts.find(p => p.inlineData);\n\nreturn {\n  imageBase64: imageData.inlineData.data,\n  productPrompt: $('Webhook').first().json.body.productPrompt,\n  videoPrompt: $('Webhook').first().json.body.videoPrompt,\n  openaiApiKey: $('Webhook').first().json.body.openaiApiKey\n};"
      },
      "typeVersion": 2
    },
    {
      "id": "dac9378f-8080-435e-9574-296d4632c799",
      "name": "SORA 2",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        -464,
        96
      ],
      "parameters": {
        "url": "https://api.openai.com/v1/videos",
        "method": "POST",
        "options": {},
        "jsonBody": "={\n  \"model\": \"sora-2\",\n  \"prompt\": \"{{ $json.videoPrompt }}\",\n  \"size\": \"720x1280\",\n  \"seconds\": \"8\"\n}",
        "sendBody": true,
        "sendHeaders": true,
        "specifyBody": "json",
        "headerParameters": {
          "parameters": [
            {
              "name": "Authorization",
              "value": "=Bearer {{ $json.openaiApiKey }}"
            },
            {
              "name": "Content-Type",
              "value": "application/json"
            }
          ]
        }
      },
      "typeVersion": 4.2
    },
    {
      "id": "61cda299-28ee-4e74-aac7-60aa52099dd1",
      "name": "Get Video",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        -192,
        96
      ],
      "parameters": {
        "url": "=https://api.openai.com/v1/videos/{{ $('SORA 2').item.json.id }}",
        "options": {},
        "sendHeaders": true,
        "headerParameters": {
          "parameters": [
            {
              "name": "Authorization",
              "value": "=Bearer {{ $('Extract Image').item.json.openaiApiKey }}"
            }
          ]
        }
      },
      "typeVersion": 4.2
    },
    {
      "id": "281e0b7f-d9ed-438e-a6fd-e144feeb8642",
      "name": "Video Complete?",
      "type": "n8n-nodes-base.if",
      "position": [
        208,
        96
      ],
      "parameters": {
        "conditions": {
          "string": [
            {
              "value1": "={{ $json.status }}",
              "value2": "completed"
            }
          ]
        }
      },
      "typeVersion": 1
    },
    {
      "id": "08038d29-b87c-4348-ace9-e0f26326cbb4",
      "name": "Wait & Retry",
      "type": "n8n-nodes-base.wait",
      "position": [
        -16,
        272
      ],
      "parameters": {
        "unit": "minutes",
        "amount": 1
      },
      "typeVersion": 1.1
    },
    {
      "id": "8c7878e6-d8fa-42d5-b253-db967e841e94",
      "name": "Add to Google Sheets",
      "type": "n8n-nodes-base.googleSheets",
      "position": [
        848,
        0
      ],
      "parameters": {
        "columns": {
          "value": {
            "Status": "={{ $json.status }}",
            "Created": "={{ new Date().toISOString() }}",
            "Product": "={{ $('Extract Image').item.json.productPrompt }}",
            "Video URL": "=={{ $('Upload file').item.json.webViewLink }}"
          },
          "schema": [
            {
              "id": "Product",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Product",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Video URL",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Video URL",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Status",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Status",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Created",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Created",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            }
          ],
          "mappingMode": "defineBelow",
          "matchingColumns": [],
          "attemptToConvertTypes": false,
          "convertFieldsToString": false
        },
        "options": {},
        "operation": "append",
        "sheetName": {
          "__rl": true,
          "mode": "list",
          "value": "gid=0",
          "cachedResultUrl": "YOUR_SHEET_URL",
          "cachedResultName": "All Videos"
        },
        "documentId": {
          "__rl": true,
          "mode": "id",
          "value": "YOUR_GOOGLE_SHEET_ID"
        }
      },
      "typeVersion": 4.4
    },
    {
      "id": "c15d9c80-ac8c-4e82-aa6a-417c9a157fe6",
      "name": "Download Video File",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        416,
        0
      ],
      "parameters": {
        "url": "=https://api.openai.com/v1/videos/{{ $json.id }}/content",
        "options": {
          "response": {
            "response": {
              "responseFormat": "file"
            }
          }
        },
        "sendHeaders": true,
        "headerParameters": {
          "parameters": [
            {
              "name": "Authorization",
              "value": "=Bearer {{ $('Webhook').first().json.body.openaiApiKey }}"
            }
          ]
        }
      },
      "typeVersion": 4.2
    },
    {
      "id": "7522e1c7-1765-4419-9656-d2e855986913",
      "name": "Upload file",
      "type": "n8n-nodes-base.googleDrive",
      "position": [
        624,
        0
      ],
      "parameters": {
        "name": "=={{ $json.id }}.mp4",
        "driveId": {
          "__rl": true,
          "mode": "list",
          "value": "My Drive"
        },
        "options": {},
        "folderId": {
          "__rl": true,
          "mode": "list",
          "value": "root",
          "cachedResultName": "/ (Root folder)"
        }
      },
      "credentials": {
        "googleDriveOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 3
    },
    {
      "id": "96429180-f0a6-469b-a32b-67aa1ae49392",
      "name": "Sticky Note",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -1600,
        -64
      ],
      "parameters": {
        "width": 416,
        "height": 448,
        "content": "# UGC Video Generator Workflow\n\nGenerates product videos using Gemini (image) + SORA 2 (video). Accepts webhook with product/video prompts and API keys, polls for completion, stores in Google Drive, and logs to Google Sheets.\n\n**Required connectors:**\n- Google Sheets OAuth\n- Google Drive OAuth\n\n**Required API keys** (passed via webhook):\n- Gemini API key\n- OpenAI API key\n\n---\nCreated by [Daniel Shashko](https://www.linkedin.com/in/daniel-shashko/)"
      },
      "typeVersion": 1
    },
    {
      "id": "621ad50b-835a-4afe-808f-dc8e2a904111",
      "name": "Sticky Note1",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -1152,
        -32
      ],
      "parameters": {
        "width": 176,
        "height": 96,
        "content": "Receives POST request with prompts and API keys\n"
      },
      "typeVersion": 1
    },
    {
      "id": "d28bf28b-13aa-4f85-9176-b3a2f2308ee9",
      "name": "Sticky Note2",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -928,
        -32
      ],
      "parameters": {
        "width": 176,
        "height": 96,
        "content": "Generates product image using Gemini AI from prompt"
      },
      "typeVersion": 1
    },
    {
      "id": "44258498-fac6-4fa4-96e4-f0ff518e9cf0",
      "name": "Sticky Note3",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -720,
        -32
      ],
      "parameters": {
        "width": 176,
        "height": 96,
        "content": "Extracts base64 image data from Gemini API response\n"
      },
      "typeVersion": 1
    },
    {
      "id": "5a2c6614-795e-495f-bb49-7152d7e9fb50",
      "name": "Sticky Note4",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -496,
        -32
      ],
      "parameters": {
        "width": 176,
        "height": 96,
        "content": "Creates video from prompt using OpenAI SORA model\n"
      },
      "typeVersion": 1
    },
    {
      "id": "e4e9b154-31cc-4118-8d76-fa3540c22aea",
      "name": "Sticky Note5",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -224,
        -32
      ],
      "parameters": {
        "width": 176,
        "height": 96,
        "content": "Checks SORA video generation status via API call\n"
      },
      "typeVersion": 1
    },
    {
      "id": "cbd4ada0-1dbb-41a5-97de-ab2852585cca",
      "name": "Sticky Note6",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        160,
        -32
      ],
      "parameters": {
        "width": 176,
        "height": 96,
        "content": "Determines if video rendering is finished or pending\n"
      },
      "typeVersion": 1
    },
    {
      "id": "86042fc7-7f4b-4306-86fb-4218bde7d5bb",
      "name": "Sticky Note7",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -208,
        336
      ],
      "parameters": {
        "width": 176,
        "height": 96,
        "content": "Pauses 1 minute then checks video status again"
      },
      "typeVersion": 1
    },
    {
      "id": "bc3c7746-3ebb-424f-aeb4-c78c341e81e6",
      "name": "Sticky Note8",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        384,
        -128
      ],
      "parameters": {
        "width": 176,
        "height": 96,
        "content": "Downloads completed video file from OpenAI API endpoint"
      },
      "typeVersion": 1
    },
    {
      "id": "7a315df7-736c-4cf4-98b3-8a2a417173d6",
      "name": "Sticky Note9",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        592,
        -128
      ],
      "parameters": {
        "width": 176,
        "height": 96,
        "content": "Saves video to Google Drive as MP4 file\n"
      },
      "typeVersion": 1
    },
    {
      "id": "2572eb1d-b20b-4fec-804e-d93e731b8e84",
      "name": "Sticky Note10",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        816,
        -128
      ],
      "parameters": {
        "width": 176,
        "height": 96,
        "content": "Logs video details: product, URL, status, timestamp"
      },
      "typeVersion": 1
    }
  ],
  "connections": {
    "SORA 2": {
      "main": [
        [
          {
            "node": "Get Video",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Webhook": {
      "main": [
        [
          {
            "node": "Nano Banana",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Get Video": {
      "main": [
        [
          {
            "node": "Video Complete?",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Nano Banana": {
      "main": [
        [
          {
            "node": "Extract Image",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Upload file": {
      "main": [
        [
          {
            "node": "Add to Google Sheets",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Wait & Retry": {
      "main": [
        [
          {
            "node": "Get Video",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Extract Image": {
      "main": [
        [
          {
            "node": "SORA 2",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Video Complete?": {
      "main": [
        [
          {
            "node": "Download Video File",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Wait & Retry",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Download Video File": {
      "main": [
        [
          {
            "node": "Upload file",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  }
}