{
  "id": "2I9c1wem2bFGuXzz",
  "meta": {
    "instanceId": "71ecea07edbb806c100ea5f8b695a5001787e0b017af53d28d0fd42f17f9e429",
    "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": {
          "id": "credential-id",
          "name": "hubspotAppToken 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": {
          "id": "credential-id",
          "name": "serpApi 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": {
          "id": "credential-id",
          "name": "hubspotAppToken Credential"
        }
      },
      "typeVersion": 2.1
    },
    {
      "id": "51e2c470-d682-4d33-b240-595f41fae02b",
      "name": "HubSpot Trigger",
      "type": "n8n-nodes-base.hubspotTrigger",
      "position": [
        1088,
        -432
      ],
      "webhookId": "20472f77-81b8-4840-9065-fa07c2d19188",
      "parameters": {
        "eventsUi": {
          "eventValues": [
            {}
          ]
        },
        "additionalFields": {}
      },
      "credentials": {
        "hubspotDeveloperApi": {
          "id": "credential-id",
          "name": "hubspotDeveloperApi Credential"
        }
      },
      "typeVersion": 1
    },
    {
      "id": "563816de-2bff-4952-ad73-402d56f34e3d",
      "name": "When clicking ‘Execute workflow’",
      "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": {
          "id": "credential-id",
          "name": "googleApi 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": {
          "id": "credential-id",
          "name": "openRouterApi 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🚀 **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’s likely LinkedIn profile and produce a concise result.\n* Code – Remove Think Part: Cleans the model output (removes hidden “think” 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🔑 **Required Credentials:**\n* HubSpot App Token (Private App) — for Get/Update contact nodes.\n* HubSpot Developer OAuth (optional) — if you use the HubSpot * Trigger node for event-based runs.\n* Google Service Account — for the Google Docs tool (share your * playbook doc with this service account).\n* OpenRouter — for the OpenRouter Chat Model used by the AI Agent.\n* SerpAPI — for targeted Google searches from within the Agent.\n\n\n🛠️ **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[➡️ 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–2 searches).\n\n\n✨ **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—no workflow changes needed.\n* Tight, low-noise searches via SerpAPI to keep costs down.\n\n\nAnd that’s it—publish 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,
  "pinData": {},
  "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 ‘Execute workflow’": {
      "main": [
        [
          {
            "node": "Get recently created/updated contacts",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Get recently created/updated contacts": {
      "main": [
        [
          {
            "node": "Edit Fields",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  }
}