{
  "name": "Solana Mint/Program Monitor — new transactions on a mint or program",
  "nodes": [
    {
      "parameters": {
        "rule": { "interval": [{ "field": "minutes", "minutesInterval": 10 }] }
      },
      "id": "trigger-10m",
      "name": "Every 10 minutes",
      "type": "n8n-nodes-base.scheduleTrigger",
      "typeVersion": 1.2,
      "position": [0, 0]
    },
    {
      "parameters": {
        "method": "POST",
        "url": "https://api.mainnet-beta.solana.com",
        "sendBody": true,
        "specifyBody": "json",
        "jsonBody": "={{ JSON.stringify({ jsonrpc: \"2.0\", id: 1, method: \"getSignaturesForAddress\", params: [ $env.MINT_OR_PROGRAM || \"INSERT_MINT_OR_PROGRAM_ID\", { limit: 20 } ] }) }}",
        "options": { "timeout": 15000 }
      },
      "id": "fetch-sigs",
      "name": "Latest signatures for mint/program",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [220, 0]
    },
    {
      "parameters": {
        "jsCode": "// Isolate signatures never seen before (state persisted in the workflow) vs the last run.\nconst result = $input.first().json.result || [];\nconst state = $getWorkflowStaticData('global');\nconst seen = new Set(state.seen || []);\nconst fresh = result.filter(r => !seen.has(r.signature) && !r.err);\nfor (const r of result) seen.add(r.signature);\nstate.seen = [...seen].slice(-500);\nconst firstRun = !state.started;\nstate.started = true;\n// on the first run just save the baseline, don't alert (otherwise it would spam the whole history)\nreturn firstRun ? [] : fresh.map(r => ({ json: { signature: r.signature, slot: r.slot } }));"
      },
      "id": "trova-nuove",
      "name": "Find new signatures",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [440, 0]
    },
    {
      "parameters": {
        "conditions": {
          "options": { "caseSensitive": true, "leftValue": "", "typeValidation": "strict" },
          "conditions": [
            { "leftValue": "={{ $json.signature }}", "rightValue": "", "operator": { "type": "string", "operation": "notEmpty" } }
          ],
          "combinator": "and"
        }
      },
      "id": "if-nuova",
      "name": "Is there a new signature?",
      "type": "n8n-nodes-base.if",
      "typeVersion": 2.2,
      "position": [660, 0]
    },
    {
      "parameters": {
        "chatId": "={{ $env.TELEGRAM_CHAT_ID || 'INSERT_CHAT_ID' }}",
        "text": "=🆕 New transaction on the watched mint/program (slot {{ $json.slot }}).\n\nhttps://solscan.io/tx/{{ $json.signature }}",
        "additionalFields": {}
      },
      "id": "notify-telegram",
      "name": "Notify on Telegram",
      "type": "n8n-nodes-base.telegram",
      "typeVersion": 1.2,
      "position": [880, 0],
      "credentials": {
        "telegramApi": { "id": "CONFIGURA_IN_N8N", "name": "Telegram Bot (create the credential in n8n)" }
      }
    }
  ],
  "connections": {
    "Every 10 minutes": { "main": [[{ "node": "Latest signatures for mint/program", "type": "main", "index": 0 }]] },
    "Latest signatures for mint/program": { "main": [[{ "node": "Find new signatures", "type": "main", "index": 0 }]] },
    "Find new signatures": { "main": [[{ "node": "Is there a new signature?", "type": "main", "index": 0 }]] },
    "Is there a new signature?": { "main": [[{ "node": "Notify on Telegram", "type": "main", "index": 0 }]] }
  },
  "settings": { "executionOrder": "v1" },
  "meta": {
    "note": "Setup (5 minutes): 1) MINT_OR_PROGRAM = the SPL mint address or Solana program ID to watch; 2) create a Telegram bot with @BotFather and attach the credential to the 'Notify on Telegram' node (for Discord: replace the node with an HTTP Request POST to a Discord webhook); 3) TELEGRAM_CHAT_ID = your chat_id; 4) activate the workflow. The first run only saves the baseline (no spam of the whole history), from the second run on it alerts on genuinely new transactions. Uses the public Solana RPC, no API key required."
  }
}
