{
  "id": "mUEXvxg3mTX2d52n",
  "meta": {
    "templateCredsSetupCompleted": true
  },
  "name": "Figma fire event - ping Slack",
  "tags": [],
  "nodes": [
    {
      "id": "5f8f5bff-1a84-4d4f-be51-db6961d26d5f",
      "name": "Sticky Note",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        368,
        -160
      ],
      "parameters": {
        "width": 480,
        "height": 896,
        "content": "Figma fire event - ping slack\n\n### How it works\n\nThis workflow monitors three Figma event types: library published, file comment, and file deleted. Each trigger runs through its own formatting code node to create an appropriate Slack message, then all formatted messages converge into a single Slack posting node. It provides an internal event log in Slack for key Figma activity.\n\n### Setup steps\n\n- Configure the Figma trigger credentials and webhook/event subscriptions for library publish, file comment, and file delete events.\n- Configure the Slack credentials on the Post to Slack node and select the target workspace and channel.\n- Review each formatting code node to confirm it matches the actual Figma payload fields and produces the Slack message format expected by the Slack node.\n- Activate the workflow and test each Figma event type to verify the notification reaches Slack.\n\n### Customization\n\nAdjust the three formatting code nodes to change message text, include links or metadata, mention users, or add routing logic. The Slack node can be pointed to a different channel for staging, production, or event-specific logging."
      },
      "typeVersion": 1
    },
    {
      "id": "b7dce9c0-d5d8-4ea0-9d90-317b3de7ab61",
      "name": "Sticky Note1",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        928,
        -160
      ],
      "parameters": {
        "color": 7,
        "width": 512,
        "height": 304,
        "content": "## Library publish event\n\nTop lane that listens for Figma library publish events and formats the event details into a Slack-ready message."
      },
      "typeVersion": 1
    },
    {
      "id": "d641dddf-8946-46ee-a761-6aa429a75f7f",
      "name": "Sticky Note2",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        928,
        176
      ],
      "parameters": {
        "color": 7,
        "width": 512,
        "height": 320,
        "content": "## File comment event\n\nMiddle lane that listens for new Figma file comments and converts the comment payload into the standard Slack message structure."
      },
      "typeVersion": 1
    },
    {
      "id": "4704aba6-52c3-4f14-a3b7-bc44da67a988",
      "name": "Sticky Note3",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        928,
        528
      ],
      "parameters": {
        "color": 7,
        "width": 512,
        "height": 304,
        "content": "## File deletion event\n\nBottom lane that listens for Figma file deletion events and formats the deletion details for Slack notification."
      },
      "typeVersion": 1
    },
    {
      "id": "42cb07d9-5952-4024-950f-ff45fcb4de21",
      "name": "Sticky Note4",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1584,
        -16
      ],
      "parameters": {
        "color": 7,
        "height": 400,
        "content": "## Shared Slack notification\n\nShared output node on the right that receives formatted messages from all three Figma event lanes and posts them to Slack."
      },
      "typeVersion": 1
    },
    {
      "id": "467999f0-d517-47a6-b85d-c59e0fe7a6c7",
      "name": "When Library Published",
      "type": "n8n-nodes-base.figmaTrigger",
      "position": [
        976,
        -32
      ],
      "parameters": {
        "triggerOn": "libraryPublish"
      },
      "typeVersion": 1
    },
    {
      "id": "46e8a9cd-35be-4d84-b76d-92236b1c4592",
      "name": "When File Commented",
      "type": "n8n-nodes-base.figmaTrigger",
      "position": [
        976,
        336
      ],
      "parameters": {
        "triggerOn": "fileComment"
      },
      "typeVersion": 1
    },
    {
      "id": "4f6ba317-da21-4496-a26d-4946b9d42140",
      "name": "When File Deleted",
      "type": "n8n-nodes-base.figmaTrigger",
      "position": [
        976,
        656
      ],
      "parameters": {
        "triggerOn": "fileDelete"
      },
      "typeVersion": 1
    },
    {
      "id": "1ce9f3f1-ac52-40ba-9c46-d65531aae29b",
      "name": "Send Message to Slack",
      "type": "n8n-nodes-base.slack",
      "position": [
        1632,
        224
      ],
      "parameters": {
        "text": "={{ $json.slackText }}",
        "select": "channel",
        "channelId": {
          "__rl": true,
          "mode": "id",
          "value": "C0BD9B326S3"
        },
        "otherOptions": {
          "mrkdwn": true,
          "includeLinkToWorkflow": false
        }
      },
      "typeVersion": 2.5
    },
    {
      "id": "dd62da13-4b3b-489c-a4a7-e434baf1cc5a",
      "name": "Build Library Event Message",
      "type": "n8n-nodes-base.code",
      "position": [
        1296,
        -32
      ],
      "parameters": {
        "mode": "runOnceForEachItem",
        "jsCode": "// LIBRARY_PUBLISH \u2192 Slack message\n// Payload has created/modified/deleted arrays for components, styles and\n// variables. Each array item looks like { name, key }.\nconst j = $json;\n\nconst count = (arr) => (arr || []).length;\nconst names = (arr) => (arr || []).map((x) => x.name).filter(Boolean);\n\n// Summarise only the categories that actually changed,\n// e.g. \"4 components, 1 style, 2 variables updated\".\nconst group = (label, created, modified, deleted) => {\n  const total = count(created) + count(modified) + count(deleted);\n  if (!total) return null;\n  return total + ' ' + label + (total !== 1 ? 's' : '');\n};\nconst summary = [\n  group('component', j.created_components, j.modified_components, j.deleted_components),\n  group('style', j.created_styles, j.modified_styles, j.deleted_styles),\n  group('variable', j.created_variables, j.modified_variables, j.deleted_variables),\n].filter(Boolean).join(', ');\n\n// Preview the first few changed item names: \"Button, Card (+4 more)\".\nconst changedNames = [].concat(\n  names(j.created_components), names(j.modified_components), names(j.deleted_components),\n  names(j.created_styles), names(j.modified_styles), names(j.deleted_styles),\n  names(j.created_variables), names(j.modified_variables), names(j.deleted_variables),\n);\nconst preview = changedNames.slice(0, 3).join(', ');\nconst more = changedNames.length > 3 ? ' (+' + (changedNames.length - 3) + ' more)' : '';\n\nconst author = (j.triggered_by && j.triggered_by.handle) || 'Unknown';\nconst when = slackDate(j.timestamp);\n\n// Build the message line by line; skip lines we have no data for.\nconst lines = ['\ud83c\udfa8 *Library published* \u2014 *' + j.file_name + '*'];\nif (summary) lines.push(summary + ' updated');\nif (preview) lines.push('Changed: ' + preview + more);\nif (j.description) lines.push('Note: ' + j.description);\nlines.push('by ' + author + (when ? ' \u00b7 ' + when : ''));\nlines.push('<https://www.figma.com/file/' + j.file_key + '|Open in Figma>');\n\nreturn { slackText: lines.join('\\n') };\n\n// Absolute, viewer-local timestamp via a Slack date token\n// (renders as e.g. \"Jun 28, 2026 at 5:24 PM\" in each reader's timezone).\nfunction slackDate(iso) {\n  if (!iso) return '';\n  const epoch = Math.floor(new Date(iso).getTime() / 1000);\n  return '<!date^' + epoch + '^{date_short} at {time}|' + iso + '>';\n}"
      },
      "typeVersion": 2
    },
    {
      "id": "c48bfa08-adf4-4edb-bd58-35d7bd6051fd",
      "name": "Build Comment Event Message",
      "type": "n8n-nodes-base.code",
      "position": [
        1296,
        336
      ],
      "parameters": {
        "mode": "runOnceForEachItem",
        "jsCode": "// FILE_COMMENT \u2192 Slack message\n// The same event fires for new comments, replies (parent_id set) and\n// resolves (resolved_at set). The comment body is an array of fragments,\n// each either { text } or { mention: <userId> }.\nconst j = $json;\n\n// Map mentioned user ids \u2192 handles, using the top-level mentions[] list.\nconst handleById = {};\nfor (const u of (j.mentions || [])) {\n  if (u && u.id) handleById[u.id] = u.handle;\n}\n\n// Rebuild the comment text, swapping mention ids for \"@handle\".\nconst body = (j.comment || [])\n  .map((frag) => {\n    if (frag && frag.text != null) return frag.text;\n    if (frag && frag.mention) return '@' + (handleById[frag.mention] || 'someone');\n    return '';\n  })\n  .join('')\n  .trim();\n\nconst author = (j.triggered_by && j.triggered_by.handle) || 'Someone';\nconst mentioned = (j.mentions || []).map((u) => u.handle).filter(Boolean);\n\n// Heading depends on the kind of comment event.\nlet heading = '\ud83d\udcac *New comment*';\nif (j.resolved_at) heading = '\ud83d\udcac *Comment resolved*';\nelse if (j.parent_id) heading = '\ud83d\udcac *New reply*';\n\nconst lines = [heading + ' \u2014 *' + j.file_name + '*'];\nlines.push(author + (mentioned.length ? ' \u2192 ' + mentioned.join(', ') : '') + ': \"' + body + '\"');\nlines.push(\n  (slackDate(j.timestamp) ? slackDate(j.timestamp) + ' \u00b7 ' : '') +\n  '<https://www.figma.com/file/' + j.file_key + '?comment-id=' + j.comment_id + '|Reply in Figma>'\n);\n\nreturn { slackText: lines.join('\\n') };\n\n// Absolute, viewer-local timestamp via a Slack date token.\nfunction slackDate(iso) {\n  if (!iso) return '';\n  const epoch = Math.floor(new Date(iso).getTime() / 1000);\n  return '<!date^' + epoch + '^{date_short} at {time}|' + iso + '>';\n}"
      },
      "typeVersion": 2
    },
    {
      "id": "6f6e4de0-3175-4600-93c8-e67921afb34d",
      "name": "Build Delete Event Message",
      "type": "n8n-nodes-base.code",
      "position": [
        1296,
        656
      ],
      "parameters": {
        "mode": "runOnceForEachItem",
        "jsCode": "// FILE_DELETE \u2192 Slack message\nconst j = $json;\n\nconst author = (j.triggered_by && j.triggered_by.handle) || 'Someone';\nconst when = slackDate(j.timestamp);\n\nconst lines = ['\ud83d\uddd1\ufe0f *File deleted* \u2014 *' + j.file_name + '*'];\nlines.push('by ' + author + (when ? ' \u00b7 ' + when : ''));\nlines.push('Recoverable from Figma trash for 30 days');\n\nreturn { slackText: lines.join('\\n') };\n\n// Absolute, viewer-local timestamp via a Slack date token.\nfunction slackDate(iso) {\n  if (!iso) return '';\n  const epoch = Math.floor(new Date(iso).getTime() / 1000);\n  return '<!date^' + epoch + '^{date_short} at {time}|' + iso + '>';\n}"
      },
      "typeVersion": 2
    }
  ],
  "active": false,
  "settings": {
    "binaryMode": "separate",
    "availableInMCP": false,
    "executionOrder": "v1"
  },
  "versionId": "45b5e0a6-dfca-40c3-9199-572994aad555",
  "nodeGroups": [],
  "connections": {
    "When File Deleted": {
      "main": [
        [
          {
            "node": "Build Delete Event Message",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "When File Commented": {
      "main": [
        [
          {
            "node": "Build Comment Event Message",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "When Library Published": {
      "main": [
        [
          {
            "node": "Build Library Event Message",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Build Delete Event Message": {
      "main": [
        [
          {
            "node": "Send Message to Slack",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Build Comment Event Message": {
      "main": [
        [
          {
            "node": "Send Message to Slack",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Build Library Event Message": {
      "main": [
        [
          {
            "node": "Send Message to Slack",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  }
}