<?xml version="1.0" encoding="UTF-8"?>
<rss xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:taxo="http://purl.org/rss/1.0/modules/taxonomy/" version="2.0">
  <channel>
    <title>topic Cannot merge two contacts using custom code in workflow in Data Hub</title>
    <link>https://community.hubspot.com/t5/Data-Hub/Cannot-merge-two-contacts-using-custom-code-in-workflow/m-p/1140363#M3013</link>
    <description>&lt;P&gt;I am attempting to use the custom code workflow capabilities in Operation Hub to merge two contacts if they match on the mobilephone (internal name) property. This is very similar to the use case provided by Hubspot staff here&amp;nbsp;&lt;A href="https://github.com/HubSpot/sample-workflow-custom-code/blob/main/samples/dedupe_contact.js" target="_blank" rel="noopener"&gt;sample-workflow-custom-code/samples/dedupe_contact.js at main · HubSpot/sample-workflow-custom-code · GitHub&lt;/A&gt;&lt;BR /&gt;&lt;BR /&gt;However, that code does nothing anymore when run and gives linting tips that mergeResults is defined but never used, and uses the now deprecated v1 APIs.&lt;BR /&gt;&lt;BR /&gt;I've tried rewriting it to use the v3 merge API and the log does show that the workflow successfully found a matching contact ID with the same mobilephone number as the enrolled contact's, and it says it successfully sent the merge request to the merge API for those two IDs. But they are not merged. Any idea why? Here's the current node.js code:&lt;/P&gt;&lt;LI-SPOILER&gt;&lt;P&gt;/**&lt;BR /&gt;* HubSpot Workflow Custom Code: Merge contacts by matching mobilephone&lt;BR /&gt;*&lt;BR /&gt;* Logic:&lt;BR /&gt;* - If NO other contact matches → do nothing&lt;BR /&gt;* - If EXACTLY 1 other contact matches → MERGE enrolled contact into that contact&lt;BR /&gt;* - If 2+ other contacts match → skip merge (ambiguous)&lt;BR /&gt;*/&lt;/P&gt;&lt;P&gt;const hubspot = require('@hubspot/api-client');&lt;BR /&gt;const DEDUPE_PROPERTY = 'mobilephone';&lt;/P&gt;&lt;P&gt;exports.main = async (event, callback) =&amp;gt; {&lt;BR /&gt;const hubspotClient = new hubspot.Client({&lt;BR /&gt;accessToken: process.env.[SECRET]&lt;BR /&gt;});&lt;/P&gt;&lt;P&gt;try {&lt;BR /&gt;const enrolledId = event.object.objectId;&lt;BR /&gt;const enrolledIdStr = String(enrolledId);&lt;/P&gt;&lt;P&gt;// 1) Fetch enrolled contact's mobilephone&lt;BR /&gt;const contact = await hubspotClient.crm.contacts.basicApi.getById(&lt;BR /&gt;enrolledId,&lt;BR /&gt;[DEDUPE_PROPERTY]&lt;BR /&gt;);&lt;/P&gt;&lt;P&gt;const phoneValue = contact.properties?.[DEDUPE_PROPERTY];&lt;/P&gt;&lt;P&gt;if (!phoneValue) {&lt;BR /&gt;console.log('No mobilephone on enrolled contact; nothing to merge.');&lt;BR /&gt;return callback(null, { status: 'no_mobilephone' });&lt;BR /&gt;}&lt;/P&gt;&lt;P&gt;console.log(`Searching for contacts with ${DEDUPE_PROPERTY} = ${phoneValue}`);&lt;/P&gt;&lt;P&gt;// 2) Search for contacts with matching mobilephone&lt;BR /&gt;const search = await hubspotClient.crm.contacts.searchApi.doSearch({&lt;BR /&gt;filterGroups: [{&lt;BR /&gt;filters: [{&lt;BR /&gt;propertyName: DEDUPE_PROPERTY,&lt;BR /&gt;operator: 'EQ',&lt;BR /&gt;value: phoneValue&lt;BR /&gt;}]&lt;BR /&gt;}],&lt;BR /&gt;limit: 10&lt;BR /&gt;});&lt;/P&gt;&lt;P&gt;const matchingIds = (search.results || [])&lt;BR /&gt;.map(c =&amp;gt; c.id)&lt;BR /&gt;.filter(id =&amp;gt; String(id) !== enrolledIdStr);&lt;/P&gt;&lt;P&gt;console.log(`Found ${matchingIds.length} other contacts with same mobilephone.`);&lt;/P&gt;&lt;P&gt;// --- Merge Logic ---&lt;BR /&gt;if (matchingIds.length === 0) {&lt;BR /&gt;console.log('No duplicates found. Nothing to merge.');&lt;BR /&gt;return callback(null, { status: 'no_duplicates' });&lt;BR /&gt;}&lt;/P&gt;&lt;P&gt;if (matchingIds.length &amp;gt;= 2) {&lt;BR /&gt;console.log('Ambiguous: 2 or more other contacts found. No merge performed.');&lt;BR /&gt;return callback(null, { status: 'ambiguous_duplicates' });&lt;BR /&gt;}&lt;/P&gt;&lt;P&gt;// 3) Exactly 1 match → perform merge using direct API call&lt;BR /&gt;const primaryId = matchingIds[0];&lt;BR /&gt;console.log(`Merging enrolled contact (${enrolledId}) INTO contact (${primaryId})`);&lt;/P&gt;&lt;P&gt;try {&lt;BR /&gt;await hubspotClient.apiRequest({&lt;BR /&gt;method: 'POST',&lt;BR /&gt;path: '/crm/v3/objects/contacts/merge',&lt;BR /&gt;body: {&lt;BR /&gt;primaryObjectId: primaryId,&lt;BR /&gt;secondaryObjectId: enrolledId&lt;BR /&gt;}&lt;BR /&gt;});&lt;/P&gt;&lt;P&gt;console.log('&lt;span class="lia-unicode-emoji" title=":white_heavy_check_mark:"&gt;✅&lt;/span&gt; Merge request sent successfully (HubSpot may return 204 No Content).');&lt;BR /&gt;return callback(null, { status: 'merged', merged_into: primaryId });&lt;/P&gt;&lt;P&gt;} catch (mergeErr) {&lt;BR /&gt;console.error('&lt;span class="lia-unicode-emoji" title=":cross_mark:"&gt;❌&lt;/span&gt; Merge API failed:', mergeErr.response?.body || mergeErr);&lt;BR /&gt;return callback(mergeErr);&lt;BR /&gt;}&lt;/P&gt;&lt;P&gt;} catch (err) {&lt;BR /&gt;console.error('&lt;span class="lia-unicode-emoji" title=":cross_mark:"&gt;❌&lt;/span&gt; General error during merge process:', err);&lt;BR /&gt;return callback(err);&lt;BR /&gt;}&lt;BR /&gt;};&lt;/P&gt;&lt;/LI-SPOILER&gt;&lt;P&gt;&lt;BR /&gt;And here's the latest log:&lt;/P&gt;&lt;LI-SPOILER&gt;&lt;P class=""&gt;Logs&lt;/P&gt;&lt;DIV class=""&gt;&lt;DIV class=""&gt;&lt;DIV&gt;2025-04-24T16:21:28.815Z INFO Searching for contacts with mobilephone = [hidden] 2025-04-24T16:21:29.135Z INFO Found 1 other contacts with same mobilephone. 2025-04-24T16:21:29.136Z INFO Merging enrolled contact (12479851) INTO contact (44946951) 2025-04-24T16:21:29.258Z INFO &lt;span class="lia-unicode-emoji" title=":white_heavy_check_mark:"&gt;✅&lt;/span&gt; Merge request sent successfully (HubSpot may return 204 No Content).&lt;/DIV&gt;&lt;/DIV&gt;&lt;/DIV&gt;&lt;/LI-SPOILER&gt;&lt;P&gt;&lt;BR /&gt;&lt;BR /&gt;&lt;/P&gt;</description>
    <pubDate>Thu, 24 Apr 2025 16:37:58 GMT</pubDate>
    <dc:creator>customtruck</dc:creator>
    <dc:date>2025-04-24T16:37:58Z</dc:date>
    <item>
      <title>Cannot merge two contacts using custom code in workflow</title>
      <link>https://community.hubspot.com/t5/Data-Hub/Cannot-merge-two-contacts-using-custom-code-in-workflow/m-p/1140363#M3013</link>
      <description>&lt;P&gt;I am attempting to use the custom code workflow capabilities in Operation Hub to merge two contacts if they match on the mobilephone (internal name) property. This is very similar to the use case provided by Hubspot staff here&amp;nbsp;&lt;A href="https://github.com/HubSpot/sample-workflow-custom-code/blob/main/samples/dedupe_contact.js" target="_blank" rel="noopener"&gt;sample-workflow-custom-code/samples/dedupe_contact.js at main · HubSpot/sample-workflow-custom-code · GitHub&lt;/A&gt;&lt;BR /&gt;&lt;BR /&gt;However, that code does nothing anymore when run and gives linting tips that mergeResults is defined but never used, and uses the now deprecated v1 APIs.&lt;BR /&gt;&lt;BR /&gt;I've tried rewriting it to use the v3 merge API and the log does show that the workflow successfully found a matching contact ID with the same mobilephone number as the enrolled contact's, and it says it successfully sent the merge request to the merge API for those two IDs. But they are not merged. Any idea why? Here's the current node.js code:&lt;/P&gt;&lt;LI-SPOILER&gt;&lt;P&gt;/**&lt;BR /&gt;* HubSpot Workflow Custom Code: Merge contacts by matching mobilephone&lt;BR /&gt;*&lt;BR /&gt;* Logic:&lt;BR /&gt;* - If NO other contact matches → do nothing&lt;BR /&gt;* - If EXACTLY 1 other contact matches → MERGE enrolled contact into that contact&lt;BR /&gt;* - If 2+ other contacts match → skip merge (ambiguous)&lt;BR /&gt;*/&lt;/P&gt;&lt;P&gt;const hubspot = require('@hubspot/api-client');&lt;BR /&gt;const DEDUPE_PROPERTY = 'mobilephone';&lt;/P&gt;&lt;P&gt;exports.main = async (event, callback) =&amp;gt; {&lt;BR /&gt;const hubspotClient = new hubspot.Client({&lt;BR /&gt;accessToken: process.env.[SECRET]&lt;BR /&gt;});&lt;/P&gt;&lt;P&gt;try {&lt;BR /&gt;const enrolledId = event.object.objectId;&lt;BR /&gt;const enrolledIdStr = String(enrolledId);&lt;/P&gt;&lt;P&gt;// 1) Fetch enrolled contact's mobilephone&lt;BR /&gt;const contact = await hubspotClient.crm.contacts.basicApi.getById(&lt;BR /&gt;enrolledId,&lt;BR /&gt;[DEDUPE_PROPERTY]&lt;BR /&gt;);&lt;/P&gt;&lt;P&gt;const phoneValue = contact.properties?.[DEDUPE_PROPERTY];&lt;/P&gt;&lt;P&gt;if (!phoneValue) {&lt;BR /&gt;console.log('No mobilephone on enrolled contact; nothing to merge.');&lt;BR /&gt;return callback(null, { status: 'no_mobilephone' });&lt;BR /&gt;}&lt;/P&gt;&lt;P&gt;console.log(`Searching for contacts with ${DEDUPE_PROPERTY} = ${phoneValue}`);&lt;/P&gt;&lt;P&gt;// 2) Search for contacts with matching mobilephone&lt;BR /&gt;const search = await hubspotClient.crm.contacts.searchApi.doSearch({&lt;BR /&gt;filterGroups: [{&lt;BR /&gt;filters: [{&lt;BR /&gt;propertyName: DEDUPE_PROPERTY,&lt;BR /&gt;operator: 'EQ',&lt;BR /&gt;value: phoneValue&lt;BR /&gt;}]&lt;BR /&gt;}],&lt;BR /&gt;limit: 10&lt;BR /&gt;});&lt;/P&gt;&lt;P&gt;const matchingIds = (search.results || [])&lt;BR /&gt;.map(c =&amp;gt; c.id)&lt;BR /&gt;.filter(id =&amp;gt; String(id) !== enrolledIdStr);&lt;/P&gt;&lt;P&gt;console.log(`Found ${matchingIds.length} other contacts with same mobilephone.`);&lt;/P&gt;&lt;P&gt;// --- Merge Logic ---&lt;BR /&gt;if (matchingIds.length === 0) {&lt;BR /&gt;console.log('No duplicates found. Nothing to merge.');&lt;BR /&gt;return callback(null, { status: 'no_duplicates' });&lt;BR /&gt;}&lt;/P&gt;&lt;P&gt;if (matchingIds.length &amp;gt;= 2) {&lt;BR /&gt;console.log('Ambiguous: 2 or more other contacts found. No merge performed.');&lt;BR /&gt;return callback(null, { status: 'ambiguous_duplicates' });&lt;BR /&gt;}&lt;/P&gt;&lt;P&gt;// 3) Exactly 1 match → perform merge using direct API call&lt;BR /&gt;const primaryId = matchingIds[0];&lt;BR /&gt;console.log(`Merging enrolled contact (${enrolledId}) INTO contact (${primaryId})`);&lt;/P&gt;&lt;P&gt;try {&lt;BR /&gt;await hubspotClient.apiRequest({&lt;BR /&gt;method: 'POST',&lt;BR /&gt;path: '/crm/v3/objects/contacts/merge',&lt;BR /&gt;body: {&lt;BR /&gt;primaryObjectId: primaryId,&lt;BR /&gt;secondaryObjectId: enrolledId&lt;BR /&gt;}&lt;BR /&gt;});&lt;/P&gt;&lt;P&gt;console.log('&lt;span class="lia-unicode-emoji" title=":white_heavy_check_mark:"&gt;✅&lt;/span&gt; Merge request sent successfully (HubSpot may return 204 No Content).');&lt;BR /&gt;return callback(null, { status: 'merged', merged_into: primaryId });&lt;/P&gt;&lt;P&gt;} catch (mergeErr) {&lt;BR /&gt;console.error('&lt;span class="lia-unicode-emoji" title=":cross_mark:"&gt;❌&lt;/span&gt; Merge API failed:', mergeErr.response?.body || mergeErr);&lt;BR /&gt;return callback(mergeErr);&lt;BR /&gt;}&lt;/P&gt;&lt;P&gt;} catch (err) {&lt;BR /&gt;console.error('&lt;span class="lia-unicode-emoji" title=":cross_mark:"&gt;❌&lt;/span&gt; General error during merge process:', err);&lt;BR /&gt;return callback(err);&lt;BR /&gt;}&lt;BR /&gt;};&lt;/P&gt;&lt;/LI-SPOILER&gt;&lt;P&gt;&lt;BR /&gt;And here's the latest log:&lt;/P&gt;&lt;LI-SPOILER&gt;&lt;P class=""&gt;Logs&lt;/P&gt;&lt;DIV class=""&gt;&lt;DIV class=""&gt;&lt;DIV&gt;2025-04-24T16:21:28.815Z INFO Searching for contacts with mobilephone = [hidden] 2025-04-24T16:21:29.135Z INFO Found 1 other contacts with same mobilephone. 2025-04-24T16:21:29.136Z INFO Merging enrolled contact (12479851) INTO contact (44946951) 2025-04-24T16:21:29.258Z INFO &lt;span class="lia-unicode-emoji" title=":white_heavy_check_mark:"&gt;✅&lt;/span&gt; Merge request sent successfully (HubSpot may return 204 No Content).&lt;/DIV&gt;&lt;/DIV&gt;&lt;/DIV&gt;&lt;/LI-SPOILER&gt;&lt;P&gt;&lt;BR /&gt;&lt;BR /&gt;&lt;/P&gt;</description>
      <pubDate>Thu, 24 Apr 2025 16:37:58 GMT</pubDate>
      <guid>https://community.hubspot.com/t5/Data-Hub/Cannot-merge-two-contacts-using-custom-code-in-workflow/m-p/1140363#M3013</guid>
      <dc:creator>customtruck</dc:creator>
      <dc:date>2025-04-24T16:37:58Z</dc:date>
    </item>
    <item>
      <title>Re: Cannot merge two contacts using custom code in workflow</title>
      <link>https://community.hubspot.com/t5/Data-Hub/Cannot-merge-two-contacts-using-custom-code-in-workflow/m-p/1140406#M3014</link>
      <description>&lt;P&gt;Hi&amp;nbsp;&lt;a href="https://community.hubspot.com/t5/user/viewprofilepage/user-id/105703"&gt;@customtruck&lt;/a&gt;&amp;nbsp;&lt;BR /&gt;&lt;BR /&gt;This might help you&lt;BR /&gt;• Use the &lt;STRONG&gt;POST /crm/v3/objects/contacts/merge&lt;/STRONG&gt; endpoint (not the old “merge-two” v1 URL). Body must be: { "primaryObjectId": "123", "objectIdToMerge": "456" }—nothing else, no JSON array.&lt;BR /&gt;• Your private-app token needs &lt;STRONG&gt;crm.objects.contacts.write&lt;/STRONG&gt; plus &lt;STRONG&gt;crm.objects.contacts.read&lt;/STRONG&gt;; without write, HubSpot returns 200 in custom-code but silently drops the merge.&lt;BR /&gt;• v3 runs the merge &lt;STRONG&gt;async&lt;/STRONG&gt;, so the 200 you log only means “request accepted.” It can take a few seconds—add a short delay or a polling step if you need to confirm inside the same workflow run.&lt;BR /&gt;• If you’re matching on mobilephone, be sure both records have an identical value in that exact internal property; HubSpot won’t merge on a partial match or on other phone fields.&lt;BR /&gt;&lt;BR /&gt;• Custom-code boilerplate that works:&lt;BR /&gt;&lt;BR /&gt;&lt;/P&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;LI-CODE lang="javascript"&gt;const hubspot = require('@hubspot/api-client');
