matelso & HubSpot

Integrationen Weitere Integrationen

In diesem Artikel beschreiben wir welche Herausforderungen bei der Kombination Integrations 2.0 und HubSpot entstehen und wie wir diese lösen können

HubSpot bietet eine API an. Über diese Schnittstelle können Datensätze gesucht, erzeugt, geändert und gelöscht werden.

Für eine Call-Tracking-Integration interessieren uns Deals und Kontakte in HubSpot. Die erste Integration die wir bauen sendet direkt an HubSpot und erzeugt einen Deal für jeden Anruf. Die zweite Integration sendet an ein PHP-Script welches dann in HubSpot nach einem Kontakt sucht und dann einen Deal zu diesem Kontakt anlegt.

ACHTUNG: Seit dem 30.11.2022 akzeptiert die HubSpot API keine API Keys mehr. Die Authentifizierung ist aktuell nur noch über private app access token oder OAuth möglich. Matelso unterstützt eine Authentifizierung über OAuth, aber der folgende Artikel bezieht sich noch auf die alte Methode. Eine Alternative ist ebenfalls HubSpot über einen Drittanbieter wie Zapier zu verbinden. In unserem Webinar haben wir dazu einen Usecase aufgezeigt.

HubSpot direkt Anbindung

Die direkte Anbindung an HubSpot erzeugt einen Deal für jeden Anruf auf eine Call-Tracking-Nummer. Diese Variante braucht kein zusätzliches Script und kann im Control Panel eingerichtet werden. 

Einrichtung im CP

Als erstes navigieren wir zu "Konfiguration"->"Integrations 2.0".



Danach erstellen wir einen Custom Push über den Vorauswahl-Button.



Danach vergeben wir einen Namen und den Zeitpunkt des Pushes.



In diesem Beispiel heißt der Push "HubSpot-Direct" und als Zeitpunkt wird "POST CALL" genutzt. Hier können auch Filter gesetzt werden, in diesem Beispiel nutzen wir das nicht.

Im nächsten Schritt tragen wir den Endpunkt der HubSpot API in den Bereich "Wohin?". Um einen Deal anzulegen nutzen wir den Endpunkt "https://api.hubapi.com/crm/v3/objects/deals".



Es wird keine HTTP Basic Authentifizierung verwendet und das Error Handling belassen wir auf dem Standard.

Als letzten Bereich müssen wir den "Was?"-Bereich ausfüllen. Hier wird als erstes die HTTP Methode auf "POST" gesetzt. Zusätzlich setzen wir einen HTTP Header "Content-Type".




Da die Authentifizierung der HubSpot API via API-Key funktioniert, müssen wir den API Key als GET-Parameter setzen. 




Im letzten Konfigurationsschritt füllen wir den POST-Body der Anfrage mit einem JSON Objekt, welches in der HubSpot API definiert ist.




Dieses Objekt enthält eine Eigenschaft mit Name "properties". In diesem "properties" Objekt sind 4 Eigenschaften enthalten.

Zeile 3 "amount": Der Betrag/Wert des Deals. Hier setzen wir statisch 1, da wir diesen Wert noch nicht kennen können.

Zeile 4 "dealname": Hier setzen wir den Namen des Deals der in HubSpot erstellt wird. In unserem Beispiel fängt der Name mit "Neuer Anruf von " an und darauf folgt der DDD-Key für die Anrufernummer. ex. "Neuer Anruf von +4971196589120"

Zeile 5 "dealstage": Hier wird die Phase des Deal definiert. In unserem Beispiel setzen wir den Deal auf "Termin geplant" ("appointmentscheduled").

Zeile 6 "pipeline": Definiert in welcher Deal Pipeline der Deal angelegt wird.

HubSpot via PHP-Script

In dieser Konfiguration wird der Push an ein PHP-Script gesendet. Dieses Script sucht in HubSpot nach einem Kontakt mit der Anrufer Nummer und legt diesen Kontakt an, falls dieser nicht vorhanden ist. Danach wird eine Notiz bei diesem Kontakt mit den Anrufinformationen hinterlegt. 

PHP Script

Um die Logik der Kontaktsuche/Kontakterstellung abzubilden wird ein PHP Script benötigt. Dieses Script muss als .php Datei auf einen Webserver mit PHP Modul.

Dieses Script muss als .php Datei auf einen Webserver mit PHP Modul.

<?php

/* ----- config starts here ----- */
define("WEB_PASSWORD", "SICHERES_PASSWORT");
define("DEBUG_LOG", true);
define("HUBSPOT_API_KEY", "0ab12c34-****-****-****-************");

/* ----- check access password ----- */
if(WEB_PASSWORD != $_GET["webPasswd"]) {
return;
}

/* ----- read values from request ----- */
$aNumber = $_GET["aNumber"];

