{
  "id": "2I9c1wem2bFGuXzz",
  "meta": {
    "templateCredsSetupCompleted": true
  },
  "name": "HubSpot Contact Refinement",
  "tags": [],
  "nodes": [
    {
      "id": "28164fc1-96bb-44ea-8e1e-2652e94e7679",
      "name": "AI Agent",
      "type": "@n8n/n8n-nodes-langchain.agent",
      "position": [
        1920,
        -640
      ],
      "parameters": {
        "text": "=First Use Read Google Docs tool to understand how to do the research on a specific contact and the expected output format\n\nThen do the research with Google search on this \ncontact-\nFirst Name: {{ $json['First Name'] }}\nLast Name: {{ $json['Last Name'] }}\nEmail: {{ $json.Email }}\n\n",
        "options": {},
        "promptType": "define"
      },
      "typeVersion": 2.2
    },
    {
      "id": "0505748a-f6da-4ebb-981f-a189891ba38a",
      "name": "HubSpot",
      "type": "n8n-nodes-base.hubspot",
      "position": [
        2704,
        -640
      ],
      "parameters": {
        "email": "={{ $('Edit Fields').item.json.Email }}",
        "options": {},
        "authentication": "appToken",
        "additionalFields": {
          "linkedinUrl": "={{ $json.cleanText }}"
        }
      },
      "credentials": {
        "hubspotAppToken": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 2.1
    },
    {
      "id": "eee601f3-e202-402b-890b-daab67ea3a32",
      "name": "SerpAPI",
      "type": "@n8n/n8n-nodes-langchain.toolSerpApi",
      "position": [
        2208,
        -432
      ],
      "parameters": {
        "options": {}
      },
      "credentials": {
        "serpApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1
    },
    {
      "id": "64e12389-996c-4682-9c2e-16abe6cef7fb",
      "name": "Get recently created/updated contacts",
      "type": "n8n-nodes-base.hubspot",
      "position": [
        1312,
        -640
      ],
      "parameters": {
        "operation": "getRecentlyCreatedUpdated",
        "authentication": "appToken",
        "additionalFields": {}
      },
      "credentials": {
        "hubspotAppToken": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 2.1
    },
    {
      "id": "51e2c470-d682-4d33-b240-595f41fae02b",
      "name": "HubSpot Trigger",
      "type": "n8n-nodes-base.hubspotTrigger",
      "position": [
        1088,
        -432
      ],
      "parameters": {
        "eventsUi": {
          "eventValues": [
            {}
          ]
        },
        "additionalFields": {}
      },
      "credentials": {
        "hubspotDeveloperApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1
    },
    {
      "id": "563816de-2bff-4952-ad73-402d56f34e3d",
      "name": "When clicking \u2018Execute workflow\u2019",
      "type": "n8n-nodes-base.manualTrigger",
      "position": [
        1104,
        -640
      ],
      "parameters": {},
      "typeVersion": 1
    },
    {
      "id": "643250fa-48b9-4e7e-8c40-b9614e56354d",
      "name": "Code - Remove Think part",
      "type": "n8n-nodes-base.code",
      "position": [
        2432,
        -640
      ],
      "parameters": {
        "mode": "runOnceForEachItem",
        "jsCode": "// Remove <think>...</think> (and optional ```json fences) from this item's text\nlet text = $json.text ?? $json.output ?? $json.result ?? \"\";\n\ntext = String(text)\n  .replace(/<think>[\\s\\S]*?<\\/think>/gi, \"\")\n  .replace(/^```(?:json)?\\s*|\\s*```$/g, \"\")\n  .trim();\n\n// Return ONLY the cleaned field\nreturn { json: { cleanText: text } };\n"
      },
      "typeVersion": 2
    },
    {
      "id": "1dbaf3d7-077a-48da-a0dd-fc09aa9cb48e",
      "name": "Read Google Docs",
      "type": "n8n-nodes-base.googleDocsTool",
      "position": [
        2080,
        -432
      ],
      "parameters": {
        "operation": "get",
        "documentURL": "Replace_With_URL",
        "authentication": "serviceAccount",
        "descriptionType": "manual",
        "toolDescription": "Get a document in Google Docs"
      },
      "credentials": {
        "googleApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 2
    },
    {
      "id": "4bcec552-cf09-485d-8584-a9490bd66de4",
      "name": "Edit Fields",
      "type": "n8n-nodes-base.set",
      "position": [
        1584,
        -640
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "d4e105c6-b0a1-43c9-9a28-c6b9a7f92381",
              "name": "First Name",
              "type": "string",
              "value": "={{ $json.properties.firstname.value }}"
            },
            {
              "id": "b04d763a-9e5f-4b65-8eb6-f100ce802395",
              "name": "Last Name",
              "type": "string",
              "value": "={{ $json.properties.lastname.value }}"
            },
            {
              "id": "4cd40bc6-0c25-40d4-98d8-11dbb5b56cc7",
              "name": "Email",
              "type": "string",
              "value": "={{ $json['identity-profiles'][0].identities[0].value }}"
            }
          ]
        }
      },
      "typeVersion": 3.4
    },
    {
      "id": "ab4cf5e3-bcab-470f-9f09-36e3431ed71d",
      "name": "OpenRouter Chat Model",
      "type": "@n8n/n8n-nodes-langchain.lmChatOpenRouter",
      "position": [
        1824,
        -432
      ],
      "parameters": {
        "options": {}
      },
      "credentials": {
        "openRouterApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1
    },
    {
      "id": "aab92067-a3f9-4a91-855c-1f22602a9930",
      "name": "Sticky Note",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1040,
        -816
      ],
      "parameters": {
        "color": 7,
        "width": 208,
        "height": 528,
        "content": "## Innitiate the Workflow\n"
      },
      "typeVersion": 1
    },
    {
      "id": "8197ccfd-c289-4ebb-a78c-f46fe9527d07",
      "name": "Sticky Note1",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1280,
        -816
      ],
      "parameters": {
        "color": 7,
        "width": 432,
        "height": 528,
        "content": "## Data Clean Up\n"
      },
      "typeVersion": 1
    },
    {
      "id": "64bfb439-a5c3-46ea-82c8-7d5d92f1fa9d",
      "name": "Sticky Note2",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1776,
        -816
      ],
      "parameters": {
        "color": 7,
        "width": 544,
        "height": 528,
        "content": "## AI Agent Led Contact Research\nAI agent performs Google search to find useful information from LinedIn Profile\n"
      },
      "typeVersion": 1
    },
    {
      "id": "c8ceb524-9b03-4b6e-a01b-04d8fbba2627",
      "name": "Sticky Note3",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        2368,
        -816
      ],
      "parameters": {
        "color": 7,
        "width": 256,
        "height": 528,
        "content": "## Data Clean up\nThink tag portion is common from smaller models and are removed "
      },
      "typeVersion": 1
    },
    {
      "id": "704037d1-f9b8-4df5-8367-8b61483b4c74",
      "name": "Sticky Note4",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        2656,
        -816
      ],
      "parameters": {
        "color": 7,
        "width": 256,
        "height": 528,
        "content": "## Update Hubspot Contact\nThe workflow updates LinkedIn field for the contact"
      },
      "typeVersion": 1
    },
    {
      "id": "93afa981-4a11-4228-b2bc-3072947789df",
      "name": "Sticky Note5",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        336,
        -1248
      ],
      "parameters": {
        "width": 576,
        "height": 1328,
        "content": "## HubSpot Contact Refinement\n\n\ud83d\ude80 **How it works**\n\n**Triggers:**\n* HubSpot Trigger: Fires when contacts are created/updated.\n* Manual Trigger: Run on demand for testing or batch checks.\n* Get Recently Created/Updated Contacts: Pulls fresh contacts from HubSpot.\n* Edit Fields (Set): Maps key fields (First Name, Last Name, Email) for the Agent.\n\n\n**AI Agent:**\n* First reads your Google Doc (via the Google Docs tool) to learn the research steps and output format.\n* Then uses SerpAPI (Google engine) to locate the contact\u2019s likely LinkedIn profile and produce a concise result.\n* Code \u2013 Remove Think Part: Cleans the model output (removes hidden \u201cthink\u201d blocks / formatting) so only the final answer remains.\n* HubSpot Update: Writes the cleaned LinkedIn URL to the contact (via email match).\n\n\n\ud83d\udd11 **Required Credentials:**\n* HubSpot App Token (Private App) \u2014 for Get/Update contact nodes.\n* HubSpot Developer OAuth (optional) \u2014 if you use the HubSpot * Trigger node for event-based runs.\n* Google Service Account \u2014 for the Google Docs tool (share your * playbook doc with this service account).\n* OpenRouter \u2014 for the OpenRouter Chat Model used by the AI Agent.\n* SerpAPI \u2014 for targeted Google searches from within the Agent.\n\n\n\ud83d\udee0\ufe0f **Setup Instructions**\n\n**HubSpot**\n* Create a Private App and copy the Access Token.\n* Add or confirm the contact property linkedinUrl (Text).\n* Plug the token into the HubSpot nodes.\n* If using HubSpot Trigger, connect your Developer OAuth app and subscribe to contact create/update events.\n\n\n**Google Docs (Living Instructions)**\n\n[\u27a1\ufe0f Sample configuration doc file](https://docs.google.com/document/d/1nn69H3wdwXJolDwu0avlFw7sIwnX_Hpr3bmOD6PgdW4/edit?usp=sharing)\n* Copy the sample doc file and modify to your need.\n* Share the doc with your Google Service Account (Viewer is fine).\n* In the Read Google Docs node, paste the Document URL.\n\n**OpenRouter & SerpAPI**\n* Add your OpenRouter key to the OpenRouter Chat Model credential.\n* Add your SerpAPI key to the SerpAPI tool node.\n* (Optional) In your Google Doc or Agent prompt, set sensible defaults for SerpAPI (engine=google, hl=en, gl=us, num=5, max 1\u20132 searches).\n\n\n\u2728 **What you get**\n* Auto-enriched contacts with a LinkedIn URL and profile insights (clean, validated output).\n* A research process you can change anytime by editing the Google Doc\u2014no workflow changes needed.\n* Tight, low-noise searches via SerpAPI to keep costs down.\n\n\nAnd that\u2019s it\u2014publish and let the Agent enrich new leads automatically while you refine the rules in your doc. It allows handing off to a team who wouldn't necessarily tweak the automation nodes."
      },
      "typeVersion": 1
    }
  ],
  "active": false,
  "settings": {
    "executionOrder": "v1"
  },
  "versionId": "b1690f40-eaa8-4ee0-9670-9586357288ab",
  "connections": {
    "SerpAPI": {
      "ai_tool": [
        [
          {
            "node": "AI Agent",
            "type": "ai_tool",
            "index": 0
          }
        ]
      ]
    },
    "AI Agent": {
      "main": [
        [
          {
            "node": "Code - Remove Think part",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Edit Fields": {
      "main": [
        [
          {
            "node": "AI Agent",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "HubSpot Trigger": {
      "main": [
        [
          {
            "node": "Edit Fields",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Read Google Docs": {
      "ai_tool": [
        [
          {
            "node": "AI Agent",
            "type": "ai_tool",
            "index": 0
          }
        ]
      ]
    },
    "OpenRouter Chat Model": {
      "ai_languageModel": [
        [
          {
            "node": "AI Agent",
            "type": "ai_languageModel",
            "index": 0
          }
        ]
      ]
    },
    "Code - Remove Think part": {
      "main": [
        [
          {
            "node": "HubSpot",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "When clicking \u2018Execute workflow\u2019": {
      "main": [
        [
          {
            "node": "Get recently created/updated contacts",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Get recently created/updated contacts": {
      "main": [
        [
          {
            "node": "Edit Fields",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  }
}