exports.main = async (event, cb) =&amp;gt; {
  const hs = new hubspot.Client({ accessToken: process.env.HUBSPOT_API_KEY });
  const primaryId = event.inputFields['hs_object_id'];        // enrolled contact
  const dupId     = event.inputFields['duplicate_id'];        // fetched via earlier search
  try {
    await hs.apiRequest({
      method: 'POST',
      path: '/crm/v3/objects/contacts/merge',
      body: { primaryObjectId: primaryId, objectIdToMerge: dupId }
    });
    cb({ outputFields: { merge_status: 'queued' }});
  } catch (e) {
    cb({ outputFields: { merge_status: `error: ${e.message}` }});
  }
};&lt;/LI-CODE&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;P&gt;(Replace duplicate_id with whatever search step you’re using.)&lt;BR /&gt;&lt;BR /&gt;Once you have the right scopes and exact JSON body, contacts will merge every time—log shows 200, a few seconds later the duplicate VID disappears.&lt;BR /&gt;&lt;BR /&gt;Hope it helps.&lt;BR /&gt;&lt;BR /&gt;&lt;/P&gt;&lt;P&gt;&lt;span class="lia-inline-image-display-wrapper lia-image-align-left" image-alt="RubenB_0-1745515849609.png" style="width: 200px;"&gt;&lt;img src="https://community.hubspot.com/t5/image/serverpage/image-id/144303iC686A98190142628/image-size/small?v=v2&amp;amp;px=200" role="button" title="RubenB_0-1745515849609.png" alt="RubenB_0-1745515849609.png" /&gt;&lt;/span&gt;&lt;/P&gt;&lt;P&gt;&lt;STRONG&gt;&lt;A href="https://www.linkedin.com/in/ruben-burdin/" target="_blank" rel="noopener nofollow noreferrer"&gt;Ruben Burdin&lt;/A&gt;&amp;nbsp;&lt;/STRONG&gt;&lt;/P&gt;&lt;P&gt;&lt;STRONG&gt;Real-Time Data Sync Between any CRM or Database | Founder @&lt;A href="https://l.stacksync.com/hubspot" target="_blank" rel="nofollow noopener noreferrer"&gt;Stacksync&lt;/A&gt;&lt;SPAN&gt;&amp;nbsp;&lt;/SPAN&gt;(YC W24)&amp;nbsp;&lt;/STRONG&gt;&lt;/P&gt;</description>
      <pubDate>Thu, 24 Apr 2025 17:31:59 GMT</pubDate>
      <guid>https://community.hubspot.com/t5/Data-Hub/Cannot-merge-two-contacts-using-custom-code-in-workflow/m-p/1140406#M3014</guid>
      <dc:creator>RubenBurdin</dc:creator>
      <dc:date>2025-04-24T17:31:59Z</dc:date>
    </item>
    <item>
      <title>Re: Cannot merge two contacts using custom code in workflow</title>
      <link>https://community.hubspot.com/t5/Data-Hub/Cannot-merge-two-contacts-using-custom-code-in-workflow/m-p/1140978#M3015</link>
      <description>&lt;P&gt;Wow, I've been beating my head against this wall for hours and all it came down to was using&amp;nbsp;"objectIdToMerge" instead of "secondaryObjectId", as you suggested. I am so relieved to finally have this working -- thank you so much for your timely assistance!&lt;/P&gt;</description>
      <pubDate>Fri, 25 Apr 2025 17:15:42 GMT</pubDate>
      <guid>https://community.hubspot.com/t5/Data-Hub/Cannot-merge-two-contacts-using-custom-code-in-workflow/m-p/1140978#M3015</guid>
      <dc:creator>customtruck</dc:creator>
      <dc:date>2025-04-25T17:15:42Z</dc:date>
    </item>
  </channel>
</rss>

