{
  "id": "NToMW6sFTYKqdLrT",
  "meta": {
    "templateCredsSetupCompleted": true
  },
  "name": "New Video \u2192 Thumbnail + Quotes \u2192 Gmail Draft",
  "tags": [],
  "nodes": [
    {
      "id": "d9039857-2345-4988-bb96-c741efb21b7f",
      "name": "When Video Added to Drive",
      "type": "n8n-nodes-base.googleDriveTrigger",
      "position": [
        37312,
        13920
      ],
      "parameters": {
        "event": "fileCreated",
        "options": {},
        "pollTimes": {
          "item": [
            {
              "mode": "everyMinute"
            }
          ]
        },
        "triggerOn": "specificFolder",
        "folderToWatch": {
          "__rl": true,
          "mode": "list",
          "value": ""
        }
      },
      "typeVersion": 1
    },
    {
      "id": "8028cf25-595d-40a3-a4dc-41cd4f63e3ef",
      "name": "Download Video",
      "type": "n8n-nodes-base.googleDrive",
      "position": [
        37536,
        13920
      ],
      "parameters": {
        "fileId": {
          "__rl": true,
          "mode": "id",
          "value": "={{ $json.id }}"
        },
        "options": {},
        "operation": "download"
      },
      "typeVersion": 3
    },
    {
      "id": "b863266a-cbbe-4b56-affd-9fbb1745b84b",
      "name": "Transcribe Audio",
      "type": "@n8n/n8n-nodes-langchain.openAi",
      "position": [
        37744,
        13920
      ],
      "parameters": {
        "options": {},
        "resource": "audio",
        "operation": "transcribe"
      },
      "typeVersion": 1.8
    },
    {
      "id": "9e1dbf9e-0495-4c00-9f07-56842ffd2823",
      "name": "Extract Thumbnail + Quotes",
      "type": "@n8n/n8n-nodes-langchain.openAi",
      "position": [
        37952,
        13920
      ],
      "parameters": {
        "modelId": {
          "__rl": true,
          "mode": "list",
          "value": "gpt-5-mini",
          "cachedResultName": "gpt-5-mini"
        },
        "options": {},
        "messages": {
          "values": [
            {
              "content": "=From this video transcript, return STRICT JSON only: {\"headline\": \"a punchy 4-7 word thumbnail headline\", \"quotes\": [\"quote 1\", \"quote 2\", \"quote 3\"]}. Transcript: {{ $('Transcribe Audio').item.json.text }}"
            }
          ]
        }
      },
      "typeVersion": 1.8
    },
    {
      "id": "db28979f-4dd3-4b30-bd07-2ab5142c368c",
      "name": "Parse Concept",
      "type": "n8n-nodes-base.code",
      "position": [
        38208,
        13920
      ],
      "parameters": {
        "jsCode": "const raw = $json.message?.content ?? $json.text ?? $json.content ?? '';\nlet a; try { a = JSON.parse(raw); } catch(e){ const m=String(raw).match(/\\{[\\s\\S]*\\}/); a=m?JSON.parse(m[0]):{headline:'',quotes:[]}; }\nconst content = `${a.headline}\\n\\n` + (a.quotes||[]).map(q=>`\\u201C${q}\\u201D`).join('\\n');\nreturn [{ json: { headline: a.headline, content } }];"
      },
      "typeVersion": 2
    },
    {
      "id": "47c43fde-e672-4f6c-acb8-2651d7229e75",
      "name": "Post to Canvora",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        38512,
        13920
      ],
      "parameters": {
        "url": "https://api.canvora.ai/api/generations",
        "method": "POST",
        "options": {},
        "jsonBody": "={{ JSON.stringify({\n  inputType: 'text',\n  inputContent: $('Parse Concept').item.json.content,\n  title: 'Video kit: ' + $('Parse Concept').item.json.headline,\n  outputFormats: ['youtube_thumbnail', 'quote_card']\n}) }}",
        "sendBody": true,
        "specifyBody": "json",
        "authentication": "genericCredentialType",
        "genericAuthType": "httpHeaderAuth"
      },
      "typeVersion": 4.2
    },
    {
      "id": "9b2983c5-4ac5-4798-b692-b1dae61680f2",
      "name": "Wait 30s",
      "type": "n8n-nodes-base.wait",
      "position": [
        38864,
        13920
      ],
      "parameters": {
        "amount": 30
      },
      "typeVersion": 1.1
    },
    {
      "id": "82236fd0-6fca-49e1-9915-dd6af9e9a241",
      "name": "Fetch Generation Status",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        39072,
        13920
      ],
      "parameters": {
        "url": "=https://api.canvora.ai/api/generations/{{ $('Post to Canvora').item.json.generation.id }}",
        "options": {},
        "authentication": "genericCredentialType",
        "genericAuthType": "httpHeaderAuth"
      },
      "typeVersion": 4.2
    },
    {
      "id": "096092d2-db6e-4fb9-bdb6-b486e4600c14",
      "name": "If Generation Done",
      "type": "n8n-nodes-base.if",
      "position": [
        39280,
        13920
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 1,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "t41",
              "operator": {
                "type": "boolean",
                "operation": "true",
                "singleValue": true
              },
              "leftValue": "={{ ['completed','failed','partial','cancelled'].includes($json.generation.status) }}",
              "rightValue": true
            }
          ]
        }
      },
      "typeVersion": 2
    },
    {
      "id": "147a22c8-7711-4402-a427-c5fb7955770e",
      "name": "If Timed Out",
      "type": "n8n-nodes-base.if",
      "position": [
        39280,
        14128
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 1,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "t42",
              "operator": {
                "type": "boolean",
                "operation": "true",
                "singleValue": true
              },
              "leftValue": "={{ $runIndex >= 20 }}",
              "rightValue": true
            }
          ]
        }
      },
      "typeVersion": 2
    },
    {
      "id": "332b1880-06c2-48a3-8fe5-d0cbc0250255",
      "name": "If Generation Succeeded",
      "type": "n8n-nodes-base.if",
      "position": [
        39632,
        13920
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 1,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "t43",
              "operator": {
                "type": "boolean",
                "operation": "true",
                "singleValue": true
              },
              "leftValue": "={{ ['completed','partial'].includes($json.generation.status) }}",
              "rightValue": true
            }
          ]
        }
      },
      "typeVersion": 2
    },
    {
      "id": "3f11304a-c621-47e8-9f08-a8a6cbf34f90",
      "name": "Build Review Email",
      "type": "n8n-nodes-base.code",
      "position": [
        39840,
        13920
      ],
      "parameters": {
        "jsCode": "const g = $input.first().json.generation;\nconst outs = g.outputs || [];\nconst imgs = outs.map(o => `<p><b>${o.format}</b><br><img src=\"${o.fileUrl}\" width=\"480\"/></p>`).join('\\n');\nconst html = `<h2>${$('Parse Concept').item.json.headline}</h2>\\n${imgs}\\n<p>Edit: https://canvora.ai/generations/${g.id}</p>`;\nreturn [{ json: { subject: 'Video visuals ready: ' + $('Parse Concept').item.json.headline, html } }];"
      },
      "typeVersion": 2
    },
    {
      "id": "8aefe662-1fda-4a58-ab2c-eb84eb121f6b",
      "name": "Create Gmail Draft",
      "type": "n8n-nodes-base.gmail",
      "position": [
        40048,
        13920
      ],
      "parameters": {
        "message": "={{ $json.html }}",
        "options": {},
        "subject": "={{ $json.subject }}",
        "resource": "draft"
      },
      "typeVersion": 2.1
    },
    {
      "id": "fcf7569f-3eea-48fa-8f77-2c90ea2141a2",
      "name": "Generation Failed (credits auto-refunded)",
      "type": "n8n-nodes-base.noOp",
      "position": [
        39952,
        14336
      ],
      "parameters": {},
      "typeVersion": 1
    },
    {
      "id": "1af8e5b9-ac06-4858-820c-2b8492d23c90",
      "name": "Sticky Note",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        36592,
        13648
      ],
      "parameters": {
        "color": 7,
        "width": 560,
        "height": 1056,
        "content": "## New Video \u2192 Thumbnail + Quote Cards \u2192 Drive + Gmail Draft\n\n### How it works\nDrop a video into a watched Google Drive folder. The workflow transcribes it,\nan AI model pulls a punchy **thumbnail headline** and three **pull-quotes**,\nand Canvora designs a **YouTube thumbnail** plus **quote cards** \u2014 on brand.\nThe finished visuals are assembled into a **Gmail draft** for a quick review\nbefore you publish (no auto-send, no Slack).\n\n### Setup steps\n- Create a free Canvora account at canvora.ai \u2014 free credits, no card \u2014 and\n  copy an API key from Integrations \u2192 API Keys (all plans).\n- In each Canvora HTTP Request node, add a **Header Auth** credential:\n  name `X-API-Key`, value your `vd_...` key.\n- Connect your Google Drive and Gmail credentials.\n- Add your OpenAI credential (used for transcription + concept extraction).\n- In the trigger, pick the Drive folder you'll drop videos into.\n\n### Customization\n- Add `instagram_reel` or `twitter_post` to `outputFormats` for more clip\n  art (100+ formats: GET https://api.canvora.ai/api/formats).\n- Pass a `brandId` (GET /api/brands) to lock visuals to your brand kit.\n- Change \"Create Gmail Draft\" to \"send\" to skip review, or upload the images\n  to Drive instead.\n- Cost: 2 visuals = 20 credits per video.\n"
      },
      "typeVersion": 1
    },
    {
      "id": "47956295-1c4e-4932-9602-0e3bb45481aa",
      "name": "Sticky Note100",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        37216,
        13760
      ],
      "parameters": {
        "color": 7,
        "width": 1134,
        "height": 406,
        "content": "## Transcribe the video\n\nWhen a video lands in the watched Drive folder, it's downloaded, transcribed, and an AI model pulls a headline + pull-quotes."
      },
      "typeVersion": 1
    },
    {
      "id": "5193d698-7f5e-49ce-8117-d8e6370f1742",
      "name": "Sticky Note101",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        38464,
        13680
      ],
      "parameters": {
        "color": 7,
        "height": 390,
        "content": "## Design the visuals\n\nSends the concept to Canvora, which designs a YouTube thumbnail and quote cards."
      },
      "typeVersion": 1
    },
    {
      "id": "0bf70099-1a75-485c-940e-a2d500655de3",
      "name": "Sticky Note102",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        38768,
        13760
      ],
      "parameters": {
        "color": 7,
        "width": 698,
        "height": 626,
        "content": "## Poll generation status\n\nWaits between checks, fetches the state, and loops until the visuals finish or it times out."
      },
      "typeVersion": 1
    },
    {
      "id": "0954989e-68f7-4a3c-86ad-c66237276a74",
      "name": "Sticky Note103",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        39568,
        13760
      ],
      "parameters": {
        "color": 7,
        "width": 666,
        "height": 310,
        "content": "## Deliver for review\n\nOn success, assembles the visuals into a Gmail draft for a quick review before publishing."
      },
      "typeVersion": 1
    },
    {
      "id": "8b1b2211-9214-4f1f-ac60-7dbaef7c43f7",
      "name": "Sticky Note104",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        39888,
        14112
      ],
      "parameters": {
        "color": 7,
        "width": 256,
        "height": 390,
        "content": "## Handle failure\n\nIf generation fails or times out, credits are refunded automatically."
      },
      "typeVersion": 1
    }
  ],
  "active": false,
  "settings": {
    "binaryMode": "separate",
    "availableInMCP": false,
    "executionOrder": "v1"
  },
  "versionId": "ed4825e8-4163-493b-9b51-1a1e92bcbf2f",
  "nodeGroups": [],
  "connections": {
    "Wait 30s": {
      "main": [
        [
          {
            "node": "Fetch Generation Status",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "If Timed Out": {
      "main": [
        [
          {
            "node": "Generation Failed (credits auto-refunded)",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Wait 30s",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Parse Concept": {
      "main": [
        [
          {
            "node": "Post to Canvora",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Download Video": {
      "main": [
        [
          {
            "node": "Transcribe Audio",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Post to Canvora": {
      "main": [
        [
          {
            "node": "Wait 30s",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Transcribe Audio": {
      "main": [
        [
          {
            "node": "Extract Thumbnail + Quotes",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Build Review Email": {
      "main": [
        [
          {
            "node": "Create Gmail Draft",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "If Generation Done": {
      "main": [
        [
          {
            "node": "If Generation Succeeded",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "If Timed Out",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Fetch Generation Status": {
      "main": [
        [
          {
            "node": "If Generation Done",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "If Generation Succeeded": {
      "main": [
        [
          {
            "node": "Build Review Email",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Generation Failed (credits auto-refunded)",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "When Video Added to Drive": {
      "main": [
        [
          {
            "node": "Download Video",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Extract Thumbnail + Quotes": {
      "main": [
        [
          {
            "node": "Parse Concept",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  }
}