Import WhatsApp Contacts From Hubspot Using The API

August 23, 2024

In this tutorial, you can import and synchronize contacts from Hubspot to Wassenger using their respective APIs.

🤩 🤖 Wassenger is a complete API solution for WhatsApp. Sign up for a 7-day free trial and get started in minutes!

This integration allows you to automatically import and synchronize all your Hubspot contacts in Wassenger, so you can later browse and search contacts by name, email or phone number, and easily start new chats and send messages in WhatsApp from the Wassenger multi-agent web chat.

This process only synchronizes contacts from Hubspot into Wassenger, not the other way around. If you update contact information in Wassenger, these changes will not be reflected in Hubspot. Optionally, you can synchronize Wassenger with Hubspot using the API + Webhooks, however this task is beyond the purpose of this tutorial.

Prerequisites

  • Hubspot account with API access.
  • Wassenger account: get your API key here
  • Familiarity with the programming language of your choice for connecting the APIs.

Introduction

This tutorial provides a ready-to-use code program that you can download and run in the cloud using Replit.com or on your computer.

This program is in different programming languages: JavaScript/Node.js, PHP, Python, C#, Kotlin, Go and Ruby. Pick the one that you know best.

Configuration

To properly run the program, you can define your Wassenger API key and your Hubspot Private App API key.

Hubspot API key

You can obtain the Hubspot API key by creating a Private App with read access to Contacts entity.

In your Hubspot action, go to Settings > Integrations > Private apps > Click on Create private app

Learn how to create a Hubspot Private App and obtain the API key here.

Once you have the Hubspot API key, define it in the code: HUBSPOT_API_KEY

Wassenger API key

Obtain your Wassenger API key from here and define it in the code: API_KEY

🤩 🤖 Wassenger is a complete communication platform and API solution for WhatsApp. Explore more than 100+ API use cases and automate anything on WhatsApp by signing up for a free trial and getting started in minutes!

How it works

Find below an explanation of what the program does.

Fetch Hubspot contacts