/* ----- code starts here ----- */
// log a message to the output if DEBUG_LOG is set to true
function logDebug($msg) {
if (DEBUG_LOG == true) {
echo $msg . '<br/>';
}
}
// finds a contact in hubspot by the given phone number
function findContactByNumber($number) {
$curl = curl_init();
curl_setopt_array($curl, array(
CURLOPT_URL => "https://api.hubapi.com/crm/v3/objects/contacts/search?hapikey=" . HUBSPOT_API_KEY,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_0,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => "{ \"filterGroups\": [ { \"filters\": [ { \"value\": \"" . $number . "\", \"propertyName\": \"phone\", \"operator\": \"EQ\" } ] } ], \"properties\": [ \"id\", \"phone\" ], \"limit\": 100 }",
CURLOPT_HTTPHEADER => array(
"accept: application/json",
"content-type: application/json"
),
));
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
return null;
} else {
return $response;
}
}
// create a new contact in hubspot with the given phone number and and email address based on the phone number
function createContact($number) {
$curl = curl_init();
curl_setopt_array($curl, array(
CURLOPT_URL => "https://api.hubapi.com/crm/v3/objects/contacts?hapikey=" . HUBSPOT_API_KEY,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_0,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => "{ \"properties\": { \"email\": \"" . $number . "@call.from.calltracking.de\", \"phone\": \"" . $number . "\" } }",
CURLOPT_HTTPHEADER => array(
"accept: application/json",
"content-type: application/json"
),
));
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
return null;
} else {
return $response;
}
}
// create notice in hubspot
function createNotice($text, $contactId) {
$curl = curl_init();
curl_setopt_array($curl, array(
CURLOPT_URL => "https://api.hubapi.com/engagements/v1/engagements?hapikey=" . HUBSPOT_API_KEY,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_0,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => "{ \"engagement\": { \"active\": true, \"ownerId\": 1, \"type\": \"NOTE\", \"timestamp\": " . time() . "000 }, \"associations\": { \"contactIds\": [ " . $contactId . "], \"companyIds\": [ ], \"dealIds\": [ ], \"ownerIds\": [ ], \"ticketIds\":[ ] }, \"attachments\": [ ], \"metadata\": { \"body\": \"". $text . "\" } }",
CURLOPT_HTTPHEADER => array(
"accept: application/json",
"content-type: application/json"
),
));
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
return null;
} else {
return $response;
}
}
// utility method for createContact and returns the id of the newly created contact
function createContactGetId($number) {
$createRes = createContact($number);
if($createRes == null) {
return -1;
}
$hsJson = json_decode($createRes, true);
return $hsJson['id'];
}

// try to find contact by number
$contactRes = findContactByNumber($aNumber);
if($contactRes == null) {
// empty result from find. Create new contact
$hsContactId = createContactGetId($aNumber);
logDebug('No search result. Create contact ' . $hsContactId);
} else {
// deserialize the hubspot response
$hsJson = json_decode($contactRes, true);
// check whether the resultset contains entries
if(count($hsJson['results']) > 0) {
// get the id from the first search result
$hsContactId = $hsJson['results'][0]['id'];
logDebug('Found contact ' . $hsContactId);
} else {
// no search result found. create new contact
$hsContactId = createContactGetId($aNumber);
logDebug('Create contact ' . $hsContactId);
}
}

// check if hsContactId is an integer
if (!is_int(intval($hsContactId))) {
logDebug("error finding or creating contact");
return;
}

// TODO: create notice with contact
createNotice("Ein Anruf von " . $aNumber, $hsContactId);
logDebug("Notiz angelegt");

?>

Das Script ist in 4 Blöcke unterteilt. Jeder dieser Blöcke beginnt mit einer Zeile die mit /* startet und mit */ endet.

Block 1 (Zeile 3):

Beginnt mit: /* ----- config starts here ----- */
Enthält: In diesem Block werden Konfigurationswerte gesetzt. Hier muss
man auch als Leser dieses Artikel aktiv werden.
Was tun?: Das WEB_PASSWORD und der HUBSPOT_API_KEY müssen vom Verwender gesetzt werden. Im ersten Abschnitt zur direkten Integration ist ein Link wie man einen HUBSPOT_API_KEY erzeugen kann.
Wenn DEBUG_LOG auf true gesetzt wird, werden Informationen in die Ausgabe/Rückgabe des Script geschrieben. Diese können dann auch in den Push Logs gesehen werden.

Block 2 (Zeile 8):

Beginnt mit: /* ----- check access password ----- */
Enthält: In diesem Abschnitt wird überprüft ob die Anfrage das korrekte WEB_PASSWORD enthält. Wenn dies nicht der Fall ist, wird die Anfrage an dieser Stelle beendet.
Durch diesen Abschnitt wird verhindert das Anfragen an das PHP Script von externen etwas in HubSpot verändern.

Block 3 (Zeile 13):

Beginnt mit: /* ----- read values from request ----- */
Enthält: In diesem Abschnitt werden die Anfrageparameter in Variablen extrahiert.

Block 4 (Zeile 16):

Beginnt mit: /* ----- code starts here ----- */
Enthält: Hilfsfunktionen und die eigentliche Logik welche ausgeführt wird.
Einrichtung im Control Panel

Wir navigieren zu "Konfiguration"->"Integrations 2.0" und klick dann auf "Custom Push" um einen Push anzulegen.




Im nächsten Schritt vergeben wir einen Namen und wählen den Zeitpunkt aus. Auch in diesem Fall verwenden wir keinen Filter.




Im Screenshot heißt der Push "HubSpot-PHP" und als Zeitpunkt ist "POST CALL" ausgewählt.

Im nächsten Schritt konfigurieren wir das "Wohin?". Hierzu brauchen wir die URL und den Namen der PHP-Datei im Webspace. In diesem Beispiel heißt die Datei "matelso-push.php" und liegt unter "https://scripts.matelso.com/matelso-push.php".



Jetzt müssen wir nur noch das "Was?" konfigurieren. Für dieses Beispielscript müssen 2 GET Parameter übertragen werden ("aNumber" & "webPasswd").


Für aNumber wird der DDD-Key "" verwendet.