{
  "meta": {
    "templateCredsSetupCompleted": true
  },
  "nodes": [
    {
      "id": "ab09ff2b-e6c6-4218-8d40-e4eab6eab2d8",
      "name": "Overview",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -608,
        -800
      ],
      "parameters": {
        "color": 4,
        "width": 508,
        "height": 1092,
        "content": "## Earnings Call to Investor Highlight Reel to Notion \u2014 WayinVideo Find Moments + GPT-4o-mini + Notion\n\nFor investment analysts, fund managers, IR teams, and financial content creators who regularly review earnings calls and want to automatically extract and organize the most important financial moments \u2014 without manually scrubbing through recordings. Submit an earnings call URL and your financial topics query via the form. WayinVideo Find Moments API scans the full recording and returns up to 8 matching moments with titles, descriptions, timestamps, and relevance scores. GPT-4o-mini analyzes each moment and generates an 8-section investor highlight including topic category, investor summary, key metrics mentioned, why it matters, sentiment with reasoning, flags for attention, and pre-formatted Notion page content. One Notion page is created per highlight in your Investor Intelligence database.\n\n## How it works\n- **1. Form \u2014 Earnings Call + Details** collects the recording URL, company name, ticker, quarter, call date, financial topics query, and optional investment thesis\n- **2. WayinVideo \u2014 Submit Find Moments** submits the URL and topics query to Find Moments API \u2014 up to 8 matching moments returned\n- **3. Wait \u2014 90 Seconds** gives the API initial processing time\n- **4. WayinVideo \u2014 Get Moments Results** polls the find-moments results endpoint\n- **5. IF \u2014 Find Moments Complete?** checks for SUCCEEDED \u2014 if not, retries via 30-second wait\n- **7. Code \u2014 Extract Highlight Clips** reads the clips array, converts millisecond timestamps, passes totalClips for AI context, and returns one item per clip\n- **8. AI Agent \u2014 Generate Investor Highlight** uses GPT-4o-mini to write an 8-section investor analysis including pre-formatted Notion page content\n- **10. Code \u2014 Parse Investor Analysis** extracts all 8 sections via regex, builds the Notion page title, and assembles the final record\n- **11. Notion \u2014 Create Highlight Page** creates one Notion page per financial highlight in your Investor Intelligence database\n\n## Set up steps\n1. In **2. WayinVideo \u2014 Submit Find Moments** and **4. WayinVideo \u2014 Get Moments Results** \u2014 replace YOUR_WAYINVIDEO_API_KEY\n2. In **9. OpenAI \u2014 GPT-4o-mini Model** \u2014 connect your OpenAI credential\n3. In **11. Notion \u2014 Create Highlight Page** \u2014 connect your Notion OAuth2 credential and set the parent database ID\n4. Create a Notion database named Investor Intelligence with properties: Title (title), Company (text), Ticker Symbol (text), Quarter (text), Topic Category (select), Sentiment (select), Timestamp (text), Relevance Score (number), Recording URL (url), Call Date (date), Status (select \u2014 default New)"
      },
      "typeVersion": 1
    },
    {
      "id": "9bfa1461-fe64-4f81-916f-eaa0ae93a63a",
      "name": "Section \u2014 Form Input",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -16,
        -512
      ],
      "parameters": {
        "color": 5,
        "width": 324,
        "height": 372,
        "content": "## Form Input\nAnalyst submits earnings call URL, company name, ticker symbol, quarter, call date, financial topics query, and optional investment thesis. The topics query drives which moments WayinVideo finds \u2014 be specific for better results."
      },
      "typeVersion": 1
    },
    {
      "id": "863d21fe-f8e1-46d2-bfae-6aa880816cb0",
      "name": "Section \u2014 Find Moments Submit and Poll",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        352,
        -512
      ],
      "parameters": {
        "color": 6,
        "width": 692,
        "height": 388,
        "content": "## WayinVideo Find Moments Submit and Poll\nSubmits the earnings call URL and financial topics query to the Find Moments API \u2014 returning up to 8 matching moments with titles, descriptions, timestamps, and relevance scores. Waits 90 seconds then polls until SUCCEEDED."
      },
      "typeVersion": 1
    },
    {
      "id": "f282a979-16c5-4837-bb07-ed83760e8dc3",
      "name": "Section \u2014 Status Check and Retry Loop",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1088,
        -704
      ],
      "parameters": {
        "color": 6,
        "width": 308,
        "height": 900,
        "content": "## Find Moments Status Check and Retry Loop\nIF checks for SUCCEEDED status. TRUE proceeds to clip extraction. FALSE waits 30 seconds and polls again. Loop continues until results are ready."
      },
      "typeVersion": 1
    },
    {
      "id": "97662931-2875-4a27-83ee-e67e2190f758",
      "name": "Section \u2014 Clip Extraction and AI Investor Analysis",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1472,
        -640
      ],
      "parameters": {
        "color": 6,
        "width": 468,
        "height": 708,
        "content": "## Clip Extraction and AI Investor Analysis\nSplits clips into one item per moment and passes totalClips for AI context. GPT-4o-mini writes an 8-section investor highlight: topic category, investor summary, key metrics, why it matters, sentiment, reasoning, flags for attention, and pre-formatted Notion page content."
      },
      "typeVersion": 1
    },
    {
      "id": "88e7b820-f15e-47a3-b9b5-4976fa54877e",
      "name": "Section \u2014 Investor Analysis Parse and Notion Page Creation",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        2000,
        -560
      ],
      "parameters": {
        "color": 4,
        "width": 532,
        "height": 500,
        "content": "## Investor Analysis Parse and Notion Page Creation\nRegex extracts all 8 sections. Builds the Notion page title as Company Ticker \u2014 Quarter \u2014 Category \u2014 Highlight N. Creates one Notion page per highlight in the Investor Intelligence database."
      },
      "typeVersion": 1
    },
    {
      "id": "ef3ba07e-7e22-41b8-a273-650ca72c6416",
      "name": "1. Form \u2014 Earnings Call + Details",
      "type": "n8n-nodes-base.formTrigger",
      "position": [
        112,
        -320
      ],
      "parameters": {
        "options": {},
        "formTitle": "Earnings Call Investor Highlight Extractor",
        "formFields": {
          "values": [
            {
              "fieldLabel": "Earnings Call Recording URL",
              "placeholder": "https://zoom.us/rec/xxxxxxx or YouTube/Vimeo link",
              "requiredField": true
            },
            {
              "fieldLabel": "Company Name",
              "placeholder": "e.g. Apple Inc, Tesla, Microsoft",
              "requiredField": true
            },
            {
              "fieldLabel": "Ticker Symbol",
              "placeholder": "e.g. AAPL, TSLA, MSFT",
              "requiredField": true
            },
            {
              "fieldLabel": "Quarter / Period",
              "placeholder": "e.g. Q1 2025, FY2025, H2 2024",
              "requiredField": true
            },
            {
              "fieldLabel": "Call Date",
              "placeholder": "e.g. 2025-04-29",
              "requiredField": true
            },
            {
              "fieldLabel": "Financial Topics to Extract",
              "placeholder": "e.g. revenue growth guidance profit margin / product launch update / risk factors / competitive landscape",
              "requiredField": true
            },
            {
              "fieldLabel": "Your Investment Thesis",
              "placeholder": "e.g. Long-term growth play / Short-term momentum / Risk assessment / Competitive positioning"
            }
          ]
        },
        "formDescription": "Paste your earnings call or investor recording URL. AI will find the most important financial moments and save structured investor highlights to your Notion database."
      },
      "typeVersion": 2.2
    },
    {
      "id": "b37e3f5a-3b1a-4ffb-96de-8b24b61de019",
      "name": "2. WayinVideo \u2014 Submit Find Moments",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        400,
        -320
      ],
      "parameters": {
        "url": "https://wayinvideo-api.wayin.ai/api/v2/clips/find-moments",
        "method": "POST",
        "options": {},
        "jsonBody": "={\n  \"video_url\": \"{{ $json['Earnings Call Recording URL'] }}\",\n  \"query\": \"{{ $json['Financial Topics to Extract'] }}\",\n  \"project_name\": \"{{ $json['Company Name'] }} {{ $json['Ticker Symbol'] }} {{ $json['Quarter / Period'] }}\",\n  \"limit\": 8,\n  \"enable_export\": false,\n  \"target_lang\": \"en\"\n}",
        "sendBody": true,
        "sendHeaders": true,
        "specifyBody": "json",
        "headerParameters": {
          "parameters": [
            {
              "name": "Authorization",
              "value": "Bearer YOUR_TOKEN_HERE"
            },
            {
              "name": "x-wayinvideo-api-version",
              "value": "v2"
            },
            {
              "name": "Content-Type",
              "value": "application/json"
            }
          ]
        }
      },
      "typeVersion": 4.2
    },
    {
      "id": "17894ac4-b5e9-43b3-97b9-8335fc07162a",
      "name": "3. Wait \u2014 90 Seconds",
      "type": "n8n-nodes-base.wait",
      "position": [
        672,
        -320
      ],
      "parameters": {
        "amount": 90
      },
      "typeVersion": 1.1
    },
    {
      "id": "977941b0-dffe-4e88-9ae7-da98fbd1279f",
      "name": "4. WayinVideo \u2014 Get Moments Results",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        912,
        -320
      ],
      "parameters": {
        "url": "=https://wayinvideo-api.wayin.ai/api/v2/clips/find-moments/results/{{ $('2. WayinVideo \u2014 Submit Find Moments').item.json.data.id }}",
        "options": {},
        "sendHeaders": true,
        "headerParameters": {
          "parameters": [
            {
              "name": "Authorization",
              "value": "Bearer YOUR_TOKEN_HERE"
            },
            {
              "name": "x-wayinvideo-api-version",
              "value": "v2"
            },
            {
              "name": "Content-Type",
              "value": "application/json"
            }
          ]
        }
      },
      "typeVersion": 4.2
    },
    {
      "id": "2c3558b0-d1a9-43d4-920a-84ea3c5c09d7",
      "name": "5. IF \u2014 Find Moments Complete?",
      "type": "n8n-nodes-base.if",
      "position": [
        1184,
        -320
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 3,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "loose"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "status-check",
              "operator": {
                "type": "string",
                "operation": "equals"
              },
              "leftValue": "={{ $json.data.status }}",
              "rightValue": "SUCCEEDED"
            }
          ]
        }
      },
      "typeVersion": 2.3
    },
    {
      "id": "e4fd3b72-203a-4ab8-8de8-9c08e5fb9a64",
      "name": "6. Wait \u2014 30 Seconds Retry",
      "type": "n8n-nodes-base.wait",
      "position": [
        1184,
        -112
      ],
      "parameters": {
        "amount": 30
      },
      "typeVersion": 1.1
    },
    {
      "id": "6ff85db5-9471-4f98-8385-3cb1884c4e97",
      "name": "7. Code \u2014 Extract Highlight Clips",
      "type": "n8n-nodes-base.code",
      "position": [
        1504,
        -336
      ],
      "parameters": {
        "jsCode": "// Extract highlight clips from WayinVideo Find Moments\nconst clips = $('4. WayinVideo \u2014 Get Moments Results').item.json.data?.clips || [];\n\nif (clips.length === 0) {\n  throw new Error('No financial moments found in this recording. Try a broader search query or verify the recording URL is accessible.');\n}\n\n// Get form data\nconst companyName = $('1. Form \u2014 Earnings Call + Details').item.json['Company Name'];\nconst tickerSymbol = $('1. Form \u2014 Earnings Call + Details').item.json['Ticker Symbol'];\nconst quarter = $('1. Form \u2014 Earnings Call + Details').item.json['Quarter / Period'];\nconst callDate = $('1. Form \u2014 Earnings Call + Details').item.json['Call Date'];\nconst financialTopics = $('1. Form \u2014 Earnings Call + Details').item.json['Financial Topics to Extract'];\nconst investmentThesis = $('1. Form \u2014 Earnings Call + Details').item.json['Your Investment Thesis'] || 'General analysis';\nconst recordingUrl = $('1. Form \u2014 Earnings Call + Details').item.json['Earnings Call Recording URL'];\n\n// Split into individual items \u2014 one per highlight moment\nreturn clips.map((clip, index) => ({\n  json: {\n    clipIndex: index + 1,\n    totalClips: clips.length,\n    clipTitle: clip.title || `Financial Highlight ${index + 1}`,\n    clipDescription: clip.desc || '',\n    clipScore: clip.score || 0,\n    clipTags: Array.isArray(clip.tags) ? clip.tags.join(', ') : '',\n    beginMs: clip.begin_ms || 0,\n    endMs: clip.end_ms || 0,\n    timestampStart: `${Math.floor((clip.begin_ms || 0) / 60000)}:${String(Math.floor(((clip.begin_ms || 0) % 60000) / 1000)).padStart(2, '0')}`,\n    timestampEnd: `${Math.floor((clip.end_ms || 0) / 60000)}:${String(Math.floor(((clip.end_ms || 0) % 60000) / 1000)).padStart(2, '0')}`,\n    companyName,\n    tickerSymbol,\n    quarter,\n    callDate,\n    financialTopics,\n    investmentThesis,\n    recordingUrl\n  }\n}));"
      },
      "typeVersion": 2
    },
    {
      "id": "74a0feeb-921d-4a5c-8860-0a999987d468",
      "name": "8. AI Agent \u2014 Generate Investor Highlight",
      "type": "@n8n/n8n-nodes-langchain.agent",
      "position": [
        1680,
        -336
      ],
      "parameters": {
        "text": "=You are an expert investment analyst who specializes in analyzing earnings calls and extracting structured investor intelligence.\n\nA video AI tool has identified and extracted a specific financial moment from an earnings call recording. Your job is to analyze this moment and write a structured investor highlight for the Notion database.\n\n---\n\n## EARNINGS CALL CONTEXT\n- Company: {{ $json.companyName }} ({{ $json.tickerSymbol }})\n- Quarter / Period: {{ $json.quarter }}\n- Call Date: {{ $json.callDate }}\n- Topics Being Analyzed: {{ $json.financialTopics }}\n- Investment Thesis Context: {{ $json.investmentThesis }}\n- Highlight {{ $json.clipIndex }} of {{ $json.totalClips }}\n\n## MOMENT FOUND BY WAYINVIDEO\n- Moment Title: {{ $json.clipTitle }}\n- Description: {{ $json.clipDescription }}\n- Timestamp: {{ $json.timestampStart }} \u2014 {{ $json.timestampEnd }}\n- Relevance Score: {{ $json.clipScore }}/100\n- Tags: {{ $json.clipTags }}\n\n---\n\n## YOUR TASK\nAnalyze this financial moment and write a structured investor highlight.\n\n## RULES\n1. Base analysis ONLY on the moment description provided \u2014 no outside knowledge about this company\n2. Be specific and numbers-focused where possible\n3. Sentiment must reflect the tone of what was said\n4. Why It Matters must connect directly to investor decision-making\n5. Keep each section concise \u2014 2-3 sentences maximum\n\n---\n\n## OUTPUT FORMAT\nReturn in this exact structure:\n\nTOPIC_CATEGORY:\n[Choose one: Revenue and Growth / Guidance and Outlook / Profitability and Margins / Product and Innovation / Risk Factors / Competitive Landscape / Management Commentary / Capital Allocation / Other]\n\nINVESTOR_SUMMARY:\n[2-3 sentences summarizing what was said in plain investor-friendly language]\n\nKEY_METRICS_MENTIONED:\n[List any specific numbers, percentages, or figures mentioned \u2014 or 'No specific metrics mentioned']\n\nWHY_IT_MATTERS:\n[2 sentences explaining why this moment is significant for investors]\n\nSENTIMENT:\n[Choose one: Very Bullish / Bullish / Neutral / Bearish / Very Bearish]\n\nSENTIMENT_REASONING:\n[1 sentence explaining why you chose this sentiment]\n\nFLAGS_FOR_ATTENTION:\n[Any red flags, positive surprises, or follow-up questions an analyst should note \u2014 or 'None identified']\n\nNOTION_PAGE_CONTENT:\n[Write the full Notion page content in clean readable format \u2014 include all sections above formatted nicely for readability]",
        "options": {},
        "promptType": "define"
      },
      "typeVersion": 3.1
    },
    {
      "id": "4e4fd765-c326-4784-8ea3-dfbd8d3688b2",
      "name": "9. OpenAI \u2014 GPT-4o-mini Model",
      "type": "@n8n/n8n-nodes-langchain.lmChatOpenAi",
      "position": [
        1680,
        -128
      ],
      "parameters": {
        "model": {
          "__rl": true,
          "mode": "list",
          "value": "gpt-4o-mini"
        },
        "options": {},
        "builtInTools": {}
      },
      "typeVersion": 1.3
    },
    {
      "id": "2a77abc5-c872-4156-80de-93ef4ad8ce29",
      "name": "10. Code \u2014 Parse Investor Analysis",
      "type": "n8n-nodes-base.code",
      "position": [
        2096,
        -336
      ],
      "parameters": {
        "jsCode": "// Parse AI investor analysis output\nconst output = $input.first().json.output || '';\n\n// Extract each section\nconst topicCategoryMatch = output.match(/TOPIC_CATEGORY:\\s*([\\s\\S]*?)(?=\\nINVESTOR_SUMMARY:|$)/);\nconst summaryMatch = output.match(/INVESTOR_SUMMARY:\\s*([\\s\\S]*?)(?=\\nKEY_METRICS_MENTIONED:|$)/);\nconst metricsMatch = output.match(/KEY_METRICS_MENTIONED:\\s*([\\s\\S]*?)(?=\\nWHY_IT_MATTERS:|$)/);\nconst whyMattersMatch = output.match(/WHY_IT_MATTERS:\\s*([\\s\\S]*?)(?=\\nSENTIMENT:|$)/);\nconst sentimentMatch = output.match(/SENTIMENT:\\s*([\\s\\S]*?)(?=\\nSENTIMENT_REASONING:|$)/);\nconst sentimentReasoningMatch = output.match(/SENTIMENT_REASONING:\\s*([\\s\\S]*?)(?=\\nFLAGS_FOR_ATTENTION:|$)/);\nconst flagsMatch = output.match(/FLAGS_FOR_ATTENTION:\\s*([\\s\\S]*?)(?=\\nNOTION_PAGE_CONTENT:|$)/);\nconst notionContentMatch = output.match(/NOTION_PAGE_CONTENT:\\s*([\\s\\S]*)$/);\n\nconst topicCategory = topicCategoryMatch ? topicCategoryMatch[1].trim() : 'Other';\nconst investorSummary = summaryMatch ? summaryMatch[1].trim() : '';\nconst keyMetrics = metricsMatch ? metricsMatch[1].trim() : 'No specific metrics mentioned';\nconst whyItMatters = whyMattersMatch ? whyMattersMatch[1].trim() : '';\nconst sentiment = sentimentMatch ? sentimentMatch[1].trim() : 'Neutral';\nconst sentimentReasoning = sentimentReasoningMatch ? sentimentReasoningMatch[1].trim() : '';\nconst flagsForAttention = flagsMatch ? flagsMatch[1].trim() : 'None identified';\nconst notionContent = notionContentMatch ? notionContentMatch[1].trim() : investorSummary;\n\n// Get clip data from previous step\nconst clipData = $('7. Code \u2014 Extract Highlight Clips').item.json;\n\n// Build Notion page title\nconst pageTitle = `${clipData.companyName} ${clipData.tickerSymbol} \u2014 ${clipData.quarter} \u2014 ${topicCategory} \u2014 Highlight ${clipData.clipIndex}`;\n\nreturn [{\n  json: {\n    pageTitle,\n    topicCategory,\n    investorSummary,\n    keyMetrics,\n    whyItMatters,\n    sentiment,\n    sentimentReasoning,\n    flagsForAttention,\n    notionContent,\n    companyName: clipData.companyName,\n    tickerSymbol: clipData.tickerSymbol,\n    quarter: clipData.quarter,\n    callDate: clipData.callDate,\n    timestamp: `${clipData.timestampStart} \u2014 ${clipData.timestampEnd}`,\n    relevanceScore: clipData.clipScore,\n    clipTitle: clipData.clipTitle,\n    recordingUrl: clipData.recordingUrl,\n    clipIndex: clipData.clipIndex\n  }\n}];"
      },
      "typeVersion": 2
    },
    {
      "id": "a88caf6f-8548-498b-a343-9ee4f9fc5fee",
      "name": "11. Notion \u2014 Create Highlight Page",
      "type": "n8n-nodes-base.notion",
      "position": [
        2336,
        -336
      ],
      "parameters": {
        "title": "={{ $json.pageTitle }}",
        "pageId": {
          "__rl": true,
          "mode": "url",
          "value": ""
        },
        "blockUi": {
          "blockValues": [
            {
              "textContent": "={{ $json.notionContent }}"
            }
          ]
        },
        "options": {}
      },
      "typeVersion": 2.2
    }
  ],
  "connections": {
    "3. Wait \u2014 90 Seconds": {
      "main": [
        [
          {
            "node": "4. WayinVideo \u2014 Get Moments Results",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "6. Wait \u2014 30 Seconds Retry": {
      "main": [
        [
          {
            "node": "4. WayinVideo \u2014 Get Moments Results",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "9. OpenAI \u2014 GPT-4o-mini Model": {
      "ai_languageModel": [
        [
          {
            "node": "8. AI Agent \u2014 Generate Investor Highlight",
            "type": "ai_languageModel",
            "index": 0
          }
        ]
      ]
    },
    "5. IF \u2014 Find Moments Complete?": {
      "main": [
        [
          {
            "node": "7. Code \u2014 Extract Highlight Clips",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "6. Wait \u2014 30 Seconds Retry",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "1. Form \u2014 Earnings Call + Details": {
      "main": [
        [
          {
            "node": "2. WayinVideo \u2014 Submit Find Moments",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "7. Code \u2014 Extract Highlight Clips": {
      "main": [
        [
          {
            "node": "8. AI Agent \u2014 Generate Investor Highlight",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "10. Code \u2014 Parse Investor Analysis": {
      "main": [
        [
          {
            "node": "11. Notion \u2014 Create Highlight Page",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "2. WayinVideo \u2014 Submit Find Moments": {
      "main": [
        [
          {
            "node": "3. Wait \u2014 90 Seconds",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "4. WayinVideo \u2014 Get Moments Results": {
      "main": [
        [
          {
            "node": "5. IF \u2014 Find Moments Complete?",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "8. AI Agent \u2014 Generate Investor Highlight": {
      "main": [
        [
          {
            "node": "10. Code \u2014 Parse Investor Analysis",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  }
}