{
  "meta": {
    "versionId": "1.0.0",
    "createdAt": "2025-09-29T07:07:45.510495",
    "updatedAt": "2025-09-29T07:07:45.510503",
    "owner": "n8n-user",
    "license": "MIT",
    "category": "automation",
    "status": "active",
    "priority": "high",
    "environment": "production"
  },
  "nodes": [
    {
      "id": "b3a0fa7c-eb47-4f51-98d7-ac1a8de7b05d",
      "name": "On new or updated row",
      "type": "n8n-nodes-base.googleSheetsTrigger",
      "position": [
        800,
        380
      ],
      "parameters": {
        "options": {
          "columnsToWatch": [
            "Security Code"
          ]
        },
        "pollTimes": {
          "item": [
            {
              "mode": "everyMinute"
            }
          ]
        },
        "sheetName": {
          "__rl": true,
          "mode": "list",
          "value": "gid=0",
          "cachedResultUrl": "{{ $env.WEBHOOK_URL }}",
          "cachedResultName": "Investments"
        },
        "documentId": {
          "__rl": true,
          "mode": "list",
          "value": "1Np8TQv7kWwwrGiPkWWsmr4WYWAosv1BMBwwCd0f-dis",
          "cachedResultUrl": "{{ $env.WEBHOOK_URL }}",
          "cachedResultName": "Investments"
        }
      },
      "typeVersion": 1,
      "notes": "This googleSheetsTrigger node performs automated tasks as part of the workflow."
    },
    {
      "id": "61b96d9b-801c-43e6-b89a-a55245386e4f",
      "name": "Send message",
      "type": "n8n-nodes-base.discord",
      "position": [
        1200,
        380
      ],
      "parameters": {
        "text": "=```\n{{ $json.ascii_table }}\n```",
        "options": {},
        "webhookUri": "{{ $env.API_BASE_URL }}"
      },
      "typeVersion": 1,
      "notes": "This discord node performs automated tasks as part of the workflow."
    },
    {
      "id": "2dc9ce88-2079-4419-9f48-2281ac25cb36",
      "name": "Convert to ASCII table",
      "type": "n8n-nodes-base.code",
      "position": [
        1000,
        380
      ],
      "parameters": {
        "jsCode": "/* configure columns to be displayed */\nconst columns_to_display = [\n  \"Security Code\",\n  \"Price\",\n  \"Quantity\",\n]\n\n/* End of configuration section (do not edit code below) */\nconst google_sheets_data = $('On new or updated row').all();\n\n/**\n * Takes a list of objects and returns an ascii table with\n * padding and headers.\n */\nfunction ascii_table(data, columns_to_display) {\n  let table = \"\"\n  \n  // Get the headers\n  let headers = []\n  for (let i = 0; i < columns_to_display.length; i++) {\n    headers.push(columns_to_display[i])\n  }\n\n  // Get the longest string in each column\n  let longest_strings = []\n  for (let i = 0; i < headers.length; i++) {\n    let longest_string = headers[i].length\n    for (let j = 0; j < data.length; j++) {\n      let string_length = data[j].json[headers[i]].length\n      if (string_length > longest_string) {\n        longest_string = string_length\n      }\n    }\n    longest_strings.push(longest_string)\n  }\n\n  // Add the headers to the table\n  for (let i = 0; i < headers.length; i++) {\n    table += headers[i].toString().padEnd(longest_strings[i] + 2, \" \")\n  }\n\n  // Add the data to the table\n  for (let i = 0; i < data.length; i++) {\n    table += \"\\n\"\n    for (let j = 0; j < headers.length; j++) {\n      table += data[i].json[headers[j]].toString().padEnd(longest_strings[j] + 2, \" \")\n    }\n  }\n\n  return table\n}\n\noutput = {\n  ascii_table: ascii_table(google_sheets_data, columns_to_display),\n}\n\nconsole.log(output.ascii_table)\n\nreturn output"
      },
      "typeVersion": 1,
      "notes": "This code node performs automated tasks as part of the workflow."
    },
    {
      "id": "2db7b37b-22f9-424d-a889-33f8a0db2b01",
      "name": "Sticky Note",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        340,
        220
      ],
      "parameters": {
        "width": 402,
        "height": 433,
        "content": "## Send Google Sheets data as a message to a Discord channel\nThis workflow sends a message to a Discord channel when a new row is added or a row is updated in a Google Sheet. The message will send all data rows in the Google Sheet.\n\n### How it works\nUsing a code node, we can use the obtained Google Sheet data to create a custom message that will be sent to Discord. The message will be sent to the Discord channel specified in the Discord node.\n\n### Setup\nThis workflow requires that you set up a Discord webhook and have an existing Google Sheet with data. See how to set up a Discord webhook [here]({{ $env.WEBHOOK_URL }}\n"
      },
      "typeVersion": 1,
      "notes": "This stickyNote node performs automated tasks as part of the workflow."
    },
    {
      "id": "error-debcd628",
      "name": "Error Handler",
      "type": "n8n-nodes-base.stopAndError",
      "typeVersion": 1,
      "position": [
        1000,
        400
      ],
      "parameters": {
        "message": "Workflow execution error",
        "options": {}
      }
    }
  ],
  "connections": {
    "b3a0fa7c-eb47-4f51-98d7-ac1a8de7b05d": {
      "main": [
        [
          {
            "node": "error-handler-b3a0fa7c-eb47-4f51-98d7-ac1a8de7b05d-6163743a",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "61b96d9b-801c-43e6-b89a-a55245386e4f": {
      "main": [
        [
          {
            "node": "error-handler-61b96d9b-801c-43e6-b89a-a55245386e4f-05c7a723",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  },
  "name": "Googlesheetstrigger Workflow",
  "settings": {
    "executionOrder": "v1",
    "saveManualExecutions": true,
    "callerPolicy": "workflowsFromSameOwner",
    "errorWorkflow": null,
    "timezone": "UTC",
    "executionTimeout": 3600,
    "maxExecutions": 1000,
    "retryOnFail": true,
    "retryCount": 3,
    "retryDelay": 1000
  },
  "description": "Automated workflow: Googlesheetstrigger Workflow. This workflow integrates 5 different services: stickyNote, code, googleSheetsTrigger, discord, stopAndError. It contains 6 nodes and follows best practices for error handling and security.",
  "tags": [
    "automation",
    "n8n",
    "production-ready",
    "excellent",
    "optimized"
  ],
  "notes": "Excellent quality workflow: Googlesheetstrigger Workflow. This workflow has been optimized for production use with comprehensive error handling, security, and documentation."
}