Make a GET request to Hubspot’s Contacts API endpoint: [https://api.hubapi.com/crm/v3/objects/contacts](https://api.hubapi.com/crm/v3/objects/contacts)

Include the Hubspot API key in the Authorization header and specify the contact fields you want to retrieve as query parameters.

Filter and map Hubspot contacts

Filter the contacts to include only those with a phone number, mobile phone number, or WhatsApp’s phone number. Map the Hubspot contact data to the appropriate Wassenger contact fields, including additional fields like crmRef, altPhone, languages, postalCode, city, address, companyName, and companyWebsite.

Fetch an active WhatsApp number from Wassenger

Make a GET request to Wassenger’s Devices API endpoint: https://api.wassenger.com/v1/devices?status=operative

Include the Wassenger API key in the Authorization header. Select the appropriate WhatsApp number based on your preferences.

Verify the Wassenger subscription plan

Ensure that the selected WhatsApp number has the contacts API access feature enabled. If not, upgrade the plan accordingly.

Create contacts in Wassenger

Make a PATCH request to Wassenger’s Contacts API endpoint: [https://api.wassenger.com/v1/chat/{device_id}/contacts](https://api.wassenger.com/v1/chat/%7Bdevice_id%7D/contacts)

Include the Wassenger API key in the Authorization header and the mapped contact data in the request body.

Handle the response to check for successfully created contacts or invalid contacts.

Note existing contacts in your Wassenger updated with the latest Hubspot information, instead of returning an error.

This can be particularly useful when you want to sync the contact information between Hubspot and Wassenger.

Handle errors and log the results

Implement error handling for failed API requests or unexpected responses. Log the results of each contact creation, including the total number of contacts created, duplicates, and invalid contacts.

🤩 🤖 Wassenger is a complete communication platform and API solution for WhatsApp. Explore more than 100+ API use cases and automate anything on WhatsApp by signing up for a free trial and getting started in minutes!

Run the program

Find below the ready-to-use program that you can download and run in the cloud using Replit.com or on your computer.

Pick the programming language that works best for you 😉

Node.js

const axios = require('axios');
// Enter Hubspot Private app API key here
// Requires Contacts read permissions
// More information: https://developers.hubspot.com/docs/api/private-apps
const HUBSPOT_API_KEY = '';
// Enter your Wassenger API key here
// Obtain it here: https://app.wassenger.com/apikeys
const API_KEY = 'API_KEY_GOES_HERE';
// Optionally, enter the WhatsApp number ID here(24 characters hexadecimal)
// If not specified, the first active WhatsApp number will be used
const WHATSAPP_NUMBER_ID = '';
const API_URL = 'https://api.wassenger.com';
const MAX_CONTACTS = 5000;
const contactFields = [
  'email',
  'name',
  'lastname',
  'phone',
  'mobilephone',
  'hs_whatsapp_phone_number',
  'zip',
  'company',
  'website',
  'address',
  'city',
  'hs_language'
];
const mapContactInfo = contact => {
  const data = {
    crmRef: `hubspot: ${contact.id}`
  };
  if (contact.email && contact.email.length > 5 && contact.email.length < 50) {
    data.email = contact.email;
  }
  if (contact.whatsapp) {
    data.phone = contact.whatsapp.slice(0, 18);
    if (contact.mobilephone) {
      data.altPhone = contact.mobilephone.slice(0, 18);
    } else if (contact.phone) {
      data.altPhone = contact.phone.slice(0, 18);
    }
  } else if (contact.mobilephone) {
    data.phone = contact.mobilephone.slice(0, 18);
    if (contact.phone) {
      data.altPhone = contact.phone.slice(0, 18);
    }
  } else if (contact.phone) {
    data.phone = contact.phone.slice(0, 18);
  }
  if (contact.language) {
    data.languages = [contact.language.slice(0, 2)];
  }
  if (contact.postalcode) {
    data.postalCode = contact.postalcode.slice(0, 20);
  }
  if (contact.city) {
    data.city = contact.city.slice(0, 30);
  }
  if (contact.address) {
    data.address = contact.address.slice(0, 100);
  }
  if (contact.company) {
    data.companyName = contact.company.slice(0, 50);
  }
  if (contact.website && contact.website.length > 5) {
    data.companyWebsite = contact.website.slice(0, 100);
  }
  return data;
};
const getHubSpotContacts = async () => {
  let after = null;
  const contacts = [];
  while (true) {
    try {
      console.log(
        ' == > Fetching HubSpot contacts...',
        contacts.length,
        '/',
        MAX_CONTACTS
      );
      const response = await axios.get(
        'https://api.hubapi.com/crm/v3/objects/contacts',
        {
          params: {
            limit: 100,
            after: after,
            properties: contactFields.join(', ')
          },
          headers: {
            Authorization: `Bearer ${HUBSPOT_API_KEY}`,
            'Content-Type': 'application/json'
          }
        }
      );
      const entries = response.data.results
        .map(contact => {
          return {
            id: contact.id,
            email: contact.properties.email,
            name: contact.properties.firstname,
            surname: contact.properties.lastname,
            phone: contact.properties.phone,
            mobilephone: contact.properties.mobilephone,
            whatsapp: contact.properties.hs_whatsapp_phone_number,
            postalcode: contact.properties.zip,
            company: contact.properties.company,
            website: contact.properties.website,
            address: contact.properties.address,
            city: contact.properties.city,
            language: contact.properties.hs_language
          };
        })
        .filter(
          contact => contact.phone || contact.mobilephone || contact.whatsapp
        )
        .map(mapContactInfo);
      if (entries.length) {
        contacts.push(...entries);
      }
      if (contacts.length >= MAX_CONTACTS) {
        break;
      }
      if (response.data.paging && response.data.paging.next) {
        after = response.data.paging.next.after;
      } else {
        break;
      }
      await new Promise(resolve => setTimeout(resolve, 1500));
    } catch (err) {
      throw new Error(`Failed to fetch HubSpot contacts: ${err.message}`);
    }
  }
  return contacts;
};
const createContacts = async (device, contacts) => {
  console.log(' == > Creating contacts in bulk mode:', contacts.length);
  try {
    const { status, data: results } = await axios.patch(
      `${API_URL}/v1/chat/${device.id}/contacts`,
      contacts,
      {
        headers: {
          'Content-Type': 'application/json',
          Authorization: API_KEY
        }
      }
    );
    console.log(
      ' == > Total contacts created:',
      results.filter(x => x.id).length
    );
    if (status === 202) {
      console.log(
        ' == > Total duplicate or invalid contacts:',
        results.filter(x => x.error).length
      );
    }
    for (const result of results) {
      if (result.error) {
        console.log(
          ' == > Contact already exists:',
          result.contact.phone,
          `https://app.wassenger.com/contacts/${device.id}/${result.contact.phone.slice(1)}`
        );
      } else {
        console.log(
          ' == > Contact created:',
          result.phone,
          `https://app.wassenger.com/contacts/${device.id}/${result.phone.slice(1)}`
        );
      }
    }
  } catch (error) {
    console.error('[error] failed to create contacts:', error.message);
  }
};
const getWhatsAppDevice = async () => {
  const { data } = await axios.get(`${API_URL}/v1/devices?status=operative`, {
    params: { size: 50 },
    headers: {
      Authorization: API_KEY
    }
  });
  if (!data.length) {
    throw new Error(
      'No active WhatsApp numbers connected in Wassenger.Connect a number here: https://app.wassenger.com/create'
    );
  }
  if (WHATSAPP_NUMBER_ID) {
    return data.find(device => device.id === WHATSAPP_NUMBER_ID);
  }
  return data[0];
};
const importContacts = async () => {
  if (!API_KEY) {
    throw new Error(
      'Missing required Wassenger API key.Sign up for free and obtain it here: https://app.wassenger.com/apikeys'
    );
  }
  const device = await getWhatsAppDevice();
  if (!device) {
    throw new Error(
      'No active WhatsApp numbers connected in Wassenger.Connect a number here: https://app.wassenger.com/create'
    );
  }
  if (device.billing.subscription.product !== 'io') {
    throw new Error(
      `The selected WhatsApp number has no contacts API access feature enabled.Please upgrade plan here: https://app.wassenger.com/${device.id}/plan`
    );
  }
  const hubspotContacts = await getHubSpotContacts();
  if (!hubspotContacts) {
    return console.error(
      '[error] Failed to obtain contacts from Hubspot: please make sure the Hubspot API key is valid and has read access to contacts in the Settings > Integrations > Private application > Edit application'
    );
  }
  for (let i = 0; i < hubspotContacts.length; i += 100) {
    await createContacts(device, hubspotContacts.slice(i, i + 100));
  }
};
importContacts().catch(err =>
  console.error('Failed to import contacts:', err.message)
);

Python

import os
import requests
import time
# Enter Hubspot Private app API key here
# Requires Contacts read permissions
# More information: https://developers.hubspot.com/docs/api/private-apps
HUBSPOT_API_KEY = ''
# Enter your Wassenger API key here
# Obtain it here: https://app.wassenger.com/apikeys
API_KEY = 'API_KEY_GOES_HERE'
# Optionally, enter the WhatsApp number ID here(24 characters hexadecimal)
# If not specified, the first active WhatsApp number will be used
WHATSAPP_NUMBER_ID = ''
API_URL = 'https://api.wassenger.com'
MAX_CONTACTS = 3000
contact_fields = [
'email', 
'name', 
'lastname', 
'phone', 
'mobilephone', 
'hs_whatsapp_phone_number', 
'zip', 
'company', 
'website', 
'address', 
'city', 
'hs_language'
]
def map_contact_info(contact):
data = {
'crmRef': f"hubspot: {contact['id']}"
}
if contact['email'] and len(contact['email']) > 5 and len(contact['email']) < 50:
data['email'] = contact['email']
if contact['whatsapp']:
data['phone'] = contact['whatsapp']
if contact['mobilephone']:
data['altPhone'] = contact['mobilephone']
elif contact['phone']:
data['altPhone'] = contact['phone']
elif contact['mobilephone']:
data['phone'] = contact['mobilephone']
if contact['phone']:
data['altPhone'] = contact['phone']
elif contact['phone']:
data['phone'] = contact['phone']
if contact['language']:
data['languages'] = [contact['language'][:2]]
if contact['postalcode']:
data['postalCode'] = contact['postalcode'][:20]
if contact['city']:
data['city'] = contact['city'][:30]
if contact['address']:
data['address'] = contact['address'][:100]
if contact['company']:
data['companyName'] = contact['company'][:50]
if contact['website'] and len(contact['website']) > 5:
data['companyWebsite'] = contact['website'][:100]
return data
def get_hubspot_contacts():
after = None
contacts = []
while True:
try:
print(f" == > Fetching HubSpot contacts...{len(contacts)} / {MAX_CONTACTS}")
response = requests.get(
'https://api.hubapi.com/crm/v3/objects/contacts', 
params={
'limit': 100, 
'after': after, 
'properties': ', '.join(contact_fields)
}, 
headers={
'Authorization': f"Bearer {HUBSPOT_API_KEY}", 
'Content-Type': 'application/json'
}
)
response_data = response.json()
entries = [
{
'id': contact['id'], 
'email': contact['properties']['email'], 
'name': contact['properties']['firstname'], 
'surname': contact['properties']['lastname'], 
'phone': contact['properties']['phone'], 
'mobilephone': contact['properties']['mobilephone'], 
'whatsapp': contact['properties']['hs_whatsapp_phone_number'], 
'postalcode': contact['properties']['zip'], 
'company': contact['properties']['company'], 
'website': contact['properties']['website'], 
'address': contact['properties']['address'], 
'city': contact['properties']['city'], 
'language': contact['properties']['hs_language']
}
for contact in response_data['results']
]
entries = list(filter(lambda c: c['phone'] or c['mobilephone'] or c['whatsapp'], entries))
entries = list(map(map_contact_info, entries))
if entries:
contacts.extend(entries)
if len(contacts) >= MAX_CONTACTS:
break
if 'paging' in response_data and 'next' in response_data['paging']:
after = response_data['paging']['next']['after']
else:
break
time.sleep(1.5)
except Exception as err:
raise Exception(f"Failed to fetch HubSpot contacts: {err}")
return contacts
def create_contacts(device, contacts):
print(f" == > Creating contacts in bulk mode: {len(contacts)}")
try:
response = requests.patch(
f"{API_URL}/v1/chat/{device['id']}/contacts", 
json=contacts, 
headers={
'Content-Type': 'application/json', 
'Authorization': API_KEY
}
)
if response.status_code == 202:
results = response.json()
print(f" == > Total contacts created: {len(list(filter(lambda x: 'id' in x, results)))}")
print(f" == > Total duplicate or invalid contacts: {len(list(filter(lambda x: 'error' in x, results)))}")
for result in results:
if 'error' in result:
print(f" == > Contact already exists: {result['contact']['phone']} https://app.wassenger.com/contacts/{device['id']}/{result['contact']['phone'][1:]}")
else:
print(f" == > Contact created: {result['phone']} https://app.wassenger.com/contacts/{device['id']}/{result['phone'][1:]}")
else:
print(f"[error] failed to create contacts: {response.text}")
except Exception as error:
print(f"[error] failed to create contacts: {error}")
def get_whatsapp_device():
response = requests.get(f"{API_URL}/v1/devices?status=operative", 
params={'size': 50}, 
headers={'Authorization': API_KEY})
data = response.json()
if not data:
raise Exception("No active WhatsApp numbers connected in Wassenger.Connect a number here: https://app.wassenger.com/create")
if WHATSAPP_NUMBER_ID:
return next((device for device in data if device['id'] == WHATSAPP_NUMBER_ID), None)
return data[0]
def import_contacts():
if not API_KEY:
raise Exception("Missing required Wassenger API key.Sign up for free and obtain it here: https://app.wassenger.com/apikeys")
device = get_whatsapp_device()
if not device:
raise Exception("No active WhatsApp numbers connected in Wassenger.Connect a number here: https://app.wassenger.com/create")
if device['billing']['subscription']['product'] != 'io':
raise Exception("The selected WhatsApp number has no contacts API access feature enabled.Please upgrade plan here: https://app.wassenger.com/{device['id']}/plan")
hubspot_contacts = get_hubspot_contacts()
if not hubspot_contacts:
print("[error] Failed to obtain contacts from Hubspot: please make sure the Hubspot API key is valid and has read access to contacts in the Settings > Integrations > Private application > Edit application")
return
for i in range(0, len(hubspot_contacts), 100):
create_contacts(device, hubspot_contacts[i:i + 100])
if __name__ == "__main__":
try:
import_contacts()
except Exception as err:
print(f"Failed to import contacts: {err}")

🤩 🤖 Wassenger is a complete communication platform and API solution for WhatsApp. Explore more than 100+ API use cases and automate anything on WhatsApp by signing up for a free trial and getting started in minutes!

PHP

<?php
// NOTE: requires pecl_http extension: pecl install pecl_http
// More information: https://pecl.php.net/package/pecl_http
require_once 'vendor/autoload.php';
use http\Client;
use http\Client\Request;
// Enter Hubspot Private app API key here
// Requires Contacts read permissions
// More information: https://developers.hubspot.com/docs/api/private-apps
const HUBSPOT_API_KEY = '';
// Enter your Wassenger API key here
// Obtain it here: https://app.wassenger.com/apikeys
const API_KEY = 'API_KEY_GOES_HERE';
// Optionally, enter the WhatsApp number ID here(24 characters hexadecimal)
// If not specified, the first active WhatsApp number will be used
const WHATSAPP_NUMBER_ID = '';
const MAX_CONTACTS = 3000;
const API_URL = 'https://api.wassenger.com';
$contactFields = [
  'email',
  'name',
  'lastname',
  'phone',
  'mobilephone',
  'hs_whatsapp_phone_number',
  'zip',
  'company',
  'website',
  'address',
  'city',
  'hs_language',
];
function mapContactInfo($contact)
{
  $data = [
    'crmRef' => "hubspot: {$contact['id']}",
  ];
  if (
    !empty($contact['email']) &&
    strlen($contact['email']) > 5 &&
    strlen($contact['email']) < 50
  ) {
    $data['email'] = $contact['email'];
  }
  if (!empty($contact['whatsapp'])) {
    $data['phone'] = $contact['whatsapp'];
    if (!empty($contact['mobilephone'])) {
      $data['altPhone'] = $contact['mobilephone'];
    } elseif (!empty($contact['phone'])) {
      $data['altPhone'] = $contact['phone'];
    }
  } elseif (!empty($contact['mobilephone'])) {
    $data['phone'] = $contact['mobilephone'];
    if (!empty($contact['phone'])) {
      $data['altPhone'] = $contact['phone'];
    }
  } elseif (!empty($contact['phone'])) {
    $data['phone'] = $contact['phone'];
  }
  if (!empty($contact['language'])) {
    $data['languages'] = [substr($contact['language'], 0, 2)];
  }
  if (!empty($contact['postalcode'])) {
    $data['postalCode'] = substr($contact['postalcode'], 0, 20);
  }
  if (!empty($contact['city'])) {
    $data['city'] = substr($contact['city'], 0, 30);
  }
  if (!empty($contact['address'])) {
    $data['address'] = substr($contact['address'], 0, 100);
  }
  if (!empty($contact['company'])) {
    $data['companyName'] = substr($contact['company'], 0, 50);
  }
  if (!empty($contact['website']) && strlen($contact['website']) > 5) {
    $data['companyWebsite'] = substr($contact['website'], 0, 100);
  }
  return $data;
}
function getHubSpotContacts()
{
  global $contactFields;
  $after = null;
  $contacts = [];
  while (true) {
    try {
      echo ' == > Fetching HubSpot contacts...',
        count($contacts),
        '/',
        MAX_CONTACTS,
        PHP_EOL;
      $httpClient = new Client();
      $request = new Request(
        'GET',
        'https://api.hubapi.com/crm/v3/objects/contacts'
      );
      $request->setQuery([
        'limit' => 100,
        'after' => $after,
        'properties' => implode(', ', $contactFields),
      ]);
      $request->setHeaders([
        'Authorization' => 'Bearer ' . HUBSPOT_API_KEY,
        'Content-Type' => 'application/json',
      ]);
      $response = $httpClient
        ->enqueue($request)
        ->send()
        ->wait()
        ->getResponse($request);
      $data = json_decode($response->getBody(), true);
      $entries = array_map(function ($contact) {
        return [
          'id' => $contact['id'],
          'email' => $contact['properties']['email'],
          'name' => $contact['properties']['firstname'],
          'surname' => $contact['properties']['lastname'],
          'phone' => $contact['properties']['phone'],
          'mobilephone' => $contact['properties']['mobilephone'],
          'whatsapp' => $contact['properties']['hs_whatsapp_phone_number'],
          'postalcode' => $contact['properties']['zip'],
          'company' => $contact['properties']['company'],
          'website' => $contact['properties']['website'],
          'address' => $contact['properties']['address'],
          'city' => $contact['properties']['city'],
          'language' => $contact['properties']['hs_language'],
        ];
      }, $data['results']);
      $entries = array_filter($entries, function ($contact) {
        return !empty($contact['phone']) ||
          !empty($contact['mobilephone']) ||
          !empty($contact['whatsapp']);
      });
      $entries = array_map('mapContactInfo', $entries);
      if (count($entries) > 0) {
        $contacts = array_merge($contacts, $entries);
      }
      if (count($contacts) >= MAX_CONTACTS) {
        break;
      }
      if (!empty($data['paging']) && !empty($data['paging']['next'])) {
        $after = $data['paging']['next']['after'];
      } else {
        break;
      }
      usleep(1500000);
    } catch (Exception $err) {
      throw new Exception(
        'Failed to fetch HubSpot contacts: ' . $err->getMessage()
      );
    }
  }
  return $contacts;
}
function createContacts($device, $contacts)
{
  echo ' == > Creating contacts in bulk mode: ' . count($contacts) . PHP_EOL;
  try {
    $httpClient = new HttpClient();
    $request = new HttpRequest();
    $request->setMethod(HttpRequest::METH_PATCH);
    $request->setUrl(API_URL . "/v1/chat/{$device['id']}/contacts");
    $request->setBody(json_encode($contacts));
    $request->setHeaders([
      'Content-Type' => 'application/json',
      'Authorization' => API_KEY,
    ]);
    $response = $httpClient
      ->enqueue($request)
      ->send()
      ->wait()
      ->getResponse($request);
    $results = json_decode($response->getBody(), true);
    $status = $response->getResponseCode();
    echo ' == > Total contacts created: ' .
      count(
        array_filter($results, function ($x) {
          return !empty($x['id']);
        })
      ) .
      PHP_EOL;
    if ($status === 202) {
      echo ' == > Total duplicate or invalid contacts: ' .
        count(
          array_filter($results, function ($x) {
            return !empty($x['error']);
          })
        ) .
        PHP_EOL;
    }
    foreach ($results as $result) {
      if (!empty($result['error'])) {
        echo ' == > Contact already exists: ' .
          $result['contact']['phone'] .
          " https://app.wassenger.com/contacts/{$device['id']}/" .
          substr($result['contact']['phone'], 1) .
          PHP_EOL;
      } else {
        echo ' == > Contact created: ' .
          $result['phone'] .
          " https://app.wassenger.com/contacts/{$device['id']}/" .
          substr($result['phone'], 1) .
          PHP_EOL;
      }
    }
  } catch (Exception $error) {
    echo '[error] failed to create contacts: ' . $error->getMessage() . PHP_EOL;
  }
}
function getWhatsAppDevice()
{
  $httpClient = new HttpClient();
  $request = new HttpRequest();
  $request->setMethod(HttpRequest::METH_GET);
  $request->setUrl(API_URL . '/v1/devices');
  $request->setQuery(['status' => 'operative', 'size' => 50]);
  $request->setHeaders([
    'Authorization' => API_KEY,
  ]);
  $response = $httpClient
    ->enqueue($request)
    ->send()
    ->wait()
    ->getResponse($request);
  $data = json_decode($response->getBody(), true);
  if (empty($data)) {
    throw new Exception(
      'No active WhatsApp numbers connected in Wassenger.Connect a number here: https://app.wassenger.com/create'
    );
  }
  if (WHATSAPP_NUMBER_ID) {
    return array_values(
      array_filter($data, function ($device) {
        return $device['id'] === WHATSAPP_NUMBER_ID;
      })
    )[0] ?? null;
  }
  return $data[0];
}
function importContacts()
{
  if (!API_KEY) {
    throw new Exception(
      'Missing required Wassenger API key.Sign up for free and obtain it here: https://app.wassenger.com/apikeys'
    );
  }
  $device = getWhatsAppDevice();
  if (!$device) {
    throw new Exception(
      'No active WhatsApp numbers connected in Wassenger.Connect a number here: https://app.wassenger.com/create'
    );
  }
  if ($device['billing']['subscription']['product'] !== 'io') {
    throw new Exception(
      "The selected WhatsApp number has no contacts API access feature enabled.Please upgrade plan here: https://app.wassenger.com/{$device['id']}/plan"
    );
  }
  $hubspotContacts = getHubSpotContacts();
  if (!$hubspotContacts) {
    echo '[error] Failed to obtain contacts from Hubspot: please make sure the Hubspot API key is valid and has read access to contacts in the Settings > Integrations > Private application > Edit application' .
      PHP_EOL;
    return;
  }
  for ($i = 0; $i < count($hubspotContacts); $i += 100) {
    createContacts($device, array_slice($hubspotContacts, $i, $i + 100));
  }
}
try {
  importContacts();
} catch (Exception $err) {
  echo 'Failed to import contacts: ' . $err->getMessage() . PHP_EOL;
}

C#

using Newtonsoft.Json.Linq;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Text;
using System.Threading.Tasks;
class HubspotContactsImporter
{
// Enter Hubspot Private app API key here
// Requires Contacts read permissions
// More information: https://developers.hubspot.com/docs/api/private-apps
private const string HUBSPOT_API_KEY = '';
// Enter your Wassenger API key here
// Obtain it here: https://app.wassenger.com/apikeys
private const string API_KEY = 'API_KEY_GOES_HERE';
// Optionally, enter the WhatsApp number ID here(24 characters hexadecimal)
// If not specified, the first active WhatsApp number will be used
private const string WHATSAPP_NUMBER_ID = '';
private const int MAX_CONTACTS = 3000;
private const string API_URL = "https://api.wassenger.com";
private static readonly string[] ContactFields = {
"email", 
"firstname", 
"lastname", 
"phone", 
"mobilephone", 
"hs_whatsapp_phone_number", 
"zip", 
"company", 
"website", 
"address", 
"city", 
"hs_language"
};
public static async Task Main()
{
try
{
await ImportContacts();
}
catch(Exception ex)
{
Console.Error.WriteLine($"Failed to import contacts: {ex.Message}");
}
}
private static Dictionary<string, object> MapContactInfo(JObject contact)
{
var data = new Dictionary<string, object>
{
["crmRef"] = $"hubspot: {contact["id"]}"
};
if(contact["email"] != null && ((string)contact["email"]).Length > 5 && ((string)contact["email"]).Length < 50)
{
data["email"] = contact["email"];
}
if(contact["whatsapp"] != null)
{
data["phone"] = contact["whatsapp"];
if(contact["mobilephone"] != null)
{
data["altPhone"] = contact["mobilephone"];
}
else if(contact["phone"] != null)
{
data["altPhone"] = contact["phone"];
}
}
else if(contact["mobilephone"] != null)
{
data["phone"] = contact["mobilephone"];
if(contact["phone"] != null)
{
data["altPhone"] = contact["phone"];
}
}
else if(contact["phone"] != null)
{
data["phone"] = contact["phone"];
}
if(contact["language"] != null)
{
data["languages"] = new string[] {((string)contact["language"]).Substring(0, 2) };
}
if(contact["postalcode"] != null)
{
data["postalCode"] =((string)contact["postalcode"]).Substring(0, 20);
}
if(contact["city"] != null)
{
data["city"] =((string)contact["city"]).Substring(0, 30);
}
if(contact["address"] != null)
{
data["address"] =((string)contact["address"]).Substring(0, 100);
}
if(contact["company"] != null)
{
data["companyName"] =((string)contact["company"]).Substring(0, 50);
}
if(contact["website"] != null && ((string)contact["website"]).Length > 5)
{
data["companyWebsite"] =((string)contact["website"]).Substring(0, 100);
}
return data;
}
private static async Task<List<Dictionary<string, object>>> GetHubSpotContacts()
{
string after = null;
var contacts = new List<Dictionary<string, object>>();
while(true)
{
try
{
Console.WriteLine($" == > Fetching HubSpot contacts...{contacts.Count}/{MAX_CONTACTS}");
using var httpClient = new HttpClient();
var request = new HttpRequestMessage(HttpMethod.Get, $"https://api.hubapi.com/crm/v3/objects/contacts?limit=100&after={after}&properties={string.Join(", ", ContactFields)}");
request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", HUBSPOT_API_KEY);
request.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
var response = await httpClient.SendAsync(request);
if(!response.IsSuccessStatusCode)
{
throw new Exception($"Failed to fetch HubSpot contacts: {response.ReasonPhrase}");
}
var content = await response.Content.ReadAsStringAsync();
var data = JObject.Parse(content);
var results = data["results"].Select(contact =>
{
return new JObject
{
["id"] = contact["id"], 
["email"] = contact["properties"]["email"], 
["name"] = contact["properties"]["firstname"], 
["surname"] = contact["properties"]["lastname"], 
["phone"] = contact["properties"]["phone"], 
["mobilephone"] = contact["properties"]["mobilephone"], 
["whatsapp"] = contact["properties"]["hs_whatsapp_phone_number"], 
["postalcode"] = contact["properties"]["zip"], 
["company"] = contact["properties"]["company"], 
["website"] = contact["properties"]["website"], 
["address"] = contact["properties"]["address"], 
["city"] = contact["properties"]["city"], 
["language"] = contact["properties"]["hs_language"]
};
})
.Where(contact => contact["phone"] != null || contact["mobilephone"] != null || contact["whatsapp"] != null)
.Select(MapContactInfo);
if(results.Any())
{
contacts.AddRange(results);
}
if(contacts.Count >= MAX_CONTACTS)
{
break;
}
if(data["paging"] != null && data["paging"]["next"] != null)
{
after =(string)data["paging"]["next"]["after"];
}
else
{
break;
}
await Task.Delay(1500);
}
catch(Exception ex)
{
throw new Exception($"Failed to fetch HubSpot contacts: {ex.Message}");
}
}
return contacts;
}
private static async Task CreateContacts(JObject device, List<JObject> contacts)
{
Console.WriteLine($" == > Creating contacts in bulk mode: {contacts.Count}");
try
{
using var httpClient = new HttpClient();
var request = new HttpRequestMessage(HttpMethod.Patch, $"{API_URL}/v1/chat/{device["id"]}/contacts");
request.Headers.Authorization = new AuthenticationHeaderValue(API_KEY);
request.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
request.Content = new StringContent(JsonConvert.SerializeObject(contacts), Encoding.UTF8, "application/json");
var response = await httpClient.SendAsync(request);
if(!response.IsSuccessStatusCode)
{
Console.WriteLine($"[error] failed to create contacts: {response.ReasonPhrase}");
return;
}
var content = await response.Content.ReadAsStringAsync();
var results = JArray.Parse(content);
Console.WriteLine($" == > Total contacts created: {results.Count(x => x["id"] != null)}");
if((int)response.StatusCode == 202)
{
Console.WriteLine($" == > Total duplicate or invalid contacts: {results.Count(x => x["error"] != null)}");
}
foreach(var result in results)
{
if(result["error"] != null)
{
Console.WriteLine($" == > Contact already exists: {result["contact"]["phone"]} https://app.wassenger.com/contacts/{device["id"]}/{((string)result["contact"]["phone"]).Substring(1)}");
}
else
{
Console.WriteLine($" == > Contact created: {result["phone"]} https://app.wassenger.com/contacts/{device["id"]}/{((string)result["phone"]).Substring(1)}");
}
}
}
catch(Exception ex)
{
Console.WriteLine($"[error] failed to create contacts: {ex.Message}");
}
}
private static async Task ImportContacts()
{
if(string.IsNullOrEmpty(API_KEY))
{
throw new Exception("Missing required Wassenger API key.Sign up for free and obtain it here: https://app.wassenger.com/apikeys");
}
var device = await GetWhatsAppDevice();
if(device == null)
{
throw new Exception("No active WhatsApp numbers connected in Wassenger.Connect a number here: https://app.wassenger.com/create");
}
if((string)device["billing"]["subscription"]["product"] != "io")
{
throw new Exception($"The selected WhatsApp number has no contacts API access feature enabled.Please upgrade plan here: https://app.wassenger.com/{device["id"]}/plan");
}
var hubspotContacts = await GetHubSpotContacts();
if(!hubspotContacts.Any())
{
Console.WriteLine("[error] Failed to obtain contacts from Hubspot: please make sure the Hubspot API key is valid and has read access to contacts in the Settings > Integrations > Private application > Edit application");
return;
}
for(int i = 0; i < hubspotContacts.Count; i += 100)
{
await CreateContacts(device, hubspotContacts.Skip(i).Take(100).ToList());
}
}
public static async Task Main(string[] args)
{
try
{
await ImportContacts();
}
catch(Exception ex)
{
Console.WriteLine($"Failed to import contacts: {ex.Message}");
}
}
}

🤩 🤖 Wassenger is a complete communication platform and API solution for WhatsApp. Explore more than 100+ API use cases and automate anything on WhatsApp by signing up for a free trial and getting started in minutes!

Kotlin

import kotlinx.coroutines.delay
import retrofit2.Retrofit
import retrofit2.converter.gson.GsonConverterFactory
import retrofit2.http.GET
import retrofit2.http.Header
import retrofit2.http.PATCH
import retrofit2.http.Query
data class Contact(
val id: String, 
val email: String?, 
val name: String?, 
val surname: String?, 
val phone: String?, 
val mobilephone: String?, 
val whatsapp: String?, 
val postalcode: String?, 
val company: String?, 
val website: String?, 
val address: String?, 
val city: String?, 
val language: String?
)
data class MappedContact(
val crmRef: String, 
val email: String?, 
val phone: String?, 
val altPhone: String?, 
val languages: List<String>?, 
val postalCode: String?, 
val city: String?, 
val address: String?, 
val companyName: String?, 
val companyWebsite: String?
)
suspend fun main() {
// Enter Hubspot Private app API key here
// Requires Contacts read permissions
// More information: https://developers.hubspot.com/docs/api/private-apps
val HUBSPOT_API_KEY = ''
// Enter your Wassenger API key here
// Obtain it here: https://app.wassenger.com/apikeys
val API_KEY = 'API_KEY_GOES_HERE'
// Optionally, enter the WhatsApp number ID here(24 characters hexadecimal)
// If not specified, the first active WhatsApp number will be used
val WHATSAPP_NUMBER_ID = ''
val MAX_CONTACTS = 3000
val API_URL = "https://api.wassenger.com"
val contactFields = listOf(
"email", 
"name", 
"lastname", 
"phone", 
"mobilephone", 
"hs_whatsapp_phone_number", 
"zip", 
"company", 
"website", 
"address", 
"city", 
"hs_language"
)
val retrofit = Retrofit.Builder()
.baseUrl(API_URL)
.addConverterFactory(GsonConverterFactory.create())
.build()
val api = retrofit.create(Api::class.java)
try {
val device = getWhatsAppDevice(api, API_KEY)
if(device == null) {
throw Exception("No active WhatsApp numbers connected in Wassenger.Connect a number here: https://app.wassenger.com/create")
}
if(device.billing.subscription.product != "io") {
throw Exception("The selected WhatsApp number has no contacts API access feature enabled.Please upgrade plan here: https://app.wassenger.com/${device.id}/plan")
}
val hubspotContacts = getHubSpotContacts(api, HUBSPOT_API_KEY, contactFields, MAX_CONTACTS)
if(hubspotContacts.isEmpty()) {
println("[error] Failed to obtain contacts from Hubspot: please make sure the Hubspot API key is valid and has read access to contacts in the Settings > Integrations > Private application > Edit application")
return
}
for(i in hubspotContacts.indices step 100) {
createContacts(api, API_KEY, device, hubspotContacts.slice(i until(i + 100).coerceAtMost(hubspotContacts.size)))
}
} catch(e: Exception) {
println("Failed to import contacts: ${e.message}")
}
}
suspend fun getHubSpotContacts(api: Api, apiKey: String, contactFields: List<String>, maxContacts: Int): List<MappedContact> {
var after: String? = null
val contacts = mutableListOf<MappedContact>()
while(contacts.size < maxContacts) {
val response = api.getHubSpotContacts(apiKey, 100, after, contactFields.joinToString(", "))
val entries = response.results
.map { contact ->
Contact(
id = contact.id, 
email = contact.properties.email, 
name = contact.properties.firstname, 
surname = contact.properties.lastname, 
phone = contact.properties.phone, 
mobilephone = contact.properties.mobilephone, 
whatsapp = contact.properties.hs_whatsapp_phone_number, 
postalcode = contact.properties.zip, 
company = contact.properties.company, 
website = contact.properties.website, 
address = contact.properties.address, 
city = contact.properties.city, 
language = contact.properties.hs_language
)
}
.filter { contact -> contact.phone != null || contact.mobilephone != null || contact.whatsapp != null }
.map(::mapContactInfo)
if(entries.isNotEmpty()) {
contacts.addAll(entries)
}
if(response.paging?.next != null) {
after = response.paging.next.after
} else {
break
}
delay(1500)
}
return contacts
}
suspend fun createContacts(api: Api, apiKey: String, device: Device, contacts: List<MappedContact>) {
println(" == > Creating contacts in bulk mode: ${contacts.size}")
try {
val response = api.createContacts(apiKey, device.id, contacts)
val results = response.data
println(" == > Total contacts created: ${results.filter { it.id != null }.size}")
if(response.status == 202) {
println(" == > Total duplicate or invalid contacts: ${results.filter { it.error != null }.size}")
}
for(result in results) {
if(result.error != null) {
println(" == > Contact already exists: ${result.contact.phone} https://app.wassenger.com/contacts/${device.id}/${result.contact.phone.substring(1)}")
} else {
println(" == > Contact created: ${result.phone} https://app.wassenger.com/contacts/${device.id}/${result.phone.substring(1)}")
}
}
} catch(e: Exception) {
println("[error] failed to create contacts: ${e.message}")
}
}
suspend fun getWhatsAppDevice(api: Api, apiKey: String): Device? {
val response = api.getDevices(apiKey, "operative", 50)
if(response.isEmpty()) {
return null
}
if(WHATSAPP_NUMBER_ID.isNotEmpty()) {
return response.find { device -> device.id == WHATSAPP_NUMBER_ID }
}
return response[0]
}
fun mapContactInfo(contact: Contact): MappedContact {
val data = mutableMapOf<String, Any?>(
"crmRef" to "hubspot: ${contact.id}"
)
// Add the remaining fields as necessary
//...
return MappedContact(
crmRef = data["crmRef"] as String, 
email = data["email"] as String?, 
phone = data["phone"] as String?, 
altPhone = data["altPhone"] as String?, 
languages = data["languages"] as List<String>?, 
postalCode = data["postalCode"] as String?, 
city = data["city"] as String?, 
address = data["address"] as String?, 
companyName = data["companyName"] as String?, 
companyWebsite = data["companyWebsite"] as String?
)
}

Ruby

require 'http'
require 'json'
# Enter Hubspot Private app API key here
# Requires Contacts read permissions
# More information: https://developers.hubspot.com/docs/api/private-apps
HUBSPOT_API_KEY = ''
# Enter your Wassenger API key here
# Obtain it here: https://app.wassenger.com/apikeys
API_KEY = 'API_KEY_GOES_HERE'
# Optionally, enter the WhatsApp number ID here(24 characters hexadecimal)
# If not specified, the first active WhatsApp number will be used
WHATSAPP_NUMBER_ID = ''
API_URL = 'https://api.wassenger.com'
MAX_CONTACTS = 3000
CONTACT_FIELDS = [
'email', 
'firstname', 
'lastname', 
'phone', 
'mobilephone', 
'hs_whatsapp_phone_number', 
'zip', 
'company', 
'website', 
'address', 
'city', 
'hs_language'
]
def map_contact_info(contact)
data = {
crmRef: "hubspot: #{contact[:id]}"
}
data[:email] = contact[:email] if contact[:email]&.length.between?(5, 50)
data[:phone] = contact[:whatsapp] if contact[:whatsapp]
data[:altPhone] = contact[:mobilephone] || contact[:phone] if contact[:whatsapp]
data[:phone] = contact[:mobilephone] if contact[:mobilephone] && !data[:phone]
data[:altPhone] = contact[:phone] if contact[:mobilephone] && contact[:phone] && !data[:altPhone]
data[:phone] = contact[:phone] if contact[:phone] && !data[:phone]
data[:languages] = [contact[:language][0, 2]] if contact[:language]
data[:postalCode] = contact[:postalcode][0, 20] if contact[:postalcode]
data[:city] = contact[:city][0, 30] if contact[:city]
data[:address] = contact[:address][0, 100] if contact[:address]
data[:companyName] = contact[:company][0, 50] if contact[:company]
data[:companyWebsite] = contact[:website][0, 100] if contact[:website]&.length > 5
data
end
def get_hubspot_contacts
after = nil
contacts = []
loop do
begin
puts " == > Fetching HubSpot contacts...#{contacts.length} / #{MAX_CONTACTS}"
response = HTTP.headers(
'Authorization' => "Bearer #{HUBSPOT_API_KEY}", 
'Content-Type' => 'application/json'
).get(
'https://api.hubapi.com/crm/v3/objects/contacts', 
params: {
limit: 100, 
after: after, 
properties: CONTACT_FIELDS.join(', ')
}
)
data = JSON.parse(response.body.to_s, symbolize_names: true)
entries = data[:results].map do |contact|
{
id: contact[:id], 
email: contact[:properties][:email], 
name: contact[:properties][:firstname], 
surname: contact[:properties][:lastname], 
phone: contact[:properties][:phone], 
mobilephone: contact[:properties][:mobilephone], 
whatsapp: contact[:properties][:hs_whatsapp_phone_number], 
postalcode: contact[:properties][:zip], 
company: contact[:properties][:company], 
website: contact[:properties][:website], 
address: contact[:properties][:address], 
city: contact[:properties][:city], 
language: contact[:properties][:hs_language]
}
end
.select { |contact| contact[:phone] || contact[:mobilephone] || contact[:whatsapp] }
.map { |contact| map_contact_info(contact) }
contacts.concat(entries) if entries.any?
break if contacts.length >= MAX_CONTACTS
if data[:paging] && data[:paging][:next]
after = data[:paging][:next][:after]
else
break
end
sleep 1.5
rescue StandardError => err
raise "Failed to fetch HubSpot contacts: #{err.message}"
end
end
contacts
end
def create_contacts(device, contacts)
puts " == > Creating contacts in bulk mode: #{contacts.length}"
begin
response = HTTP.headers(
'Content-Type' => 'application/json', 
'Authorization' => API_KEY
).patch(
"#{API_URL}/v1/chat/#{device[:id]}/contacts", body: JSON.generate(contacts)
)
results = JSON.parse(response.body.to_s, symbolize_names: true)
puts " == > Total contacts created: #{results.count { |x| x[:id] }}"
if response.status.code == 202
puts " == > Total duplicate or invalid contacts: #{results.count { |x| x[:error] }}"
end
results.each do |result|
if result[:error]
puts " == > Contact already exists: #{result[:contact][:phone]} https://app.wassenger.com/contacts/#{device[:id]}/#{result[:contact][:phone][1..]}"
else
puts " == > Contact created: #{result[:phone]} https://app.wassenger.com/contacts/#{device[:id]}/#{result[:phone][1..]}"
end
end
rescue StandardError => error
puts "[error] failed to create contacts: #{error.message}"
end
end
def get_whatsapp_device
response = HTTP.headers(
'Authorization' => API_KEY
).get(
"#{API_URL}/v1/devices?status=operative", 
params: { size: 50 }
)
data = JSON.parse(response.body.to_s, symbolize_names: true)
raise 'No active WhatsApp numbers connected in Wassenger.Connect a number here: https://app.wassenger.com/create' if data.empty?
return data.find { |device| device[:id] == WHATSAPP_NUMBER_ID } if WHATSAPP_NUMBER_ID
data[0]
end
def import_contacts
raise 'Missing required Wassenger API key.Sign up for free and obtain it here: https://app.wassenger.com/apikeys' if API_KEY.empty?
device = get_whatsapp_device
raise 'No active WhatsApp numbers connected in Wassenger.Connect a number here: https://app.wassenger.com/create' unless device
if device[:billing][:subscription][:product] != 'io'
raise "The selected WhatsApp number has no contacts API access feature enabled.Please upgrade plan here: https://app.wassenger.com/#{device[:id]}/plan"
end
hubspot_contacts = get_hubspot_contacts
unless hubspot_contacts
return puts "[error] Failed to obtain contacts from Hubspot: please make sure the Hubspot API key is valid and has read access to contacts in the Settings > Integrations > Private application > Edit application"
end
hubspot_contacts.each_slice(100) do |slice|
create_contacts(device, slice)
end
end
begin
import_contacts
rescue StandardError => err
puts "Failed to import contacts: #{err.message}"
end

🤩 🤖 Wassenger is a complete communication platform and API solution for WhatsApp. Explore more than 100+ API use cases and automate anything on WhatsApp by signing up for a free trial and getting started in minutes!

Go

package main
import(
"encoding/json"
"fmt"
"net/http"
"strconv"
"strings"
"time"
"github.com/parnurzeal/gorequest"
)
const(
// Enter Hubspot Private app API key here
// Requires Contacts read permissions
// More information: https://developers.hubspot.com/docs/api/private-apps
HubspotAPIKey = ""
// Enter your Wassenger API key here
// Obtain it here: https://app.wassenger.com/apikeys
APIKey = "API_KEY_GOES_HERE"
// Optionally, enter the WhatsApp number ID here(24 characters hexadecimal)
// If not specified, the first active WhatsApp number will be used
WhatsAppNumberID = ""
MaxContacts = 3000
APIURL = "https://api.wassenger.com"
)
var contactFields = []string{
"email", 
"name", 
"lastname", 
"phone", 
"mobilephone", 
"hs_whatsapp_phone_number", 
"zip", 
"company", 
"website", 
"address", 
"city", 
"hs_language", 
}
type Contact struct {
ID string `json:"id"`
Email string `json:"email"`
Name string `json:"name"`
Surname string `json:"surname"`
Phone string `json:"phone"`
MobilePhone string `json:"mobilephone"`
WhatsApp string `json:"whatsapp"`
PostalCode string `json:"postalcode"`
Company string `json:"company"`
Website string `json:"website"`
Address string `json:"address"`
City string `json:"city"`
Language string `json:"language"`
}
type MappedContact struct {
CrmRef string `json:"crmRef, omitempty"`
Email string `json:"email, omitempty"`
Phone string `json:"phone, omitempty"`
AltPhone string `json:"altPhone, omitempty"`
Languages []string `json:"languages, omitempty"`
PostalCode string `json:"postalCode, omitempty"`
City string `json:"city, omitempty"`
Address string `json:"address, omitempty"`
CompanyName string `json:"companyName, omitempty"`
CompanyWebsite string `json:"companyWebsite, omitempty"`
}
type Device struct {
ID string `json:"id"`
Billing struct {
Subscription struct {
Product string `json:"product"`
} `json:"subscription"`
} `json:"billing"`
}
func mapContactInfo(contact Contact) MappedContact {
data:= MappedContact{
CrmRef: fmt.Sprintf("hubspot: %s", contact.ID), 
}
if len(contact.Email) > 5 && len(contact.Email) < 50 {
data.Email = contact.Email
}
if contact.WhatsApp != "" {
data.Phone = contact.WhatsApp
if contact.MobilePhone != "" {
data.AltPhone = contact.MobilePhone
} else if contact.Phone != "" {
data.AltPhone = contact.Phone
}
} else if contact.MobilePhone != "" {
data.Phone = contact.MobilePhone
if contact.Phone != "" {
data.AltPhone = contact.Phone
}
} else if contact.Phone != "" {
data.Phone = contact.Phone
}
if contact.Language != "" {
data.Languages = []string{contact.Language[:2]}
}
if contact.PostalCode != "" {
data.PostalCode = contact.PostalCode[:20]
}
if contact.City != "" {
data.City = contact.City[:30]
}
if contact.Address != "" {
data.Address = contact.Address[:100]
}
if contact.Company != "" {
data.CompanyName = contact.Company[:50]
}
if len(contact.Website) > 5 {
data.CompanyWebsite = contact.Website[:100]
}
return data
}
func getHubSpotContacts()([]MappedContact, error) {
var after string
contacts:= []MappedContact{}
for {
fmt.Printf(" == > Fetching HubSpot contacts...%d / %d\n", len(contacts), MaxContacts)
request:= gorequest.New()
url:= "https://api.hubapi.com/crm/v3/objects/contacts"
params:= map[string]string{
"limit": "100", 
"after": after, 
"properties": strings.Join(contactFields, ", "), 
}
headers:= map[string]string{
"Authorization": fmt.Sprintf("Bearer %s", HubspotAPIKey), 
"Content-Type": "application/json", 
}
resp, body, errs:= request.Get(url).
Set("params", params).
Set("headers", headers).
End()
if errs != nil {
return nil, fmt.Errorf("failed to fetch HubSpot contacts: %v", errs)
}
var response struct {
Results []Contact `json:"results"`
Paging struct {
Next struct {
After string `json:"after"`
} `json:"next"`
} `json:"paging"`
}
err:= json.Unmarshal([]byte(body), &response)
if err != nil {
return nil, fmt.Errorf("failed to unmarshal HubSpot contacts response: %v", err)
}
entries:= []MappedContact{}
for _, contact:= range response.Results {
if contact.Phone != "" || contact.MobilePhone != "" || contact.WhatsApp != "" {
entries = append(entries, mapContactInfo(contact))
}
}
if len(entries) > 0 {
contacts = append(contacts, entries...)
}
if len(contacts) >= MaxContacts {
break
}
if response.Paging.Next.After != "" {
after = response.Paging.Next.After
} else {
break
}
time.Sleep(1500 * time.Millisecond)
}
return contacts, nil
}
func createContacts(device Device, contacts []MappedContact) error {
fmt.Printf(" == > Creating contacts in bulk mode: %d\n", len(contacts))
request:= gorequest.New()
url:= fmt.Sprintf("%s/v1/chat/%s/contacts", APIURL, device.ID)
headers:= map[string]string{
"Content-Type": "application/json", 
"Authorization": APIKey, 
}
resp, body, errs:= request.Patch(url).
Set("headers", headers).
Send(contacts).
End()
if errs != nil {
return fmt.Errorf("failed to create contacts: %v", errs)
}
var results []struct {
ID string `json:"id"`
Phone string `json:"phone"`
Contact MappedContact `json:"contact"`
Error string `json:"error"`
}
err:= json.Unmarshal([]byte(body), &results)
if err != nil {
return fmt.Errorf("failed to unmarshal create contacts response: %v", err)
}
totalCreated:= 0
totalDuplicateOrInvalid:= 0
for _, result:= range results {
if result.ID != "" {
totalCreated++
fmt.Printf(" == > Contact created: %s https://app.wassenger.com/contacts/%s/%s\n", result.Phone, device.ID, result.Phone[1:])
} else if result.Error != "" {
totalDuplicateOrInvalid++
fmt.Printf(" == > Contact already exists: %s https://app.wassenger.com/contacts/%s/%s\n", result.Contact.Phone, device.ID, result.Contact.Phone[1:])
}
}
fmt.Printf(" == > Total contacts created: %d\n", totalCreated)
if resp.StatusCode == 202 {
fmt.Printf(" == > Total duplicate or invalid contacts: %d\n", totalDuplicateOrInvalid)
}
return nil
}
func getWhatsAppDevice()(*Device, error) {
request:= gorequest.New()
url:= fmt.Sprintf("%s/v1/devices?status=operative", APIURL)
headers:= map[string]string{
"Authorization": APIKey, 
}
resp, body, errs:= request.Get(url).
Set("headers", headers).
End()
if errs != nil {
return nil, fmt.Errorf("failed to fetch devices: %v", errs)
}
var devices []Device
err:= json.Unmarshal([]byte(body), &devices)
if err != nil {
return nil, fmt.Errorf("failed to unmarshal devices response: %v", err)
}
if len(devices) == 0 {
return nil, fmt.Errorf("no active WhatsApp numbers connected in Wassenger.Connect a number here: https://app.wassenger.com/create")
}
if WhatsAppNumberID != "" {
for _, device:= range devices {
if device.ID == WhatsAppNumberID {
return &device, nil
}
}
return nil, fmt.Errorf("WhatsApp number with ID %s not found", WhatsAppNumberID)
}
return &devices[0], nil
}
func importContacts() error {
if APIKey == "" {
return fmt.Errorf("missing required Wassenger API key.Sign up for free and obtain it here: https://app.wassenger.com/apikeys")
}
device, err:= getWhatsAppDevice()
if err != nil {
return err
}
if device.Billing.Subscription.Product != "io" {
return fmt.Errorf("the selected WhatsApp number has no contacts API access feature enabled.Please upgrade plan here: https://app.wassenger.com/%s/plan", device.ID)
}
hubspotContacts, err:= getHubSpotContacts()
if err != nil {
return fmt.Errorf("failed to obtain contacts from Hubspot: please make sure the Hubspot API key is valid and has read access to contacts in the Settings > Integrations > Private application > Edit application: %v", err)
}
for i:= 0; i < len(hubspotContacts); i += 100 {
end:= i + 100
if end > len(hubspotContacts) {
end = len(hubspotContacts)
}
err = createContacts(*device, hubspotContacts[i:end])
if err != nil {
return fmt.Errorf("failed to create contacts: %v", err)
}
}
return nil
}
func main() {
err:= importContacts()
if err != nil {
fmt.Printf("Failed to import contacts: %v\n", err)
}
}

By following this tutorial, you can successfully import contacts from Hubspot to Wassenger using their APIs. This integration will enable you to manage your contacts more effectively and take advantage of Wassenger’s messaging capabilities.

Make sure to test your implementation thoroughly and handle any edge cases that may arise during the process.

🤩 🤖 Wassenger is a complete communication platform and API solution for WhatsApp. Explore more than 100+ API use cases and automate anything on WhatsApp by signing up for a free trial and getting started in minutes!

Ready to transform your WhatsApp communication?

Start automating your customer interactions today with Wassenger

Get Started Free