
Auto-Monitor SEC Filings and Filter by Investment Thesis
SEC Deal Flow Automation
Most VC and PE firms are still monitoring SEC filings manually. An analyst opens EDGAR, filters by form type, scrolls through hundreds of entries, copies names into a spreadsheet, and repeats this every morning.
This automation eliminates that entirely.
Every weekday at 6AM, the pipeline pulls all new S-1 and Form D filings from SEC EDGAR, runs each company through an AI filter trained on your investment thesis, and delivers two clean reports to your inbox, one with companies that match, one with companies that don't. No manual work. No missed filings. No wasted analyst hours.
What gets automated: Daily SEC EDGAR monitoring (S-1, Form D, or any filing type) , AI-powered thesis filtering (sectors, stage, geography, exclusions) , Structured email report with company name, location, form type, and direct SEC link , Separate matched and excluded lists so nothing gets lost
The result: Your team starts every morning with a pre-filtered deal list instead of a raw data dump. Analysts spend their time on first calls and conviction-building, not filing lookups.
Built on n8n, SEC EDGAR's public API, and OpenRouter. No third-party data subscriptions required.

Workflow JSON
{ "nodes": [ { "parameters": { "rule": { "interval": [ { "triggerAtHour": 9 } ] } }, "id": "9c6697c8-77ea-49c1-b148-479fffd7d42d", "name": "Schedule Trigger2", "type": "n8n-nodes-base.scheduleTrigger", "typeVersion": 1.1, "position": [ 1408, 2704 ] }, { "parameters": { "url": "https://efts.sec.gov/LATEST/search-index", "sendQuery": true, "queryParameters": { "parameters": [ { "name": "q", "value": "\" \"" }, { "name": "forms", "value": "S-1" }, { "name": "dateRange", "value": "custom" }, { "name": "startdt", "value": "={{ $now.minus({days:1}).toFormat('yyyy-MM-dd') }}" }, { "name": "enddt", "value": "={{ $now.toFormat('yyyy-MM-dd') }}" } ] }, "sendHeaders": true, "headerParameters": { "parameters": [ { "name": "User-Agent", "value": "NeuroloopLab/1.0 (daksh@neurolooplab.com)" }, { "name": "Accept", "value": "application/json" } ] }, "options": {} }, "id": "18d2528b-ed4a-434e-bc2f-247d6696b497", "name": "SEC EDGAR – S-1 Filings2", "type": "n8n-nodes-base.httpRequest", "typeVersion": 4.2, "position": [ 1616, 2592 ] }, { "parameters": { "url": "https://efts.sec.gov/LATEST/search-index", "sendQuery": true, "queryParameters": { "parameters": [ { "name": "q", "value": "\" \"" }, { "name": "forms", "value": "D" }, { "name": "dateRange", "value": "custom" }, { "name": "startdt", "value": "={{ $now.minus({days:1}).toFormat('yyyy-MM-dd') }}" }, { "name": "enddt", "value": "={{ $now.toFormat('yyyy-MM-dd') }}" } ] }, "sendHeaders": true, "headerParameters": { "parameters": [ { "name": "User-Agent", "value": "NeuroloopLab/1.0 (daksh@neurolooplab.com)" }, { "name": "Accept", "value": "application/json" } ] }, "options": {} }, "id": "e7b964ec-5775-460a-b008-001d3c3e2b11", "name": "SEC EDGAR – Form D (New Raises)2", "type": "n8n-nodes-base.httpRequest", "typeVersion": 4.2, "position": [ 1616, 2800 ] }, { "parameters": {}, "id": "408a9e84-b52c-46cb-b3ed-416822f12d82", "name": "Merge Results2", "type": "n8n-nodes-base.merge", "typeVersion": 3, "position": [ 1840, 2704 ] }, { "parameters": { "jsCode": "const items = $input.all();\n\nlet allFilings = [];\n\nfor (const item of items) {\n const hits = item.json?.hits?.hits || [];\n\n for (const hit of hits) {\n const src = hit._source || {};\n\n // ACTUAL field names from SEC EDGAR response:\n // display_names: ['Company Name (TICKER) (CIK 0001234)']\n // entity_names: ['Company Name'] -- sometimes present\n // ciks: ['0001234567'] -- array of CIK strings\n // form: 'S-1' -- NOT form_type\n // file_date: '2026-03-20'\n // biz_locations: ['Oakland, CA']\n // inc_states: ['WY']\n // adsh: '0001234567-26-000001' -- accession number\n\n // Extract company name\n let companyName = 'Unknown';\n if (Array.isArray(src.display_names) && src.display_names.length > 0) {\n // Format: \"Acme Corp (ACME) (CIK 0001234)\" — strip the parenthetical parts\n companyName = src.display_names[0].replace(/\\s*\\([^)]*\\)\\s*/g, '').trim();\n } else if (Array.isArray(src.entity_names) && src.entity_names.length > 0) {\n companyName = src.entity_names[0];\n } else if (typeof src.entity_name === 'string') {\n companyName = src.entity_name;\n }\n\n // CIK is in ciks[] array, strip leading zeros for URL\n const cikRaw = Array.isArray(src.ciks) ? src.ciks[0] : (src.entity_id || '');\n const cik = cikRaw.replace(/^0+/, '');\n\n // Form type is 'form' not 'form_type'\n const formType = src.form || src.form_type || 'N/A';\n\n const filedDate = src.file_date || 'N/A';\n\n // Location fields\n const location = Array.isArray(src.biz_locations) ? src.biz_locations[0] : '';\n const incState = Array.isArray(src.inc_states) ? src.inc_states[0] : '';\n\n // Accession number for direct filing link\n const adsh = src.adsh || '';\n const filingUrl = adsh\n ? `https://www.sec.gov/Archives/edgar/data/${cik}/${adsh.replace(/-/g, '')}/`\n : (cik\n ? `https://www.sec.gov/cgi-bin/browse-edgar?action=getcompany&CIK=${cik}&type=${formType}&dateb=&owner=include&count=10`\n : 'https://www.sec.gov/cgi-bin/browse-edgar');\n\n if (companyName === 'Unknown' || !companyName) continue;\n\n allFilings.push({\n company_name: companyName,\n form_type: formType,\n filed_date: filedDate,\n cik: cikRaw,\n location,\n inc_state: incState,\n filing_url: filingUrl\n });\n }\n}\n\n// Deduplicate by CIK (more reliable than name), fall back to name\nconst seen = new Set();\nconst unique = allFilings.filter(f => {\n const key = f.cik || f.company_name;\n if (seen.has(key)) return false;\n seen.add(key);\n return true;\n});\n\nif (unique.length === 0) {\n return [{ json: { filings: [], count: 0, empty: true } }];\n}\n\nreturn [{ json: { filings: unique, count: unique.length, empty: false } }];" }, "id": "555a7da9-9e3b-40b0-8871-19e0dfa866a7", "name": "Parse & Deduplicate Filings1", "type": "n8n-nodes-base.code", "typeVersion": 2, "position": [ 2048, 2720 ] }, { "parameters": { "sendTo": "daksh@neurolooplab.com", "subject": "={{ $json.subject }}", "message": "={{ $json.html_body }}", "options": {} }, "id": "62c166ea-3b8a-4902-9ee8-ba77ae99bde5", "name": "Gmail – Send Alert1", "type": "n8n-nodes-base.gmail", "typeVersion": 2.1, "position": [ 3440, 2768 ], "webhookId": "d02d9829-68d2-48b2-9537-f1c6b878e5a0", "credentials": { "gmailOAuth2": { "id": "MbrD9BQtwtesvYq8", "name": "Gmail account" } } }, { "parameters": { "jsonSchemaExample": "[\n {\n \"company_name\": \"exact name as given\",\n \"match\": true,\n \"reason\": \"one sentence\"\n }\n]", "autoFix": true }, "type": "@n8n/n8n-nodes-langchain.outputParserStructured", "typeVersion": 1.3, "position": [ 2400, 2928 ], "id": "cba5db0a-f21a-41e0-ae7c-495b1ecac975", "name": "Structured Output Parser" }, { "parameters": { "model": "anthropic/claude-sonnet-4.6", "options": {} }, "type": "@n8n/n8n-nodes-langchain.lmChatOpenRouter", "typeVersion": 1, "position": [ 2064, 2976 ], "id": "84576a98-8762-4021-9964-2cc3faed2149", "name": "OpenRouter Chat Model", "credentials": { "openRouterApi": { "id": "4yUud29VMMrKxpX0", "name": "Ishmeet" } } }, { "parameters": { "model": "anthropic/claude-sonnet-4.6", "options": {} }, "type": "@n8n/n8n-nodes-langchain.lmChatOpenRouter", "typeVersion": 1, "position": [ 2336, 3088 ], "id": "cddc0197-56ef-4a00-ab2c-db707ecd2d1e", "name": "OpenRouter Chat Model1", "credentials": { "openRouterApi": { "id": "4yUud29VMMrKxpX0", "name": "Ishmeet" } } }, { "parameters": { "promptType": "define", "text": "=You are a VC analyst at an early-stage investment firm.\n\nYou will receive a list of companies that have recently filed with the SEC. Your job is to filter them against our investment thesis and return ONLY a valid JSON array — no markdown, no explanation, no extra text.\n\nINVESTMENT THESIS:\n- Sectors: B2B SaaS, AI/ML, fintech, healthtech, deeptech\n- Stage: Early stage (seed to Series B)\n- Geography: Prefer US-based, open to global\n- Exclude: ETFs, mutual funds, SPACs, real estate, holding companies, shell companies, blank check companies, and any entity that is clearly not an operating startup\n\nINSTRUCTIONS:\n- For each company, decide: does it match the thesis or not?\n- Base your decision on the company name, form type, incorporation state, and location\n- If the name clearly indicates a fund, ETF, trust, or SPAC — mark it false\n- If the name sounds like an operating startup in a relevant sector — mark it true\n- If you are unsure, mark it false and say why in the reason\n\nOUTPUT FORMAT — return ONLY this JSON array, nothing else:\n[\n {\n \"company_name\": \"exact name as given\",\n \"match\": true,\n \"reason\": \"one sentence\"\n }\n]\n\nCOMPANIES TO EVALUATE:\n{{ JSON.stringify($json.filings) }}", "hasOutputParser": true, "options": {} }, "type": "@n8n/n8n-nodes-langchain.agent", "typeVersion": 3.1, "position": [ 2256, 2720 ], "id": "3a54d471-e949-4e89-9f78-74e83a4344d8", "name": "AI Agent" }, { "parameters": { "jsCode": "const input = $input.first().json;\n\n// AI agent output array\nconst aiResults = input.output || [];\n\n// Original filings array from earlier in the workflow\nlet originalFilings = [];\ntry {\n originalFilings = $('Parse & Deduplicate Filings1').first().json.filings || [];\n} catch(e) {}\n\n// Build a lookup map from original filings by company name\nconst filingMap = {};\nfor (const f of originalFilings) {\n filingMap[f.company_name.trim().toLowerCase()] = f;\n}\n\n// Merge ALL companies — no filter — keep match field\nconst merged = aiResults.map(r => {\n const key = (r.company_name || '').trim().toLowerCase();\n const original = filingMap[key] || {};\n return {\n company_name: r.company_name,\n match: r.match === true,\n reason: r.reason || '',\n form_type: original.form_type || 'N/A',\n filed_date: original.filed_date || 'N/A',\n location: original.location || '',\n inc_state: original.inc_state || '',\n cik: original.cik || '',\n filing_url: original.filing_url || 'https://www.sec.gov'\n };\n});\n\nconst matchCount = merged.filter(r => r.match).length;\n\nreturn [{ json: { merged, total: merged.length, match_count: matchCount } }];" }, "id": "ef88ae04-eb22-4fd3-91a2-a85817239ecd", "name": "Merge AI Results With Filing Data", "type": "n8n-nodes-base.code", "typeVersion": 2, "position": [ 2768, 2768 ], "notes": "Joins AI match/reason with original filing metadata (URL, location, CIK etc)" }, { "parameters": { "jsCode": "const { merged, match_count } = $input.first().json;\nconst matched = merged.filter(r => r.match === true);\nconst count = match_count;\n\nconst today = new Date().toLocaleDateString('en-US', {\n weekday: 'long', year: 'numeric', month: 'long', day: 'numeric'\n});\n\nlet rows = '';\nfor (const f of matched) {\n const location = [f.location, f.inc_state].filter(Boolean).join(' · ');\n rows += `\n <tr>\n <td style=\"padding:12px 16px;border-bottom:1px solid #eee\">\n <div style=\"font-weight:600;color:#0d1f3c;font-size:14px\">${f.company_name}</div>\n <div style=\"color:#888;font-size:12px;margin-top:2px\">${location}</div>\n </td>\n <td style=\"padding:12px 16px;border-bottom:1px solid #eee;color:#555;font-size:13px\">${f.form_type}</td>\n <td style=\"padding:12px 16px;border-bottom:1px solid #eee;color:#555;font-size:13px\">${f.filed_date}</td>\n <td style=\"padding:12px 16px;border-bottom:1px solid #eee;font-size:13px;color:#666;font-style:italic\">${f.reason}</td>\n <td style=\"padding:12px 16px;border-bottom:1px solid #eee;text-align:center\">\n <a href=\"${f.filing_url}\" style=\"display:inline-block;padding:5px 12px;background:#0d1f3c;color:#fff;text-decoration:none;border-radius:4px;font-size:12px\">View →</a>\n </td>\n </tr>`;\n}\n\nconst html = `<!DOCTYPE html>\n<html>\n<body style=\"margin:0;padding:0;background:#f4f5f7;font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Arial,sans-serif\">\n <div style=\"max-width:780px;margin:32px auto;background:#fff;border-radius:10px;overflow:hidden;box-shadow:0 2px 8px rgba(0,0,0,0.08)\">\n\n <div style=\"background:#0d1f3c;padding:28px 32px\">\n <p style=\"margin:0;color:#7b9ac4;font-size:11px;text-transform:uppercase;letter-spacing:1.5px\">Daily Deal Flow · SEC EDGAR</p>\n <h1 style=\"margin:8px 0 4px;color:#ffffff;font-size:24px;font-weight:600\">${count} thesis match${count !== 1 ? 'es' : ''} today</h1>\n <p style=\"margin:0;color:#a0b4cc;font-size:13px\">${today}</p>\n </div>\n\n <div style=\"padding:0\">\n <table style=\"width:100%;border-collapse:collapse;font-size:14px\">\n <thead>\n <tr style=\"background:#f8f9fb\">\n <th style=\"padding:10px 16px;text-align:left;color:#444;font-size:12px;font-weight:600;text-transform:uppercase;letter-spacing:0.5px;border-bottom:2px solid #e8eaed\">Company</th>\n <th style=\"padding:10px 16px;text-align:left;color:#444;font-size:12px;font-weight:600;text-transform:uppercase;letter-spacing:0.5px;border-bottom:2px solid #e8eaed\">Form</th>\n <th style=\"padding:10px 16px;text-align:left;color:#444;font-size:12px;font-weight:600;text-transform:uppercase;letter-spacing:0.5px;border-bottom:2px solid #e8eaed\">Filed</th>\n <th style=\"padding:10px 16px;text-align:left;color:#444;font-size:12px;font-weight:600;text-transform:uppercase;letter-spacing:0.5px;border-bottom:2px solid #e8eaed\">Why it matched</th>\n <th style=\"padding:10px 16px;text-align:left;color:#444;font-size:12px;font-weight:600;text-transform:uppercase;letter-spacing:0.5px;border-bottom:2px solid #e8eaed\"></th>\n </tr>\n </thead>\n <tbody>${rows}</tbody>\n </table>\n </div>\n\n <div style=\"padding:20px 32px;background:#f8f9fb;border-top:1px solid #eee;display:flex;justify-content:space-between;align-items:center\">\n <p style=\"margin:0;color:#aaa;font-size:12px\">Automated by n8n · Source: SEC EDGAR</p>\n <a href=\"https://efts.sec.gov/LATEST/search-index\" style=\"color:#0066cc;font-size:12px;text-decoration:none\">View all filings →</a>\n </div>\n\n </div>\n</body>\n</html>`;\n\nreturn [{\n json: {\n html_body: html,\n subject: `[SEC Monitor] ${count} thesis match${count !== 1 ? 'es' : ''} – ${today}`,\n count\n }\n}];" }, "id": "3352f651-d9bc-4451-8a29-8a45bc0a4f41", "name": "Format Email HTML2", "type": "n8n-nodes-base.code", "typeVersion": 2, "position": [ 3072, 2768 ] }, { "parameters": { "jsCode": "const { merged } = $input.first().json;\n\nconst notMatched = merged.filter(r => r.match === false);\nconst count = notMatched.length;\n\nconst today = new Date().toLocaleDateString('en-US', {\n weekday: 'long', year: 'numeric', month: 'long', day: 'numeric'\n});\n\nlet rows = '';\nfor (const f of notMatched) {\n const location = [f.location, f.inc_state].filter(Boolean).join(' · ');\n rows += `\n <tr>\n <td style=\"padding:12px 16px;border-bottom:1px solid #eee\">\n <div style=\"font-weight:600;color:#0d1f3c;font-size:14px\">${f.company_name}</div>\n <div style=\"color:#888;font-size:12px;margin-top:2px\">${location}</div>\n </td>\n <td style=\"padding:12px 16px;border-bottom:1px solid #eee;color:#555;font-size:13px\">${f.form_type}</td>\n <td style=\"padding:12px 16px;border-bottom:1px solid #eee;color:#555;font-size:13px\">${f.filed_date}</td>\n <td style=\"padding:12px 16px;border-bottom:1px solid #eee;font-size:13px;color:#999;font-style:italic\">${f.reason}</td>\n <td style=\"padding:12px 16px;border-bottom:1px solid #eee;text-align:center\">\n <a href=\"${f.filing_url}\" style=\"display:inline-block;padding:5px 12px;background:#888;color:#fff;text-decoration:none;border-radius:4px;font-size:12px\">View →</a>\n </td>\n </tr>`;\n}\n\nconst html = `<!DOCTYPE html>\n<html>\n<body style=\"margin:0;padding:0;background:#f4f5f7;font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Arial,sans-serif\">\n <div style=\"max-width:780px;margin:32px auto;background:#fff;border-radius:10px;overflow:hidden;box-shadow:0 2px 8px rgba(0,0,0,0.08)\">\n\n <div style=\"background:#4a4a4a;padding:28px 32px\">\n <p style=\"margin:0;color:#bbb;font-size:11px;text-transform:uppercase;letter-spacing:1.5px\">Daily Deal Flow · SEC EDGAR · Excluded</p>\n <h1 style=\"margin:8px 0 4px;color:#ffffff;font-size:24px;font-weight:600\">${count} compan${count !== 1 ? 'ies' : 'y'} filtered out</h1>\n <p style=\"margin:0;color:#ccc;font-size:13px\">${today}</p>\n </div>\n\n <div style=\"padding:0\">\n <table style=\"width:100%;border-collapse:collapse;font-size:14px\">\n <thead>\n <tr style=\"background:#f8f9fb\">\n <th style=\"padding:10px 16px;text-align:left;color:#444;font-size:12px;font-weight:600;text-transform:uppercase;letter-spacing:0.5px;border-bottom:2px solid #e8eaed\">Company</th>\n <th style=\"padding:10px 16px;text-align:left;color:#444;font-size:12px;font-weight:600;text-transform:uppercase;letter-spacing:0.5px;border-bottom:2px solid #e8eaed\">Form</th>\n <th style=\"padding:10px 16px;text-align:left;color:#444;font-size:12px;font-weight:600;text-transform:uppercase;letter-spacing:0.5px;border-bottom:2px solid #e8eaed\">Filed</th>\n <th style=\"padding:10px 16px;text-align:left;color:#444;font-size:12px;font-weight:600;text-transform:uppercase;letter-spacing:0.5px;border-bottom:2px solid #e8eaed\">Why excluded</th>\n <th style=\"padding:10px 16px;border-bottom:2px solid #e8eaed\"></th>\n </tr>\n </thead>\n <tbody>${rows}</tbody>\n </table>\n </div>\n\n <div style=\"padding:20px 32px;background:#f8f9fb;border-top:1px solid #eee\">\n <p style=\"margin:0;color:#aaa;font-size:12px\">Automated by n8n · Source: SEC EDGAR</p>\n </div>\n\n </div>\n</body>\n</html>`;\n\nreturn [{\n json: {\n html_body: html,\n subject: `[SEC Monitor] ${count} excluded compan${count !== 1 ? 'ies' : 'y'} – ${today}`,\n count\n }\n}];\n" }, "id": "94efe50c-de4c-49c1-bc85-958066ec6129", "name": "Format Email HTML3", "type": "n8n-nodes-base.code", "typeVersion": 2, "position": [ 3104, 2944 ] }, { "parameters": { "sendTo": "daksh@neurolooplab.com", "subject": "={{ $json.subject }}", "message": "={{ $json.html_body }}", "options": {} }, "id": "3083240e-ae3a-41a1-9319-8d989610c74e", "name": "Gmail – Send Alert2", "type": "n8n-nodes-base.gmail", "typeVersion": 2.1, "position": [ 3392, 2992 ], "webhookId": "d02d9829-68d2-48b2-9537-f1c6b878e5a0", "credentials": { "gmailOAuth2": { "id": "MbrD9BQtwtesvYq8", "name": "Gmail account" } } } ], "connections": { "Schedule Trigger2": { "main": [ [ { "node": "SEC EDGAR – S-1 Filings2", "type": "main", "index": 0 }, { "node": "SEC EDGAR – Form D (New Raises)2", "type": "main", "index": 0 } ] ] }, "SEC EDGAR – S-1 Filings2": { "main": [ [ { "node": "Merge Results2", "type": "main", "index": 0 } ] ] }, "SEC EDGAR – Form D (New Raises)2": { "main": [ [ { "node": "Merge Results2", "type": "main", "index": 1 } ] ] }, "Merge Results2": { "main": [ [ { "node": "Parse & Deduplicate Filings1", "type": "main", "index": 0 } ] ] }, "Parse & Deduplicate Filings1": { "main": [ [ { "node": "AI Agent", "type": "main", "index": 0 } ] ] }, "Structured Output Parser": { "ai_outputParser": [ [ { "node": "AI Agent", "type": "ai_outputParser", "index": 0 } ] ] }, "OpenRouter Chat Model": { "ai_languageModel": [ [ { "node": "AI Agent", "type": "ai_languageModel", "index": 0 } ] ] }, "OpenRouter Chat Model1": { "ai_languageModel": [ [ { "node": "Structured Output Parser", "type": "ai_languageModel", "index": 0 } ] ] }, "AI Agent": { "main": [ [ { "node": "Merge AI Results With Filing Data", "type": "main", "index": 0 } ] ] }, "Merge AI Results With Filing Data": { "main": [ [ { "node": "Format Email HTML2", "type": "main", "index": 0 }, { "node": "Format Email HTML3", "type": "main", "index": 0 } ] ] }, "Format Email HTML2": { "main": [ [ { "node": "Gmail – Send Alert1", "type": "main", "index": 0 } ] ] }, "Format Email HTML3": { "main": [ [ { "node": "Gmail – Send Alert2", "type": "main", "index": 0 } ] ] } }, "pinData": {}, "meta": { "templateCredsSetupCompleted": true, "instanceId": "68e38a4d16f6bb0fc4dc0d12c182b0537e5cd43d16c8c06d03fb68dbc38c8ff4" } }