Links
Comment on page

Send conversation to HubSpot communication

Tags: #linkedin #message #naas_drivers #content #snippet #dataframe
Author: Florent Ravenel​
Last update: 2023-08-31 (Created: 2023-08-31)
Description: This notebook send a LinkedIn conversation with all messages to a contact HubSpot communication.
Disclaimer: This code is in no way affiliated with, authorized, maintained, sponsored or endorsed by Linkedin or any of its affiliates or subsidiaries. It uses an independent and unofficial API. Use at your own risk.
This project violates Linkedin's User Agreement Section 8.2, and because of this, Linkedin may (and will) temporarily or permanently ban your account. We are not responsible for your account being banned.

Input

Import libraries

from naas_drivers import linkedin
import naas
from datetime import datetime, timezone
import requests
import pandas as pd

Setup variables

Mandatory
  • li_at: Cookie used to authenticate Members and API clients.
  • JSESSIONID: Cookie used for Cross Site Request Forgery (CSRF) protection and URL signature validation.
  • conversation_url: LinkedIn conversation URL
  • hs_access_token: This variable stores an access token used for accessing the HubSpot API.
  • contact_id: This variable stores the HubSpot contact ID that will be associated to the communication.
Optional
  • limit: Number of conversations to be retrieved. Max limit is 600.
# Mandatory
li_at = naas.secret.get("LINKEDIN_LI_AT") or "YOUR_LINKEDIN_LI_AT" #example: AQFAzQN_PLPR4wAAAXc-FCKmgiMit5FLdY1af3-2
JSESSIONID = naas.secret.get("LINKEDIN_JSESSIONID") or "YOUR_LINKEDIN_JSESSIONID" #example: ajax:8379907400220387585
conversation_url = "https://www.linkedin.com/messaging/thread/2-YzRhNGMxMjAtNGFiMy01ZmFiLWI3YTYtMWNkNmQ0YzJhMGU3XzAwMA==/"
hs_access_token = naas.secret.get("HS_ACCESS_TOKEN") or "YOUR_HS_ACCESS_TOKEN"
contact_id = "308551"
​
# Optional
limit = 40

Model

Get messages from a LinkedIn conversation

df = linkedin.connect(li_at, JSESSIONID).message.get_messages(conversation_url=conversation_url, limit=limit)
print("Row fetched:", len(df))
df.head(1)

Get existings communications associated to contact ID

def delete_communication(
token,
object_id,
​
):
# Requests
headers = {
"Content-Type": "application/json",
"Authorization": f"Bearer {token}"
}
url = f"https://api.hubapi.com/crm/v3/objects/Communications/{object_id}"
​
# Response
res = requests.delete(url, headers=headers)
if res.status_code == 204:
print(f"Communication '{object_id}' successfully deleted!")
else:
print(res.text)
return res
​
def get_association_from_contact(
token,
contact_id,
endpoint,
):
# Init
results = []
# Requests
headers = {
"Content-Type": "application/json",
"Authorization": f"Bearer {token}"
}
url = f"https://api.hubapi.com/crm/v4/objects/contacts/{contact_id}/associations/{endpoint}"
# Response
res = requests.get(url, headers=headers)
if res.status_code == 200:
results = res.json().get("results")
return results
​
def retrieve_object_details(
token,
object_id,
object_type,
properties=None,
):
# Init
data = []
params = {
"archived": "false"
}
# Requests
if properties:
params["properties"] = properties
headers = {
"Content-Type": "application/json",
"Authorization": f"Bearer {token}"
}
url = f"https://api.hubapi.com/crm/v3/objects/{object_type}/{object_id}"
# Response
res = requests.get(url, headers=headers, params=params)
if res.status_code == 200:
data = res.json().get("properties")
else:
print(res.text)
return pd.DataFrame([data])
​
def create_activity_df(
token,
contact_id,
activity,
properties_dict=None,
):
# Init
df = pd.DataFrame()
if not properties_dict:
properties_dict = {
"hs_object_id": "activity_hs_id",
"hs_lastmodifieddate": "activity_date",
"hs_body_preview": "activity_content"
}
properties = [x for x in properties_dict]
# List activities
data = get_association_from_contact(
token,
contact_id,
activity
)
for d in data:
object_id = d.get("toObjectId")
# res = delete_communication(hs_access_token, object_id)
tmp_df = retrieve_object_details(
token,
object_id,
activity,
properties
)
if len(tmp_df) > 0:
tmp_df = tmp_df[properties]
df = pd.concat([df, tmp_df])
if len(df) > 0:
df = df.rename(columns=properties_dict)
if 'activity_type' not in df:
df.insert(loc=1, column="activity_type", value=activity.upper())
return df.reset_index(drop=True)
​
properties_dict = {
"hs_object_id": "activity_hs_id",
"hs_unique_id": "message_id",
"hs_timestamp": "activity_date",
"hs_communication_channel_type": "activity_type",
"hs_body_preview": "activity_content"
}
​
df_communications = create_activity_df(
hs_access_token,
contact_id,
"communications",
properties_dict
)
print("Communications:", len(df_communications))
df_communications

Output

Create communication

def create_communication(
api_key,
communication_body,
contact_id,
communication_datetime,
message_id,
channel_type=None,
):
# Init
data = []
# Get the current timestamp in UTC
if not communication_datetime:
communication_datetime = datetime.utcnow()
hs_timestamp = communication_datetime.replace(tzinfo=timezone.utc).strftime("%s") + "000"
# Requests
url = "https://api.hubapi.com/crm/v3/objects/Communications"
payload = {
"properties":
{
"hs_communication_channel_type": channel_type,
"hs_communication_logged_from": "CRM",
"hs_communication_body": communication_body,
"hs_timestamp": hs_timestamp,
"hs_unique_id": message_id
},
"associations": [
{
"to": {"id": contact_id},
"types": [
{
"associationCategory": "HUBSPOT_DEFINED",
"associationTypeId": 81 #contact
}
]
}
]
}
​
headers = {
'accept': "application/json",
'content-type': "application/json",
'authorization': f"Bearer {api_key}"
}
​
# Response
res = requests.post(url, headers=headers, json=payload)
if res.status_code == 201:
data = res.json()
else:
print(res.text)
return data
​
message_ids = []
if len(df_communications) > 0:
message_ids = df_communications["message_id"].tolist():
​
for row in df.itertuples():
message = row.MESSAGE.replace('\n', '')
message_id = row.MESSAGE_ID
fullname = row.FULLNAME
message_sent_at = row.MESSAGE_SENT_AT
if message != "" and not message_id in message_ids:
communication_body = f"{fullname}: {message}"
communication_datetime = datetime.strptime(message_sent_at, "%Y-%m-%d %H:%M:%S")
print(f"{message_sent_at} - {communication_body}")
data = create_communication(
hs_access_token,
communication_body,
contact_id,
communication_datetime,
message_id,
"LINKEDIN_MESSAGE",
)