{
  "name": "AlphaAI: insider (SEC Form 4) alerts -> Discord",
  "nodes": [
    {
      "parameters": {
        "content": "## AlphaAI \u2192 Discord: insider (SEC Form 4) alerts\n\n**What it does:** every 30 min it pulls AlphaAI's insider feed \u2014 SEC EDGAR Form 4 insider trades plus institutional-stake stories \u2014 and posts material ones (score \u2265 6) to Discord as rich cards: detected Buy/Sell (colour-coded), direct/indirect holding, ticker, and a link to the filing on alphai.io. One message per run, de-duped across runs.\n\n### Setup (2 steps)\n1. **AlphaAI key** \u2014 on *Get insider news*: Authentication = *Generic Credential Type \u2192 Bearer Auth*, paste just your key `ak_live_\u2026` (no `Bearer ` prefix). Free key at alphai.io/account/api-keys.\n2. **Discord** \u2014 *Channel \u2192 Edit \u2192 Integrations \u2192 Webhooks \u2192 New Webhook \u2192 Copy URL*, then paste into the *Post to Discord* node's URL field.\n\nTune the score threshold in the *Build Discord cards* node (`MIN_SCORE`). Activate the workflow.",
        "height": 660,
        "width": 480
      },
      "id": "a0000000-0000-4000-8000-0000000000a3",
      "name": "README",
      "type": "n8n-nodes-base.stickyNote",
      "typeVersion": 1,
      "position": [
        -360,
        -40
      ]
    },
    {
      "parameters": {
        "rule": {
          "interval": [
            {
              "field": "minutes",
              "minutesInterval": 30
            }
          ]
        }
      },
      "id": "b0000000-0000-4000-8000-0000000000b3",
      "name": "Every 30 min",
      "type": "n8n-nodes-base.scheduleTrigger",
      "typeVersion": 1.2,
      "position": [
        160,
        0
      ]
    },
    {
      "parameters": {
        "url": "https://api.alphai.io/api/news/insider/",
        "authentication": "genericCredentialType",
        "genericAuthType": "httpBearerAuth",
        "options": {}
      },
      "id": "c0000000-0000-4000-8000-0000000000c3",
      "name": "Get insider news",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [
        380,
        0
      ]
    },
    {
      "parameters": {
        "mode": "runOnceForAllItems",
        "jsCode": "// AlphaAI insider (SEC Form 4) -> Discord rich embeds.\n// One message per run: header + up to 10 cards, each linking to the filing's\n// page on alphai.io. Colours by detected Buy/Sell, shows direct/indirect holding\n// form. Dedupes by uid across runs; overflow posts next run. One POST per run.\n\n// \u25bc tune this: minimum relevance score to alert on (endpoint already floors at 4).\n// The insider score scales with transaction value \u2014 6 skips the tiny trades.\nconst MIN_SCORE = 6;\n\nfunction slugify(text) {\n  return (text || '').toLowerCase()\n    .replace(/[^\\w\\s-]/g, '').replace(/\\s+/g, '-').replace(/-+/g, '-').trim();\n}\nfunction dateForUrl(iso) {\n  const d = new Date(iso);\n  if (isNaN(d.getTime())) { return ''; }\n  return String(d.getUTCMonth() + 1).padStart(2, '0') + '-' + String(d.getUTCDate()).padStart(2, '0');\n}\nfunction trunc(s, n) { s = (s == null ? '' : String(s)); return s.length > n ? s.slice(0, n - 1) + '\u2026' : s; }\n\nconst SITE = 'https://alphai.io';\nconst GREEN = 3066993, RED = 15158332, GREY = 9807270;\n\nconst incoming = $input.all();\nlet articles = [];\nfor (const it of incoming) {\n  const j = it.json;\n  if (Array.isArray(j)) { articles = articles.concat(j); }\n  else if (j && Array.isArray(j.results)) { articles = articles.concat(j.results); }\n  else if (j) { articles.push(j); }\n}\n\nconst store = $getWorkflowStaticData('global');\nstore.postedUids = store.postedUids || [];\nconst seen = new Set(store.postedUids);\n\nconst embeds = [];\nconst postedUids = [];\nlet budget = 0;\n\nfor (const a of articles) {\n  if (embeds.length >= 10) { break; }\n  const enr = (a && a.enrichment) || {};\n  const org = (a && a.original) || {};\n  const uid = org.uid;\n  const score = enr.relevance_score || 0;\n  const tickers = enr.tickers || [];\n  if (!uid || seen.has(uid)) { continue; }\n  if (score < MIN_SCORE || tickers.length === 0) { continue; }\n\n  // Detect Buy/Sell from the filing's templated text (best-effort).\n  const hay = ((org.title || '') + ' ' + (org.summary || '')).toLowerCase();\n  let direction = '\u2014', color = GREY;\n  if (/\\b(bought|buy|purchas|acqui)/.test(hay)) { direction = 'Buy'; color = GREEN; }\n  else if (/\\b(sold|sell|sale|dispos)/.test(hay)) { direction = 'Sell'; color = RED; }\n\n  const url = `${SITE}/news/article/${dateForUrl(org.time_published)}/${uid}/${slugify(org.title)}`;\n\n  const fields = [];\n  fields.push({ name: 'Direction', value: direction, inline: true });\n  if (org.ownership_form) { fields.push({ name: 'Holding', value: trunc(org.ownership_form, 40), inline: true }); }\n  fields.push({ name: 'Score', value: String(score) + '/10', inline: true });\n\n  const embed = {\n    title: trunc(`${tickers.join(', ')} \u2014 ${org.title || 'Insider filing'}`, 250),\n    url,\n    description: trunc(org.summary || '', 320),\n    color,\n    fields,\n    footer: { text: trunc(`insider \u00b7 ${org.source || org.source_domain || 'SEC EDGAR'} \u00b7 via AlphaAI`, 120) },\n  };\n  if (org.time_published) { embed.timestamp = org.time_published; }\n\n  const size = JSON.stringify(embed).length;\n  if (budget + size > 5200 && embeds.length > 0) { break; }\n  budget += size;\n\n  embeds.push(embed);\n  postedUids.push(uid);\n  seen.add(uid);\n}\n\nif (embeds.length === 0) { return []; }\n\nfor (const uid of postedUids) { store.postedUids.push(uid); }\nif (store.postedUids.length > 500) { store.postedUids = store.postedUids.slice(-500); }\n\nconst n = embeds.length;\nconst content = `\ud83d\udd75\ufe0f **AlphaAI \u2014 ${n} new insider ${n === 1 ? 'filing' : 'filings'}**`;\n\nreturn [{ json: { payload: { content, embeds } } }];\n"
      },
      "id": "d0000000-0000-4000-8000-0000000000d3",
      "name": "Build Discord cards",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        600,
        0
      ]
    },
    {
      "parameters": {
        "method": "POST",
        "url": "https://discord.com/api/webhooks/REPLACE_WITH_YOUR_WEBHOOK_URL",
        "sendBody": true,
        "contentType": "json",
        "specifyBody": "json",
        "jsonBody": "={{ $json.payload }}",
        "options": {}
      },
      "id": "e0000000-0000-4000-8000-0000000000e3",
      "name": "Post to Discord",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [
        820,
        0
      ],
      "retryOnFail": true,
      "maxTries": 3,
      "waitBetweenTries": 3000
    }
  ],
  "connections": {
    "Every 30 min": {
      "main": [
        [
          {
            "node": "Get insider news",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Get insider news": {
      "main": [
        [
          {
            "node": "Build Discord cards",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Build Discord cards": {
      "main": [
        [
          {
            "node": "Post to Discord",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  },
  "active": false,
  "settings": {
    "executionOrder": "v1"
  },
  "meta": {
    "templateCredsSetupCompleted": false
  }
}