{
  "name": "Create Videotok product ads from new catalog items",
  "nodes": [
    {
      "parameters": {
        "content": "## Create Videotok product ads from new catalog items\n\n### How it works\n\n1. Triggers manually to start the workflow.\n2. Sets the product details like title, description, and image URL.\n3. Sends the product details to OpenAI for generating unique ad angles.\n4. Builds ad payloads based on the angles received.\n5. Sends the ad payloads to the Videotok API to create video ads.\n6. Waits and then fetches the generated video assets.\n\n### Setup steps\n\n- [ ] Ensure OpenAI API credentials are set for ad generation\n- [ ] Configure Videotok API credentials for video ad generation\n\n### Customization\n\nBefore activating the workflow, test it with one item, review the generated creative in Videotok, and confirm the brand, platform, and publishing requirements.",
        "width": 480,
        "height": 720
      },
      "type": "n8n-nodes-base.stickyNote",
      "typeVersion": 1,
      "position": [-1232, -32],
      "id": "8f68f9f9-c0c8-4896-8fff-925942036e1b",
      "name": "Sticky Note"
    },
    {
      "parameters": {
        "content": "## Trigger and set product details\n\nStarts the workflow manually and initializes product details like title, description, and image URL. Submits product data to OpenAI and receives creative ad angles.",
        "width": 736,
        "height": 320,
        "color": 7
      },
      "type": "n8n-nodes-base.stickyNote",
      "typeVersion": 1,
      "position": [-672, -32],
      "id": "d4078c55-94cd-4a7e-b5d4-6164502c5cb2",
      "name": "Sticky Note1"
    },
    {
      "parameters": {
        "content": "## Prepare and send ad payloads\n\nConstructs payloads for ads and posts them to Videotok to create video ads.",
        "width": 1008,
        "height": 272,
        "color": 7
      },
      "type": "n8n-nodes-base.stickyNote",
      "typeVersion": 1,
      "position": [176, 16],
      "id": "1fd84ed4-b030-4eeb-958a-91c70b99fd39",
      "name": "Sticky Note2"
    },
    {
      "parameters": {},
      "id": "manual",
      "name": "When Manual Product Triggered",
      "type": "n8n-nodes-base.manualTrigger",
      "typeVersion": 1,
      "position": [-624, 128]
    },
    {
      "parameters": {
        "assignments": {
          "assignments": [
            {
              "id": "title",
              "name": "product_title",
              "type": "string",
              "value": "Vitamin C serum"
            },
            {
              "id": "description",
              "name": "product_description",
              "type": "string",
              "value": "Brightening serum for dull skin with clean ingredients."
            },
            {
              "id": "image",
              "name": "product_image_url",
              "type": "string",
              "value": "https://example.com/product.png"
            }
          ]
        }
      },
      "id": "sample-product",
      "name": "Set Product Information",
      "type": "n8n-nodes-base.set",
      "typeVersion": 3.4,
      "position": [-352, 128]
    },
    {
      "parameters": {
        "method": "POST",
        "url": "https://api.openai.com/v1/responses",
        "sendHeaders": true,
        "headerParameters": {
          "parameters": [
            {
              "name": "Authorization",
              "value": "=Bearer {{$vars.OPENAI_API_KEY}}"
            },
            {
              "name": "Content-Type",
              "value": "application/json"
            }
          ]
        },
        "sendBody": true,
        "specifyBody": "json",
        "jsonBody": "={\"model\":\"gpt-4.1-mini\",\"input\":\"Write JSON for a product ad launch. Include static_prompt, video_prompt, caption, primary_claim, offer_angle. Product: \" + JSON.stringify($json)}"
      },
      "id": "openai-angles",
      "name": "Send to OpenAI for Ad Ideas",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [-80, 128]
    },
    {
      "parameters": {
        "jsCode": "const product = $('Set Product Information').first().json;\nconst raw = $input.first().json.output_text || '{}';\nlet angles;\ntry { angles = JSON.parse(raw); } catch { angles = { static_prompt: raw, video_prompt: raw, caption: raw }; }\nreturn [\n  { json: { type: 'static_ad', template_slug: 'product-shoot', prompt: angles.static_prompt, aspect_ratio: '1:1', resolution: '1K', reference_image_urls: [product.product_image_url], brand_kit_id: $vars.VIDEOTOK_BRAND_KIT_ID, idempotency_key: `product-static-${$execution.id}` } },\n  { json: { type: 'video_ad', template_slug: 'viral-video-ads', prompt: angles.video_prompt, aspect_ratio: '9:16', duration: 8, quality_tier: 'high', reference_image_urls: [product.product_image_url], brand_kit_id: $vars.VIDEOTOK_BRAND_KIT_ID, idempotency_key: `product-video-${$execution.id}` } }\n];"
      },
      "id": "split-payloads",
      "name": "Generate Ad Payloads",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [224, 128]
    },
    {
      "parameters": {
        "method": "POST",
        "url": "https://videotok.app/api/v1/generations",
        "sendHeaders": true,
        "headerParameters": {
          "parameters": [
            {
              "name": "Authorization",
              "value": "=Bearer {{$vars.VIDEOTOK_API_KEY}}"
            },
            {
              "name": "Content-Type",
              "value": "application/json"
            },
            {
              "name": "Idempotency-Key",
              "value": "={{$json.idempotency_key}}"
            }
          ]
        },
        "sendBody": true,
        "specifyBody": "json",
        "jsonBody": "={{$json}}"
      },
      "id": "videotok-generate",
      "name": "Submit to Videotok API",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [528, 128]
    },
    {
      "parameters": {
        "amount": 90,
        "unit": "seconds"
      },
      "id": "wait",
      "name": "Wait 90 Seconds",
      "type": "n8n-nodes-base.wait",
      "typeVersion": 1.1,
      "position": [784, 128]
    },
    {
      "parameters": {
        "url": "=https://videotok.app/api/v1/generations/{{$json.id || $json.generation_id}}",
        "sendHeaders": true,
        "headerParameters": {
          "parameters": [
            {
              "name": "Authorization",
              "value": "=Bearer {{$vars.VIDEOTOK_API_KEY}}"
            }
          ]
        }
      },
      "id": "poll",
      "name": "Retrieve From Videotok API",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [1040, 128]
    }
  ],
  "connections": {
    "When Manual Product Triggered": {
      "main": [
        [
          {
            "node": "Set Product Information",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Set Product Information": {
      "main": [
        [
          {
            "node": "Send to OpenAI for Ad Ideas",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Send to OpenAI for Ad Ideas": {
      "main": [
        [
          {
            "node": "Generate Ad Payloads",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Generate Ad Payloads": {
      "main": [
        [
          {
            "node": "Submit to Videotok API",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Submit to Videotok API": {
      "main": [
        [
          {
            "node": "Wait 90 Seconds",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Wait 90 Seconds": {
      "main": [
        [
          {
            "node": "Retrieve From Videotok API",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  },
  "pinData": {},
  "settings": {
    "executionOrder": "v1"
  },
  "tags": ["videotok", "openai", "ecommerce", "product ads"],
  "active": false,
  "versionId": "videotok-product-drop-ad-factory-1"
}
