{
  "name": "FilingPulse — insider trade alerts (polling, no public URL needed)",
  "nodes": [
    {
      "parameters": {
        "content": "## FilingPulse → Slack/Discord (polling)\n\nChecks FilingPulse every 10 minutes for new Form 4 insider filings and posts one line per new filing. No public webhook URL required — works on any n8n, including local instances behind NAT.\n\n**Setup (2 minutes):**\n1. Get a free API key at https://filingpulse.io/signup.html\n2. Paste it into the **Fetch latest filings** node (X-API-Key header).\n3. Paste your Slack incoming-webhook URL into the **Send alert** node. For Discord, change the body to `{\"content\": ...}`.\n4. Activate the workflow.\n\nTo watch specific tickers, add a `ticker` query parameter to the fetch node (one workflow per ticker), or switch to the real-time webhook template — server-side ticker filters, no polling: https://filingpulse.io/n8n.html\n\n*Notes: the first run only seeds the memory (no alert flood of old filings). The seen-filings memory uses workflow static data, which persists only while the workflow is **active** — manual test runs alert on everything every time.*",
        "height": 560,
        "width": 460
      },
      "id": "sticky-setup-poll",
      "name": "Setup",
      "type": "n8n-nodes-base.stickyNote",
      "typeVersion": 1,
      "position": [-260, 120]
    },
    {
      "parameters": {
        "rule": {
          "interval": [
            {
              "field": "minutes",
              "minutesInterval": 10
            }
          ]
        }
      },
      "id": "schedule-10m",
      "name": "Every 10 minutes",
      "type": "n8n-nodes-base.scheduleTrigger",
      "typeVersion": 1.2,
      "position": [260, 300]
    },
    {
      "parameters": {
        "url": "https://api.filingpulse.io/v1/insider-trades",
        "sendQuery": true,
        "queryParameters": {
          "parameters": [
            {
              "name": "limit",
              "value": "50"
            }
          ]
        },
        "sendHeaders": true,
        "headerParameters": {
          "parameters": [
            {
              "name": "X-API-Key",
              "value": "PASTE_YOUR_FREE_KEY"
            }
          ]
        },
        "options": {}
      },
      "id": "fetch-latest",
      "name": "Fetch latest filings",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [480, 300]
    },
    {
      "parameters": {
        "jsCode": "// Keep only filings not seen on a previous run, then format one factual line each.\nconst staticData = $getWorkflowStaticData('global');\nconst firstRun = !Array.isArray(staticData.seenAccessions);\nconst seen = new Set(staticData.seenAccessions || []);\nconst rows = $json.data || [];\nconst fresh = rows.filter(r => r.accession && !seen.has(r.accession));\nstaticData.seenAccessions = [...new Set([...rows.map(r => r.accession), ...seen])].slice(0, 1000);\nif (firstRun) {\n  // Seed the memory without alerting on filings that predate the workflow.\n  return [];\n}\nreturn fresh.map(f => {\n  const issuer = (f.issuer && f.issuer.name) || '?';\n  const ticker = f.issuer && f.issuer.ticker ? ' (' + f.issuer.ticker + ')' : '';\n  const owners = (f.reporting_owners || []).map(o => o.name).join(', ');\n  const codes = [...new Set((f.transactions || []).map(t => t.transaction_code).filter(Boolean))].join(',');\n  const text = 'Form ' + (f.form_type || '4') + ': ' + owners + ' @ ' + issuer + ticker +\n               ' — codes: ' + (codes || 'holdings only') +\n               '\\nfiled ' + (f.filed_date || '?') + ' — accession ' + f.accession;\n  return { json: { text } };\n});"
      },
      "id": "dedupe-format",
      "name": "New filings only + format",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [700, 300]
    },
    {
      "parameters": {
        "method": "POST",
        "url": "https://hooks.slack.com/services/REPLACE/WITH/YOURS",
        "sendBody": true,
        "specifyBody": "json",
        "jsonBody": "={{ JSON.stringify({ text: $json.text }) }}",
        "options": {}
      },
      "id": "send-alert",
      "name": "Send alert",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [920, 300]
    }
  ],
  "connections": {
    "Every 10 minutes": {
      "main": [[{ "node": "Fetch latest filings", "type": "main", "index": 0 }]]
    },
    "Fetch latest filings": {
      "main": [[{ "node": "New filings only + format", "type": "main", "index": 0 }]]
    },
    "New filings only + format": {
      "main": [[{ "node": "Send alert", "type": "main", "index": 0 }]]
    }
  },
  "settings": {
    "executionOrder": "v1"
  },
  "pinData": {}
}
