{
  "id": "PLACEHOLDER_WORKFLOW_ID",
  "meta": {
    "templateCredsSetupCompleted": true
  },
  "name": "20 - HubSpot to Slack Contact Card",
  "tags": [],
  "nodes": [
    {
      "id": "00cc9790-780b-45e8-bb85-1613ef34cd05",
      "name": "\ud83c\udf10 Incoming Slash Command",
      "type": "n8n-nodes-base.webhook",
      "position": [
        -900,
        200
      ],
      "parameters": {
        "path": "hubspot-contact-lookup",
        "options": {},
        "httpMethod": "POST"
      },
      "typeVersion": 2
    },
    {
      "id": "06f703df-a621-4c3b-a860-83859f8db226",
      "name": "\ud83d\udd0d Check if Message Exists",
      "type": "n8n-nodes-base.if",
      "position": [
        -680,
        200
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 2,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "ec3773aa-e58f-4743-b2f1-ac508daf3c87",
              "operator": {
                "type": "string",
                "operation": "notEmpty",
                "singleValue": true
              },
              "leftValue": "={{ $json.body.text }}",
              "rightValue": ""
            }
          ]
        }
      },
      "typeVersion": 2.2
    },
    {
      "id": "2898d6d5-8cd5-4e71-bf09-bc3303dea75b",
      "name": "\ud83d\uded1 Stop \u2013 Missing Message",
      "type": "n8n-nodes-base.stopAndError",
      "position": [
        -460,
        300
      ],
      "parameters": {
        "errorMessage": "No message found"
      },
      "typeVersion": 1
    },
    {
      "id": "b1bbfab9-57d8-4d26-9ab7-95e66dffa40d",
      "name": "\u2702\ufe0f Parse Search Input",
      "type": "n8n-nodes-base.code",
      "position": [
        -460,
        100
      ],
      "parameters": {
        "jsCode": "const input = $input.first().json.body.text || '';\nconst trimmedInput = input.trim();\n\nif (!trimmedInput) {\n  throw new Error('Please provide an email address or HubSpot contact ID');\n}\n\nconst emailRegex = /^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$/;\nconst isEmail = emailRegex.test(trimmedInput);\n\nreturn {\n  searchValue: trimmedInput,\n  searchType: isEmail ? 'email' : 'id',\n  channelId: $json.channel_id,\n  userId: $json.user_id,\n  responseUrl: $json.response_url\n};"
      },
      "typeVersion": 2
    },
    {
      "id": "e05b7063-1779-427d-b23f-b0fc9f6a20ad",
      "name": "\ud83d\udd00 Determine Search Type",
      "type": "n8n-nodes-base.if",
      "position": [
        -240,
        100
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 1,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "condition1",
              "operator": {
                "type": "string",
                "operation": "equals"
              },
              "leftValue": "={{ $json.searchType }}",
              "rightValue": "email"
            }
          ]
        }
      },
      "typeVersion": 2
    },
    {
      "id": "e19a4c16-c33e-4bb5-8060-12e52e356d71",
      "name": "\ud83d\udce7 Search Contact by Email",
      "type": "n8n-nodes-base.hubspot",
      "position": [
        -20,
        0
      ],
      "parameters": {
        "operation": "search",
        "authentication": "appToken",
        "filterGroupsUi": {
          "filterGroupsValues": [
            {
              "filtersUi": {
                "filterValues": [
                  {
                    "value": "={{ $json.searchValue }}",
                    "propertyName": "email|string"
                  }
                ]
              }
            }
          ]
        },
        "additionalFields": {
          "properties": [
            "firstname",
            "lastname",
            "email",
            "phone"
          ]
        }
      },
      "credentials": {
        "hubspotAppToken": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 2.1
    },
    {
      "id": "47964017-2ed4-4f4a-a180-8f89759a54d0",
      "name": "\ud83c\udd94 Get Contact by ID",
      "type": "n8n-nodes-base.hubspot",
      "position": [
        -20,
        200
      ],
      "parameters": {
        "contactId": {
          "__rl": true,
          "mode": "id",
          "value": "={{ $json.searchValue }}"
        },
        "operation": "get",
        "authentication": "appToken",
        "additionalFields": {}
      },
      "credentials": {
        "hubspotAppToken": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 2
    },
    {
      "id": "f6fc8617-197a-42da-9d5b-4d42d428b40d",
      "name": "\ud83d\udcdd Format Contact Info (ID Search)",
      "type": "n8n-nodes-base.code",
      "position": [
        200,
        200
      ],
      "parameters": {
        "jsCode": "const items = $input.all();\nlet contact = null;\n\nif (items.length === 0) {\n  return {\n    success: false,\n    message: 'Contact not found',\n    channelId: $('\u2702\ufe0f Parse Search Input').item.json.channelId,\n    responseUrl: $('\u2702\ufe0f Parse Search Input').item.json.responseUrl\n  };\n}\n\nif (items[0].json.results && items[0].json.results.length > 0) {\n  contact = items[0].json.results[0].properties;\n} else if (items[0].json.properties) {\n  contact = items[0].json.properties;\n} else {\n  return {\n    success: false,\n    message: 'Contact not found',\n    channelId: $('\u2702\ufe0f Parse Search Input').item.json.channelId,\n    responseUrl: $('\u2702\ufe0f Parse Search Input').item.json.responseUrl\n  };\n}\n\nconst firstName = $input.first().json.properties.firstname.value || '';\nconst lastName = $input.first().json.properties.lastname.value || '';\nconst fullName = $input.first().json.properties.hs_full_name_or_email.value || 'N/A';\nconst email = $input.first().json.properties.email.value || 'N/A';\nconst phone = $input.first().json.properties.phone.value || 'N/A';\n\nconst message = `\ud83d\udccb *Contact Information*\\n\\n` +\n  `\ud83d\udc64 *Name:* ${fullName}\\n` +\n  `\ud83d\udce7 *Email:* ${email}\\n` +\n  `\ud83d\udcde *Phone:* ${phone}`;\n\nreturn {\n  success: true,\n  message: message,\n  channelId: $('\u2702\ufe0f Parse Search Input').item.json.channelId,\n  responseUrl: $('\u2702\ufe0f Parse Search Input').item.json.responseUrl\n};"
      },
      "typeVersion": 2
    },
    {
      "id": "5cb1767c-6d3d-4f08-b486-2cc1a59d2bd2",
      "name": "\ud83d\udcdd Format Contact Info (Email Search)",
      "type": "n8n-nodes-base.code",
      "position": [
        200,
        0
      ],
      "parameters": {
        "jsCode": "const items = $input.all();\nlet contact = null;\n\nif (items.length === 0) {\n  return {\n    success: false,\n    message: 'Contact not found'\n  };\n}\n\n// Your input has `properties` directly inside the first item\nif (items[0].json.properties) {\n  contact = items[0].json.properties;\n} else {\n  return {\n    success: false,\n    message: 'Contact not found'\n  };\n}\n\nconst firstName = contact.firstname || '';\nconst lastName = contact.lastname || '';\nconst fullName = [firstName, lastName].filter(Boolean).join(' ') || 'N/A';\nconst email = contact.email || 'N/A';\nconst phone = contact.phone || 'N/A';\nconst company = contact.company || 'N/A';\nconst dealStage = contact.dealstage || 'N/A';\n\n\nconst message = `\ud83d\udccb *Contact Information*\\n\\n` +\n  `\ud83d\udc64 *Name:* ${fullName}\\n` +\n  `\ud83d\udce7 *Email:* ${email}\\n` +\n  `\ud83d\udcde *Phone:* ${phone}\\n` +\n  `\ud83c\udfe2 *Company:* ${company}\\n` +\n  `\ud83d\udcbc *Deal Stage:* ${dealStage}`;\n\nreturn {\n  success: true,\n  message\n};"
      },
      "typeVersion": 2
    },
    {
      "id": "2df1ebf2-bda8-4112-994d-352a587ba91d",
      "name": "\ud83d\udcac Send Contact Info to Slack",
      "type": "n8n-nodes-base.slack",
      "position": [
        420,
        100
      ],
      "parameters": {
        "text": "={{ $json.message }}",
        "select": "channel",
        "channelId": {
          "__rl": true,
          "mode": "id",
          "value": "YOUR_CHANNEL_ID"
        },
        "otherOptions": {}
      },
      "credentials": {
        "slackApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 2.1
    },
    {
      "id": "3fadae4a-a629-4c2a-aa3c-ed5d953ff1a4",
      "name": "Sticky Note",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -940,
        -60
      ],
      "parameters": {
        "width": 420,
        "height": 520,
        "content": "## Nodes: Incoming Webhook (Webhook) + Check if Message Exists (If)\n\n*This section handles receiving incoming requests (e.g., from Slack) and ensuring they contain a valid message. If the message text is empty, the workflow stops with an error response. This prevents unnecessary API calls when no search term (email or ID) is provided.*"
      },
      "typeVersion": 1
    },
    {
      "id": "220b5b75-09af-4315-9844-d0740dc9d1cf",
      "name": "Sticky Note1",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -500,
        -160
      ],
      "parameters": {
        "color": 5,
        "width": 420,
        "height": 420,
        "content": "## Nodes: Parse Search Input (Parse Input) + Determine Search Type (Check Search Type)\n\n*Parses the incoming message to extract and clean the search value. Determines if the provided value is a valid email address or a HubSpot contact ID using regex. This decision directs the workflow toward the correct HubSpot search method.*"
      },
      "typeVersion": 1
    },
    {
      "id": "0aad2c24-807f-4065-a905-19f0489d8bf3",
      "name": "Sticky Note2",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -60,
        -420
      ],
      "parameters": {
        "color": 4,
        "width": 190,
        "height": 780,
        "content": "## Nodes: Search Contact by Email (HubSpot) + Get Contact by ID (Get by ID)\n\n*If the input is an email \u2192 searches HubSpot using the email filter.\n\nIf the input is an ID \u2192 retrieves the contact record directly by ID*"
      },
      "typeVersion": 1
    },
    {
      "id": "9a3e57b1-fc33-411c-8237-5285158a06ad",
      "name": "Sticky Note3",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        160,
        -420
      ],
      "parameters": {
        "color": 6,
        "width": 190,
        "height": 780,
        "content": "## Nodes: Format Contact Info\n\n*Formats the retrieved HubSpot contact properties into a Slack-friendly message. Includes name, email, phone number, and other key details like company and deal stage where available. Ensures consistent presentation regardless of the search method used.*"
      },
      "typeVersion": 1
    },
    {
      "id": "2d27ce7f-2d1f-4dbb-8116-225661aa9be4",
      "name": "Sticky Note4",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        380,
        -240
      ],
      "parameters": {
        "color": 3,
        "width": 190,
        "height": 600,
        "content": "## Node: Send Contact Info to Slack (Send to Slack)\n\n*Sends the formatted contact information to the designated Slack channel, making it immediately accessible to the requesting user or team.*"
      },
      "typeVersion": 1
    }
  ],
  "active": false,
  "settings": {
    "executionOrder": "v1"
  },
  "versionId": "PLACEHOLDER_VERSION_ID",
  "connections": {
    "\ud83c\udd94 Get Contact by ID": {
      "main": [
        [
          {
            "node": "\ud83d\udcdd Format Contact Info (ID Search)",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "\u2702\ufe0f Parse Search Input": {
      "main": [
        [
          {
            "node": "\ud83d\udd00 Determine Search Type",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "\ud83d\udd00 Determine Search Type": {
      "main": [
        [
          {
            "node": "\ud83d\udce7 Search Contact by Email",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "\ud83c\udd94 Get Contact by ID",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "\ud83c\udf10 Incoming Slash Command": {
      "main": [
        [
          {
            "node": "\ud83d\udd0d Check if Message Exists",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "\ud83d\udce7 Search Contact by Email": {
      "main": [
        [
          {
            "node": "\ud83d\udcdd Format Contact Info (Email Search)",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "\ud83d\udd0d Check if Message Exists": {
      "main": [
        [
          {
            "node": "\u2702\ufe0f Parse Search Input",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "\ud83d\uded1 Stop \u2013 Missing Message",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "\ud83d\udcdd Format Contact Info (ID Search)": {
      "main": [
        [
          {
            "node": "\ud83d\udcac Send Contact Info to Slack",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "\ud83d\udcdd Format Contact Info (Email Search)": {
      "main": [
        [
          {
            "node": "\ud83d\udcac Send Contact Info to Slack",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  }
}