{
  "name": "AI Animated Shorts Factory (9:16) - 10/day - 5 Characters - TG Approve - YT Upload",
  "nodes": [
    {
      "parameters": {
        "triggerTimes": {
          "item": [
            {
              "mode": "everyDay",
              "hour": 9,
              "minute": 0
            }
          ]
        }
      },
      "id": "CronDaily",
      "name": "Cron (Daily)",
      "type": "n8n-nodes-base.cron",
      "typeVersion": 1,
      "position": [
        -980,
        -240
      ]
    },
    {
      "parameters": {
        "values": {
          "string": [
            {
              "name": "batchDate",
              "value": "={{$now.toISODate()}}"
            },
            {
              "name": "nVideos",
              "value": "10"
            },
            {
              "name": "format",
              "value": "9:16"
            },
            {
              "name": "niche",
              "value": "AI_ANIMATED_TALKING_VIDEOS"
            },
            {
              "name": "LANG_MODE",
              "value": "both"
            }
          ],
          "json": [
            {
              "name": "TEMPLATE_IDS",
              "value": "={{[\n  'HEYGEN_TEMPLATE_ID_1',\n  'HEYGEN_TEMPLATE_ID_2',\n  'HEYGEN_TEMPLATE_ID_3',\n  'HEYGEN_TEMPLATE_ID_4',\n  'HEYGEN_TEMPLATE_ID_5'\n]}}"
            },
            {
              "name": "ELEVEN_VOICE",
              "value": "={{{\n  ar: 'ELEVENLABS_VOICE_ID_AR',\n  en: 'ELEVENLABS_VOICE_ID_EN'\n}}}"
            }
          ]
        }
      },
      "id": "SetConfig",
      "name": "Set Config",
      "type": "n8n-nodes-base.set",
      "typeVersion": 2,
      "position": [
        -760,
        -240
      ]
    },
    {
      "parameters": {
        "operation": "set",
        "key": "={{'run:' + $json.batchDate}}",
        "value": "={{ { status: 'started', date: $json.batchDate, n: $json.nVideos, format: $json.format } }}"
      },
      "id": "DSRunStart",
      "name": "Data Store: Run Started",
      "type": "n8n-nodes-base.dataStore",
      "typeVersion": 1,
      "position": [
        -540,
        -240
      ]
    },
    {
      "parameters": {
        "url": "https://YOUR_TRENDS_ENDPOINT",
        "method": "GET",
        "responseFormat": "json",
        "options": {
          "timeout": 30000
        }
      },
      "id": "FetchTrends",
      "name": "HTTP: Fetch Trends (placeholder)",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4,
      "position": [
        -320,
        -240
      ]
    },
    {
      "parameters": {
        "model": "gpt-4o-mini",
        "messages": [
          {
            "role": "system",
            "content": "You are a trend selector for short vertical talking animated videos. Output ONLY JSON."
          },
          {
            "role": "user",
            "content": "From these raw trend signals: {{$json}}, select exactly 10 topics suitable for 60\u201390 seconds animated talking videos (vertical 9:16). Each must be story-worthy and high retention.\nReturn JSON array with fields: id(1..10), topic, angle, keywords[]."
          }
        ],
        "responseFormat": "json"
      },
      "id": "OpenAISelectTopics",
      "name": "OpenAI: Select 10 Topics",
      "type": "n8n-nodes-base.openAi",
      "typeVersion": 1,
      "position": [
        -80,
        -240
      ],
      "credentials": {
        "openAiApi": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "functionCode": "const topics = Array.isArray($json) ? $json : ($json?.topics || $json?.data || []);\nif (!Array.isArray(topics) || topics.length !== 10) throw new Error('Expected exactly 10 topics');\nreturn topics.map(t => ({ json: { ...t, batchDate: $node['Set Config'].json.batchDate } }));"
      },
      "id": "NormalizeTopics",
      "name": "Function: Normalize to 10 items",
      "type": "n8n-nodes-base.function",
      "typeVersion": 2,
      "position": [
        160,
        -240
      ]
    },
    {
      "parameters": {
        "batchSize": 1
      },
      "id": "SplitInBatches",
      "name": "Split in Batches (10 items)",
      "type": "n8n-nodes-base.splitInBatches",
      "typeVersion": 3,
      "position": [
        400,
        -240
      ]
    },
    {
      "parameters": {
        "functionCode": "const idx = $itemIndex;\nconst cfg = $node['Set Config'].json;\nconst lang = (idx % 2 === 0) ? 'ar' : 'en';\nconst templates = cfg.TEMPLATE_IDS;\nconst template_id = templates[idx % templates.length];\nreturn [{ json: { ...$json, lang, template_id, format: cfg.format } }];"
      },
      "id": "PickLangAndTemplate",
      "name": "Function: Pick lang + template (5 chars)",
      "type": "n8n-nodes-base.function",
      "typeVersion": 2,
      "position": [
        640,
        -240
      ]
    },
    {
      "parameters": {
        "model": "gpt-4o-mini",
        "messages": [
          {
            "role": "system",
            "content": "You are a professional director for AI animated talking videos. Output ONLY JSON."
          },
          {
            "role": "user",
            "content": "Create a PRODUCTION PACKAGE for a 60\u201390 second vertical (9:16) animated talking video.\nLanguage: {{$json.lang}}\nTopic: {{$json.topic}}\nAngle: {{$json.angle}}\nKeywords: {{$json.keywords}}\n\nRules (monetization-safe originality):\n- Must be original & value-adding: commentary/analysis/storyline + cause\u2192effect.\n- Hook in first 3\u20135 seconds.\n- Pattern interrupts every 10\u201315 seconds (quick question, reveal, recap, on-screen emphasis).\n- No recycled wording.\n- End with summary + CTA.\n\nOutput ONLY JSON:\n{\n  \"video_id\":\"v{{$json.id}}-{{$json.batchDate}}\",\n  \"youtube_title\":\"...\",\n  \"thumbnail_text\":\"...\",\n  \"voice_text\":\"(final narration text)\",\n  \"on_screen_captions\":[{\"t\":\"00:00\",\"text\":\"...\"}],\n  \"subtitle_srt\":\"SRT...\",\n  \"heygen_script\":\"(script formatted for HeyGen template variables)\",\n  \"fb_caption\":\"...\",\n  \"fb_tags\":[\"...\"],\n  \"tiktok_caption\":\"...\",\n  \"tiktok_hashtags\":[\"...\"]\n}"
          }
        ],
        "responseFormat": "json"
      },
      "id": "OpenAIPackage",
      "name": "OpenAI: Video Package",
      "type": "n8n-nodes-base.openAi",
      "typeVersion": 1,
      "position": [
        900,
        -240
      ],
      "credentials": {
        "openAiApi": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "operation": "set",
        "key": "={{'log:' + $json.video_id}}",
        "value": "={{ { status: 'package_done', at: $now.toISO(), meta: $json } }}"
      },
      "id": "DSLogPackage",
      "name": "Data Store: log package done",
      "type": "n8n-nodes-base.dataStore",
      "typeVersion": 1,
      "position": [
        1140,
        -240
      ]
    },
    {
      "parameters": {
        "url": "={{'https://api.elevenlabs.io/v1/text-to-speech/' + $node['Set Config'].json.ELEVEN_VOICE[$node['Function: Pick lang + template (5 chars)'].json.lang]}}",
        "method": "POST",
        "responseFormat": "file",
        "jsonParameters": true,
        "options": {
          "timeout": 300000
        },
        "headerParametersJson": "={\"xi-api-key\":\"YOUR_ELEVENLABS_API_KEY\",\"accept\":\"audio/mpeg\"}",
        "bodyParametersJson": "={\n  \"text\": $node['OpenAI: Video Package'].json.voice_text,\n  \"model_id\": \"eleven_multilingual_v2\",\n  \"voice_settings\": {\"stability\": 0.45, \"similarity_boost\": 0.8}\n}"
      },
      "id": "ElevenTTS",
      "name": "HTTP: ElevenLabs TTS (MP3)",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4,
      "position": [
        1380,
        -240
      ],
      "continueOnFail": true
    },
    {
      "parameters": {
        "if": {
          "conditions": {
            "boolean": [
              {
                "value1": "={{!!$json.error}}",
                "value2": true
              }
            ]
          }
        }
      },
      "id": "IfTTSFailed",
      "name": "IF: TTS failed?",
      "type": "n8n-nodes-base.if",
      "typeVersion": 2,
      "position": [
        1600,
        -240
      ]
    },
    {
      "parameters": {
        "operation": "set",
        "key": "={{'log:' + $node['OpenAI: Video Package'].json.video_id}}",
        "value": "={{ { status: 'tts_failed', at: $now.toISO(), error: $json } }}"
      },
      "id": "DSLogTTSFail",
      "name": "Data Store: log TTS failed",
      "type": "n8n-nodes-base.dataStore",
      "typeVersion": 1,
      "position": [
        1820,
        -360
      ]
    },
    {
      "parameters": {
        "url": "https://graph.facebook.com/v20.0/YOUR_PHONE_NUMBER_ID/messages",
        "method": "POST",
        "responseFormat": "json",
        "jsonParameters": true,
        "options": {
          "timeout": 30000
        },
        "headerParametersJson": "={\"Authorization\":\"Bearer YOUR_WHATSAPP_TOKEN\"}",
        "bodyParametersJson": "={\n  \"messaging_product\": \"whatsapp\",\n  \"to\": \"YOUR_WHATSAPP_NUMBER_IN_E164\",\n  \"type\": \"template\",\n  \"template\": {\n    \"name\": \"daily_alert_template\",\n    \"language\": {\"code\": \"en_US\"},\n    \"components\": [\n      {\"type\":\"body\",\"parameters\":[\n        {\"type\":\"text\",\"text\":\"TTS failed for \" + $node['OpenAI: Video Package'].json.video_id}\n      ]}\n    ]\n  }\n}"
      },
      "id": "WhatsAppTTSError",
      "name": "WhatsApp: Alert - TTS failed",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4,
      "position": [
        2040,
        -360
      ],
      "continueOnFail": true
    },
    {
      "parameters": {
        "operation": "set",
        "key": "={{'log:' + $node['OpenAI: Video Package'].json.video_id}}",
        "value": "={{ { status: 'tts_done', at: $now.toISO() } }}"
      },
      "id": "DSLogTTSDone",
      "name": "Data Store: log TTS done",
      "type": "n8n-nodes-base.dataStore",
      "typeVersion": 1,
      "position": [
        1820,
        -120
      ]
    },
    {
      "parameters": {
        "url": "https://api.heygen.com/v2/video/generate",
        "method": "POST",
        "responseFormat": "json",
        "jsonParameters": true,
        "options": {
          "timeout": 300000
        },
        "headerParametersJson": "={\"X-API-KEY\":\"YOUR_HEYGEN_API_KEY\"}",
        "bodyParametersJson": "={\n  \"video_inputs\": [\n    {\n      \"template_id\": $node['Function: Pick lang + template (5 chars)'].json.template_id,\n      \"variables\": {\n        \"script\": $node['OpenAI: Video Package'].json.heygen_script\n      }\n    }\n  ],\n  \"aspect_ratio\": \"9:16\",\n  \"test\": false\n}"
      },
      "id": "HeyGenGenerate",
      "name": "HTTP: HeyGen Generate Video",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4,
      "position": [
        2040,
        -120
      ],
      "continueOnFail": true
    },
    {
      "parameters": {
        "if": {
          "conditions": {
            "boolean": [
              {
                "value1": "={{!!$json.error}}",
                "value2": true
              }
            ]
          }
        }
      },
      "id": "IfHeyGenFailed",
      "name": "IF: HeyGen generate failed?",
      "type": "n8n-nodes-base.if",
      "typeVersion": 2,
      "position": [
        2260,
        -120
      ]
    },
    {
      "parameters": {
        "operation": "set",
        "key": "={{'log:' + $node['OpenAI: Video Package'].json.video_id}}",
        "value": "={{ { status: 'heygen_generate_failed', at: $now.toISO(), error: $json } }}"
      },
      "id": "DSLogHeyGenFail",
      "name": "Data Store: log HeyGen failed",
      "type": "n8n-nodes-base.dataStore",
      "typeVersion": 1,
      "position": [
        2480,
        -240
      ]
    },
    {
      "parameters": {
        "url": "https://graph.facebook.com/v20.0/YOUR_PHONE_NUMBER_ID/messages",
        "method": "POST",
        "responseFormat": "json",
        "jsonParameters": true,
        "options": {
          "timeout": 30000
        },
        "headerParametersJson": "={\"Authorization\":\"Bearer YOUR_WHATSAPP_TOKEN\"}",
        "bodyParametersJson": "={\n  \"messaging_product\": \"whatsapp\",\n  \"to\": \"YOUR_WHATSAPP_NUMBER_IN_E164\",\n  \"type\": \"template\",\n  \"template\": {\n    \"name\": \"daily_alert_template\",\n    \"language\": {\"code\": \"en_US\"},\n    \"components\": [\n      {\"type\":\"body\",\"parameters\":[\n        {\"type\":\"text\",\"text\":\"HeyGen generate failed for \" + $node['OpenAI: Video Package'].json.video_id}\n      ]}\n    ]\n  }\n}"
      },
      "id": "WhatsAppHeyGenError",
      "name": "WhatsApp: Alert - HeyGen failed",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4,
      "position": [
        2700,
        -240
      ],
      "continueOnFail": true
    },
    {
      "parameters": {
        "functionCode": "const vid = $node['OpenAI: Video Package'].json.video_id;\nconst jobId = $json.data?.video_id || $json.video_id || $json.data?.id || $json.id;\nif (!jobId) throw new Error('HeyGen response missing job/video id');\nreturn [{ json: { video_id: vid, heygen_job_id: jobId } }];"
      },
      "id": "ExtractHeyGenJob",
      "name": "Function: Extract HeyGen Job ID",
      "type": "n8n-nodes-base.function",
      "typeVersion": 2,
      "position": [
        2480,
        0
      ]
    },
    {
      "parameters": {
        "url": "={{'https://api.heygen.com/v1/video_status.get?video_id=' + $json.heygen_job_id}}",
        "method": "GET",
        "responseFormat": "json",
        "options": {
          "timeout": 30000
        },
        "headerParametersJson": "={\"X-API-KEY\":\"YOUR_HEYGEN_API_KEY\"}"
      },
      "id": "HeyGenStatus",
      "name": "HTTP: HeyGen Status",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4,
      "position": [
        2700,
        0
      ]
    },
    {
      "parameters": {
        "if": {
          "conditions": {
            "string": [
              {
                "value1": "={{$json.data?.status || $json.status}}",
                "operation": "equal",
                "value2": "completed"
              }
            ]
          }
        }
      },
      "id": "IfHeyGenCompleted",
      "name": "IF: HeyGen completed?",
      "type": "n8n-nodes-base.if",
      "typeVersion": 2,
      "position": [
        2920,
        0
      ]
    },
    {
      "parameters": {
        "seconds": 20
      },
      "id": "WaitPoll",
      "name": "Wait (20s)",
      "type": "n8n-nodes-base.wait",
      "typeVersion": 1,
      "position": [
        3140,
        120
      ]
    },
    {
      "parameters": {
        "functionCode": "const url = $json.data?.video_url || $json.video_url || $json.data?.url;\nif (!url) throw new Error('No video_url in HeyGen completed status');\nreturn [{ json: { video_url: url, video_id: $node['Function: Extract HeyGen Job ID'].json.video_id } }];"
      },
      "id": "ExtractVideoURL",
      "name": "Function: Extract video URL",
      "type": "n8n-nodes-base.function",
      "typeVersion": 2,
      "position": [
        3140,
        -80
      ]
    },
    {
      "parameters": {
        "url": "={{$json.video_url}}",
        "method": "GET",
        "responseFormat": "file",
        "options": {
          "timeout": 300000
        }
      },
      "id": "DownloadMP4",
      "name": "HTTP: Download MP4 (binary)",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4,
      "position": [
        3360,
        -80
      ]
    },
    {
      "parameters": {
        "chatId": "YOUR_TELEGRAM_CHAT_ID",
        "text": "={{'Approval needed \u2705\\nVideo: ' + $node['OpenAI: Video Package'].json.video_id + '\\nTitle: ' + $node['OpenAI: Video Package'].json.youtube_title + '\\nLang: ' + $node['Function: Pick lang + template (5 chars)'].json.lang + '\\nTemplate: ' + $node['Function: Pick lang + template (5 chars)'].json.template_id + '\\n\\nReply: /approve ' + $node['OpenAI: Video Package'].json.video_id}}"
      },
      "id": "TelegramApproval",
      "name": "Telegram: Request Approval",
      "type": "n8n-nodes-base.telegram",
      "typeVersion": 1,
      "position": [
        3580,
        -80
      ],
      "credentials": {
        "telegramApi": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "seconds": 20
      },
      "id": "WaitApprove",
      "name": "Wait (20s) Approve Poll",
      "type": "n8n-nodes-base.wait",
      "typeVersion": 1,
      "position": [
        3800,
        -80
      ]
    },
    {
      "parameters": {
        "operation": "get",
        "key": "={{'approve:' + $node['OpenAI: Video Package'].json.video_id}}"
      },
      "id": "DSCheckApprove",
      "name": "Data Store: Check Approval",
      "type": "n8n-nodes-base.dataStore",
      "typeVersion": 1,
      "position": [
        4020,
        -80
      ]
    },
    {
      "parameters": {
        "if": {
          "conditions": {
            "boolean": [
              {
                "value1": "={{$json && ($json.value === true || $json.value === 'true' || $json.approved === true)}}",
                "value2": true
              }
            ]
          }
        }
      },
      "id": "IfApproved",
      "name": "IF: Approved?",
      "type": "n8n-nodes-base.if",
      "typeVersion": 2,
      "position": [
        4240,
        -80
      ]
    },
    {
      "parameters": {
        "resource": "video",
        "operation": "upload",
        "title": "={{$node['OpenAI: Video Package'].json.youtube_title}}",
        "description": "={{$node['OpenAI: Video Package'].json.tiktok_caption}}",
        "additionalFields": {
          "privacyStatus": "public"
        }
      },
      "id": "YouTubeUpload",
      "name": "YouTube: Upload (binary required)",
      "type": "n8n-nodes-base.youtube",
      "typeVersion": 1,
      "position": [
        4460,
        -140
      ],
      "credentials": {
        "youTubeOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "continueOnFail": true
    },
    {
      "parameters": {
        "operation": "set",
        "key": "={{'log:' + $node['OpenAI: Video Package'].json.video_id}}",
        "value": "={{ { status: 'published_youtube', at: $now.toISO(), youtube: $node['YouTube: Upload (binary required)'].json } }}"
      },
      "id": "DSLogPublished",
      "name": "Data Store: log published",
      "type": "n8n-nodes-base.dataStore",
      "typeVersion": 1,
      "position": [
        4680,
        -140
      ]
    },
    {
      "parameters": {
        "url": "https://graph.facebook.com/v20.0/YOUR_PHONE_NUMBER_ID/messages",
        "method": "POST",
        "responseFormat": "json",
        "jsonParameters": true,
        "options": {
          "timeout": 30000
        },
        "headerParametersJson": "={\"Authorization\":\"Bearer YOUR_WHATSAPP_TOKEN\"}",
        "bodyParametersJson": "={\n  \"messaging_product\": \"whatsapp\",\n  \"to\": \"YOUR_WHATSAPP_NUMBER_IN_E164\",\n  \"type\": \"template\",\n  \"template\": {\n    \"name\": \"daily_alert_template\",\n    \"language\": {\"code\": \"en_US\"},\n    \"components\": [\n      {\"type\":\"body\",\"parameters\":[\n        {\"type\":\"text\",\"text\":\"Published on YouTube: \" + $node['OpenAI: Video Package'].json.video_id}\n      ]}\n    ]\n  }\n}"
      },
      "id": "WhatsAppPublished",
      "name": "WhatsApp: Alert - Published",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4,
      "position": [
        4900,
        -140
      ],
      "continueOnFail": true
    },
    {
      "parameters": {},
      "id": "NoOpNext",
      "name": "Next Item",
      "type": "n8n-nodes-base.noOp",
      "typeVersion": 1,
      "position": [
        5120,
        -140
      ]
    },
    {
      "parameters": {
        "operation": "set",
        "key": "={{'run:' + $node['Set Config'].json.batchDate}}",
        "value": "={{ { status: 'completed', date: $node['Set Config'].json.batchDate, completedAt: $now.toISO() } }}"
      },
      "id": "DSRunDone",
      "name": "Data Store: Run Completed",
      "type": "n8n-nodes-base.dataStore",
      "typeVersion": 1,
      "position": [
        5340,
        -240
      ]
    },
    {
      "parameters": {
        "chatId": "YOUR_TELEGRAM_CHAT_ID",
        "text": "={{'\u2705 Batch completed: ' + $node['Set Config'].json.batchDate + ' | 10 videos attempted (9:16, 5 characters, AR/EN).'}}"
      },
      "id": "TelegramDone",
      "name": "Telegram: Batch Done",
      "type": "n8n-nodes-base.telegram",
      "typeVersion": 1,
      "position": [
        5560,
        -240
      ],
      "credentials": {
        "telegramApi": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {},
      "id": "TelegramTrigger",
      "name": "Telegram Trigger (commands)",
      "type": "n8n-nodes-base.telegramTrigger",
      "typeVersion": 1,
      "position": [
        -980,
        240
      ],
      "credentials": {
        "telegramApi": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "functionCode": "const text = ($json.message?.text || '').trim();\nconst chatId = $json.message?.chat?.id;\nif (!text) return [{ json: { ok:false, reason:'no_text', chatId } }];\nconst parts = text.split(/\\s+/);\nconst cmd = parts[0].toLowerCase();\nconst video_id = parts[1];\nreturn [{ json: { ok:true, cmd, video_id, chatId, raw:text } }];"
      },
      "id": "ParseTelegram",
      "name": "Function: Parse Telegram",
      "type": "n8n-nodes-base.function",
      "typeVersion": 2,
      "position": [
        -760,
        240
      ]
    },
    {
      "parameters": {
        "switch": {
          "property": "={{$json.cmd}}",
          "rules": [
            {
              "operation": "equal",
              "value": "/approve"
            }
          ]
        }
      },
      "id": "SwitchCmd",
      "name": "Switch: /approve",
      "type": "n8n-nodes-base.switch",
      "typeVersion": 2,
      "position": [
        -540,
        240
      ]
    },
    {
      "parameters": {
        "operation": "set",
        "key": "={{'approve:' + $json.video_id}}",
        "value": "={{ { approved: true, at: $now.toISO(), by: $json.chatId } }}"
      },
      "id": "DSApprove",
      "name": "Data Store: set approve",
      "type": "n8n-nodes-base.dataStore",
      "typeVersion": 1,
      "position": [
        -320,
        240
      ]
    },
    {
      "parameters": {
        "chatId": "={{$json.chatId}}",
        "text": "={{'\u2705 Approved: ' + $json.video_id}}"
      },
      "id": "TelegramAck",
      "name": "Telegram: Ack Approve",
      "type": "n8n-nodes-base.telegram",
      "typeVersion": 1,
      "position": [
        -100,
        240
      ],
      "credentials": {
        "telegramApi": {
          "name": "<your credential>"
        }
      }
    }
  ],
  "connections": {
    "Cron (Daily)": {
      "main": [
        [
          {
            "node": "Set Config",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Set Config": {
      "main": [
        [
          {
            "node": "Data Store: Run Started",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Data Store: Run Started": {
      "main": [
        [
          {
            "node": "HTTP: Fetch Trends (placeholder)",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "HTTP: Fetch Trends (placeholder)": {
      "main": [
        [
          {
            "node": "OpenAI: Select 10 Topics",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "OpenAI: Select 10 Topics": {
      "main": [
        [
          {
            "node": "Function: Normalize to 10 items",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Function: Normalize to 10 items": {
      "main": [
        [
          {
            "node": "Split in Batches (10 items)",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Split in Batches (10 items)": {
      "main": [
        [
          {
            "node": "Function: Pick lang + template (5 chars)",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Data Store: Run Completed",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Function: Pick lang + template (5 chars)": {
      "main": [
        [
          {
            "node": "OpenAI: Video Package",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "OpenAI: Video Package": {
      "main": [
        [
          {
            "node": "Data Store: log package done",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Data Store: log package done": {
      "main": [
        [
          {
            "node": "HTTP: ElevenLabs TTS (MP3)",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "HTTP: ElevenLabs TTS (MP3)": {
      "main": [
        [
          {
            "node": "IF: TTS failed?",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "IF: TTS failed?": {
      "main": [
        [
          {
            "node": "Data Store: log TTS failed",
            "type": "main",
            "index": 0
          },
          {
            "node": "WhatsApp: Alert - TTS failed",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Data Store: log TTS done",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Data Store: log TTS done": {
      "main": [
        [
          {
            "node": "HTTP: HeyGen Generate Video",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "HTTP: HeyGen Generate Video": {
      "main": [
        [
          {
            "node": "IF: HeyGen generate failed?",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "IF: HeyGen generate failed?": {
      "main": [
        [
          {
            "node": "Data Store: log HeyGen failed",
            "type": "main",
            "index": 0
          },
          {
            "node": "WhatsApp: Alert - HeyGen failed",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Function: Extract HeyGen Job ID",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Function: Extract HeyGen Job ID": {
      "main": [
        [
          {
            "node": "HTTP: HeyGen Status",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "HTTP: HeyGen Status": {
      "main": [
        [
          {
            "node": "IF: HeyGen completed?",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "IF: HeyGen completed?": {
      "main": [
        [
          {
            "node": "Function: Extract video URL",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Wait (20s)",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Wait (20s)": {
      "main": [
        [
          {
            "node": "HTTP: HeyGen Status",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Function: Extract video URL": {
      "main": [
        [
          {
            "node": "HTTP: Download MP4 (binary)",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "HTTP: Download MP4 (binary)": {
      "main": [
        [
          {
            "node": "Telegram: Request Approval",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Telegram: Request Approval": {
      "main": [
        [
          {
            "node": "Wait (20s) Approve Poll",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Wait (20s) Approve Poll": {
      "main": [
        [
          {
            "node": "Data Store: Check Approval",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Data Store: Check Approval": {
      "main": [
        [
          {
            "node": "IF: Approved?",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "IF: Approved?": {
      "main": [
        [
          {
            "node": "YouTube: Upload (binary required)",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Wait (20s) Approve Poll",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "YouTube: Upload (binary required)": {
      "main": [
        [
          {
            "node": "Data Store: log published",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Data Store: log published": {
      "main": [
        [
          {
            "node": "WhatsApp: Alert - Published",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "WhatsApp: Alert - Published": {
      "main": [
        [
          {
            "node": "Next Item",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Next Item": {
      "main": [
        [
          {
            "node": "Split in Batches (10 items)",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Data Store: Run Completed": {
      "main": [
        [
          {
            "node": "Telegram: Batch Done",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Telegram Trigger (commands)": {
      "main": [
        [
          {
            "node": "Function: Parse Telegram",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Function: Parse Telegram": {
      "main": [
        [
          {
            "node": "Switch: /approve",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Switch: /approve": {
      "main": [
        [
          {
            "node": "Data Store: set approve",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Data Store: set approve": {
      "main": [
        [
          {
            "node": "Telegram: Ack Approve",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  },
  "active": false,
  "settings": {
    "executionTimeout": 7200,
    "saveExecutionProgress": true,
    "saveManualExecutions": true,
    "timezone": "Africa/Cairo"
  },
  "versionId": "1"
}