This is an update to my previous post, Submitting Leads to Marketo’s SOAP API using PHP. Recently, Marketo did an update to their SOAP PHP Client and a few things changed along the way. More specifically, what information you pass in to the sync lead function.
I’ll quickly go through the code needed for the new change. You might want to read the previous post to get an idea of how it all works together.
Your Marketo Lead Array
At this point, you’ve collected your user’s data from most likely a web form. We’ll store these details in an array and pass that array to our function for lead submission.
//Creating the array $marketoArray = array( 'Company' => $_POST['company'], 'FirstName' => $_POST['firstname'], 'LastName' => $_POST['lastname'], 'Email' => $_POST['email'], 'ListSource' => 'Name of your list source', 'LeadSource' => 'Name of your lead source' ); marketo_submit_lead($marketoArray);
Function to submit lead
Here is the lead submit function which gets your array from the previous secion and calls the marketo class. You’ll notice that we’re no longer passing in a cookie to the syncLead function.
//Submitting the user's registration info to Marketo function marketo_submit_lead($marketoArray) { //Marketo SOAP PHP Client Class require_once('marketo.php'); $marketo_user_id = 'YOUR MARKETO USER ID'; $marketo_encryption_key = 'YOUR MARKETO ENCRYPTION KEY'; $marketo_soap_host = 'YOUR MARKETO SOAP END POINT'; //Connecting to Marketo $marketo_client = new MarketoAPI($marketo_user_id, $marketo_encryption_key, $marketo_soap_host); //Checking for the existence of a lead //If lead exists, setting the lead record and submit the lead to Marketo $checkLead = $marketo_client->getLead('EMAIL', $marketoArray['Email']); if ($checkLead == null) { //This is a new lead $marketo_client->syncLead($marketoArray['Email'], $marketoArray); } else { //This is an existing lead $leadId = $checkLead->Id; $marketo_client->syncLead($leadId, $marketoArray); } //Adding the Lead to a campaign $campaign_name = "NAME OF YOUR MARKETO SMART CAMPAIGN"; //Getting List of Campaigns $campaign_list = $marketo_client->getCampaignsForSource(); //Checking if out campaign is available in the list if (empty($campaign_list[$campaign_name])) { //No campaign found. } else { $campaign_id = $campaign_list[$campaign_name]; //Get Lead ID if new lead. Otherwise, add lead to campaign if ($leadId) { $marketo_client->requestCampaign($campaign_id, $leadId); } else { $getLead = $marketo_client->getLead('EMAIL', $marketoArray['Email']); if ($checkLead != null) { $leadId = $getLead->Id; $marketo_client->requestCampaign($campaign_id, $leadId); } } } }
The updated SOAP PHP Client/Class from Marketo (marketo.php)
This one is slightly modified from the original. I’ve removed the credentials from the class. This allows you to pass that in from your lead submit function and do interesting things like, encrypt it outside of the class and decrypt before passing in.
// PHP classes corresponding to the data types in defined in WSDL class ActivityRecord { /** * @var int */ public $id; /** * @var dateTime */ public $activityDateTime; /** * @var string */ public $activityType; /** * @var string */ public $mktgAssetName; /** * @var (object)ArrayOfAttribute */ public $activityAttributes; /** * @var string */ public $campaign; /** * @var string */ public $personName; /** * @var string */ public $mktPersonId; /** * @var string */ public $foreignSysId; /** * @var string */ public $orgName; /** * @var string */ public $foreignSysOrgId; } class ActivityTypeFilter { /** * @var (object)ArrayOfActivityType */ public $includeTypes; /** * @var (object)ArrayOfActivityType */ public $excludeTypes; } class Attribute { /** * @var string */ public $attrName; /** * @var string */ public $attrType; /** * @var string */ public $attrValue; } class AuthenticationHeaderInfo { /** * @var string */ public $mktowsUserId; /** * @var string */ public $requestSignature; /** * @var string */ public $requestTimestamp; /** * @var string */ public $audit; /** * @var int */ public $mode; } class CampaignRecord { /** * @var int */ public $id; /** * @var string */ public $name; /** * @var string */ public $description; } class LeadActivityList { /** * @var int */ public $returnCount; /** * @var int */ public $remainingCount; /** * @var (object)StreamPosition */ public $newStartPosition; /** * @var (object)ArrayOfActivityRecord */ public $activityRecordList; } class LeadChangeRecord { /** * @var int */ public $id; /** * @var dateTime */ public $activityDateTime; /** * @var string */ public $activityType; /** * @var string */ public $mktgAssetName; /** * @var (object)ArrayOfAttribute */ public $activityAttributes; /** * @var string */ public $campaign; /** * @var string */ public $mktPersonId; } class LeadKey { /** * @var string * NOTE: keyType should follow the following restrictions * You can have one of the following value * IDNUM * COOKIE * EMAIL * LEADOWNEREMAIL * SFDCACCOUNTID * SFDCCONTACTID * SFDCLEADID * SFDCLEADOWNERID * SFDCOPPTYID */ public $keyType; /** * @var string */ public $keyValue; } class LeadRecord { /** * @var int */ public $Id; /** * @var string */ public $Email; /** * @var string */ public $ForeignSysPersonId; /** * @var string * NOTE: ForeignSysType should follow the following restrictions * You can have one of the following value * CUSTOM * SFDC * NETSUITE */ public $ForeignSysType; /** * @var (object)ArrayOfAttribute */ public $leadAttributeList; } class LeadStatus { /** * @var (object)LeadKey */ public $leadKey; /** * @var boolean */ public $status; } class ListKey { /** * @var string * NOTE: keyType should follow the following restrictions * You can have one of the following value * MKTOLISTNAME * MKTOSALESUSERID * SFDCLEADOWNERID */ public $keyType; /** * @var string */ public $keyValue; } class ResultGetCampaignsForSource { /** * @var int */ public $returnCount; /** * @var (object)ArrayOfCampaignRecord */ public $campaignRecordList; } class ResultGetLead { /** * @var int */ public $count; /** * @var (object)ArrayOfLeadRecord */ public $leadRecordList; } class ResultGetLeadChanges { /** * @var int */ public $returnCount; /** * @var int */ public $remainingCount; /** * @var (object)StreamPosition */ public $newStartPosition; /** * @var (object)ArrayOfLeadChangeRecord */ public $leadChangeRecordList; } class ResultGetMultipleLeads { /** * @var int */ public $returnCount; /** * @var int */ public $remainingCount; /** * @var string */ public $newStreamPosition; /** * @var (object)ArrayOfLeadRecord */ public $leadRecordList; } class ResultListOperation { /** * @var boolean */ public $success; /** * @var (object)ArrayOfLeadStatus */ public $statusList; } class ResultRequestCampaign { /** * @var boolean */ public $success; } class ResultSyncLead { /** * @var int */ public $leadId; /** * @var string * NOTE: syncStatus should follow the following restrictions * You can have one of the following value * CREATED * UPDATED * FAILED */ public $syncStatus; /** * @var (object)LeadRecord */ public $leadRecord; } class ResultSyncMultipleLeads { /** * @var (object)ArrayOfSyncStatus */ public $syncStatusList; } class StreamPosition { /** * @var dateTime */ public $latestCreatedAt; /** * @var dateTime */ public $oldestCreatedAt; /** * @var dateTime */ public $activityCreatedAt; /** * @var string */ public $offset; } class SyncStatus { /** * @var int */ public $leadId; /** * @var string * NOTE: status should follow the following restrictions * You can have one of the following value * CREATED * UPDATED * UNCHANGED * FAILED */ public $status; /** * @var string */ public $error; } class VersionedItem { /** * @var integer */ public $id; /** * @var string */ public $name; /** * @var string */ public $type; /** * @var string */ public $description; /** * @var dateTime */ public $timestamp; } class ArrayOfActivityRecord { /** * @var array[0, unbounded] of (object)ActivityRecord */ public $activityRecord; } class ArrayOfActivityType { /** * @var array[0, unbounded] of string * NOTE: activityType should follow the following restrictions * You can have one of the following value * VisitWebpage * FillOutForm * ClickLink * RegisterForEvent * AttendEvent * SendEmail * EmailDelivered * EmailBounced * UnsubscribeEmail * OpenEmail * ClickEmail * NewLead * ChangeDataValue * LeadAssigned * NewSFDCOpprtnty * Wait * RunSubflow * RemoveFromFlow * PushLeadToSales * CreateTask * ConvertLead * ChangeScore * ChangeOwner * AddToList * RemoveFromList * SFDCActivity * EmailBouncedSoft * PushLeadUpdatesToSales * DeleteLeadFromSales * SFDCActivityUpdated * SFDCMergeLeads * MergeLeads * ResolveConflicts * AssocWithOpprtntyInSales * DissocFromOpprtntyInSales * UpdateOpprtntyInSales * DeleteLead * SendAlert * SendSalesEmail * OpenSalesEmail * ClickSalesEmail * AddtoSFDCCampaign * RemoveFromSFDCCampaign * ChangeStatusInSFDCCampaign * ReceiveSalesEmail * InterestingMoment * RequestCampaign * SalesEmailBounced */ public $activityType; } class ArrayOfAttribute { /** * @var array[0, unbounded] of (object)Attribute */ public $attribute; } class ArrayOfBase64Binary { // You need to set only one from the following two vars /** * @var array[0, unbounded] of Plain Binary */ public $base64Binary; /** * @var array[0, unbounded] of base64Binary */ public $base64Binary_encoded; } class ArrayOfCampaignRecord { /** * @var array[0, unbounded] of (object)CampaignRecord */ public $campaignRecord; } class ArrayOfLeadChangeRecord { /** * @var array[0, unbounded] of (object)LeadChangeRecord */ public $leadChangeRecord; } class ArrayOfLeadKey { /** * @var array[0, unbounded] of (object)LeadKey */ public $leadKey; } class ArrayOfLeadRecord { /** * @var array[0, unbounded] of (object)LeadRecord */ public $leadRecord; } class ArrayOfLeadStatus { /** * @var array[0, unbounded] of (object)LeadStatus */ public $leadStatus; } class ArrayOfSyncStatus { /** * @var array[0, unbounded] of (object)SyncStatus */ public $syncStatus; } class ArrayOfVersionedItem { /** * @var array[0, unbounded] of (object)VersionedItem */ public $versionedItem; } class paramsGetCampaignsForSource { /** * @var string * NOTE: source should follow the following restrictions * You can have one of the following value * MKTOWS * SALES */ public $source; /** * @var string */ public $name; /** * @var boolean */ public $exactName; } class paramsGetLead { /** * @var (object)LeadKey */ public $leadKey; } class paramsGetLeadActivity { /** * @var (object)LeadKey */ public $leadKey; /** * @var (object)ActivityTypeFilter */ public $activityFilter; /** * @var (object)StreamPosition */ public $startPosition; /** * @var int */ public $batchSize; } class paramsGetLeadChanges { /** * @var (object)StreamPosition */ public $startPosition; /** * @var (object)ActivityTypeFilter */ public $activityFilter; /** * @var int */ public $batchSize; } class paramsGetMultipleLeads { /** * @var dateTime */ public $lastUpdatedAt; /** * @var string */ public $streamPosition; /** * @var int */ public $batchSize; } class paramsListOperation { /** * @var string * NOTE: listOperation should follow the following restrictions * You can have one of the following value * ADDTOLIST * ISMEMBEROFLIST * REMOVEFROMLIST */ public $listOperation; /** * @var (object)ListKey */ public $listKey; /** * @var (object)ArrayOfLeadKey */ public $listMemberList; /** * @var boolean */ public $strict; } class paramsRequestCampaign { /** * @var string * NOTE: source should follow the following restrictions * You can have one of the following value * MKTOWS * SALES */ public $source; /** * @var int */ public $campaignId; /** * @var (object)ArrayOfLeadKey */ public $leadList; } class paramsSyncLead { /** * @var (object)LeadRecord */ public $leadRecord; /** * @var boolean */ public $returnLead; /** * @var string */ public $marketoCookie; } class paramsSyncMultipleLeads { /** * @var (object)ArrayOfLeadRecord */ public $leadRecordList; /** * @var boolean */ public $dedupEnabled; } class successGetCampaignsForSource { /** * @var (object)ResultGetCampaignsForSource */ public $result; } class successGetLead { /** * @var (object)ResultGetLead */ public $result; } class successGetLeadActivity { /** * @var (object)LeadActivityList */ public $leadActivityList; } class successGetLeadChanges { /** * @var (object)ResultGetLeadChanges */ public $result; } class successGetMultipleLeads { /** * @var (object)ResultGetMultipleLeads */ public $result; } class successListOperation { /** * @var (object)ResultListOperation */ public $result; } class successRequestCampaign { /** * @var (object)ResultRequestCampaign */ public $result; } class successSyncLead { /** * @var (object)ResultSyncLead */ public $result; } class successSyncMultipleLeads { /** * @var (object)ResultSyncMultipleLeads */ public $result; } // define the class map class MktowsXmlSchema { // Do not change the indentation or line breaks below this comment. // For the curious, it helps with merging new changes from the WSDL code generator. static public $class_map = array( "ActivityRecord" => "ActivityRecord", "ActivityTypeFilter" => "ActivityTypeFilter", "Attribute" => "Attribute", "AuthenticationHeaderInfo" => "AuthenticationHeaderInfo", "CampaignRecord" => "CampaignRecord", "LeadActivityList" => "LeadActivityList", "LeadChangeRecord" => "LeadChangeRecord", "LeadKey" => "LeadKey", "LeadRecord" => "LeadRecord", "LeadStatus" => "LeadStatus", "ListKey" => "ListKey", "ResultGetCampaignsForSource" => "ResultGetCampaignsForSource", "ResultGetLead" => "ResultGetLead", "ResultGetLeadChanges" => "ResultGetLeadChanges", "ResultGetMultipleLeads" => "ResultGetMultipleLeads", "ResultListOperation" => "ResultListOperation", "ResultRequestCampaign" => "ResultRequestCampaign", "ResultSyncLead" => "ResultSyncLead", "ResultSyncMultipleLeads" => "ResultSyncMultipleLeads", "StreamPosition" => "StreamPosition", "SyncStatus" => "SyncStatus", "VersionedItem" => "VersionedItem", "ArrayOfActivityRecord" => "ArrayOfActivityRecord", "ArrayOfActivityType" => "ArrayOfActivityType", "ArrayOfAttribute" => "ArrayOfAttribute", "ArrayOfBase64Binary" => "ArrayOfBase64Binary", "ArrayOfCampaignRecord" => "ArrayOfCampaignRecord", "ArrayOfLeadChangeRecord" => "ArrayOfLeadChangeRecord", "ArrayOfLeadKey" => "ArrayOfLeadKey", "ArrayOfLeadRecord" => "ArrayOfLeadRecord", "ArrayOfLeadStatus" => "ArrayOfLeadStatus", "ArrayOfSyncStatus" => "ArrayOfSyncStatus", "ArrayOfVersionedItem" => "ArrayOfVersionedItem", "paramsGetCampaignsForSource" => "paramsGetCampaignsForSource", "paramsGetLead" => "paramsGetLead", "paramsGetLeadActivity" => "paramsGetLeadActivity", "paramsGetLeadChanges" => "paramsGetLeadChanges", "paramsGetMultipleLeads" => "paramsGetMultipleLeads", "paramsListOperation" => "paramsListOperation", "paramsRequestCampaign" => "paramsRequestCampaign", "paramsSyncLead" => "paramsSyncLead", "paramsSyncMultipleLeads" => "paramsSyncMultipleLeads", "successGetCampaignsForSource" => "successGetCampaignsForSource", "successGetLead" => "successGetLead", "successGetLeadActivity" => "successGetLeadActivity", "successGetLeadChanges" => "successGetLeadChanges", "successGetMultipleLeads" => "successGetMultipleLeads", "successListOperation" => "successListOperation", "successRequestCampaign" => "successRequestCampaign", "successSyncLead" => "successSyncLead", "successSyncMultipleLeads" => "successSyncMultipleLeads"); } /** * Client for Marketo SOAP API. * */ class MarketoAPI { // Change this vale to true to enable debug output. const DEBUG = false; const CLIENT_TZ = 'America/Toronto'; const MKTOWS_NAMESPACE = 'http://www.marketo.com/mktows/'; protected $accessKey; protected $secretKey; /** * @var SoapClient */ protected $soapClient; public function __construct($accessKey, $secretKey, $soapEndPoint) { $this->accessKey = $accessKey; $this->secretKey = $secretKey; $options = array("connection_timeout" => 20, "location" => $soapEndPoint); if (self::DEBUG) { $options["trace"] = true; } $wsdlUri = $soapEndPoint . '?WSDL'; $this->soapClient = new SoapClient($wsdlUri, $options); } private function _getAuthenticationHeader() { $dtzObj = new DateTimeZone(self::CLIENT_TZ); $dtObj = new DateTime('now', $dtzObj); $timestamp = $dtObj->format(DATE_W3C); //$timestamp = '2009-01-27T15:53'; $encryptString = $timestamp . $this->accessKey; $signature = hash_hmac('sha1', $encryptString, $this->secretKey); //echo "encrypt: $encryptString\n"; //echo "key: {this->secretKey}\n"; //echo "signature: $signature\n"; $attrs = new stdClass(); $attrs->mktowsUserId = $this->accessKey; $attrs->requestSignature = $signature; $attrs->requestTimestamp = $timestamp; $soapHdr = new SoapHeader(self::MKTOWS_NAMESPACE, 'AuthenticationHeader', $attrs); return $soapHdr; } public function getLead($keyType, $keyValue) { $retLead = null; $leadKey = new LeadKey(); $leadKey->keyType = $keyType; $leadKey->keyValue = $keyValue; $params = new paramsGetLead(); $params->leadKey = $leadKey; $options = array(); $authHdr = $this->_getAuthenticationHeader(); try { $success = $this->soapClient->__soapCall('getLead', array($params), $options, $authHdr); if (self::DEBUG) { $req = $this->soapClient->__getLastRequest(); echo "RAW request:\n$req\n"; $resp = $this->soapClient->__getLastResponse(); echo "RAW response:\n$resp\n"; } if (isset($success->result)) { if ($success->result->count > 1) { // Is this okay? If not, raise exception } if (isset($success->result->leadRecordList->leadRecord)) { $leadRecList = $success->result->leadRecordList->leadRecord; if (!is_array($leadRecList)) { $leadRecList = array($leadRecList); $count = count($leadRecList); if ($count > 0) { $retLead = $leadRecList[$count-1]; } } } } } catch (SoapFault $ex) { $ok = false; $errCode = 1; $faultCode = null; if (!empty($ex->detail->serviceException->code)) { $errCode = $ex->detail->serviceException->code; } if (!empty($ex->faultCode)) { $faultCode = $ex->faultCode; } switch ($errCode) { case mktWsError::ERR_LEAD_NOT_FOUND: $ok = true; $success = false; break; default: } if (!$ok) { if ($faultCode != null) { if (strpos($faultCode, 'Client')) { // This is a client error. Check the other codes and handle. } else if (strpos($faultCode, 'Server')) { // This is a server error. Call Marketo support with details. } else { // W3C spec has changed// But seriously, Call Marketo support with details. } } else { // Not a good place to be. } } } catch (Exception $ex) { $msg = $ex->getMessage(); $req = $this->soapClient->__getLastRequest(); echo "Error occurred for request: $msg\n$req\n"; var_dump($ex); exit(1); } return $retLead; } public function syncLead($key, $attrs) { // Build array of Attribute objects $attrArray = array(); foreach ($attrs as $attrName => $attrValue) { $a = new Attribute(); $a->attrName = $attrName; $a->attrValue = $attrValue; $attrArray[] = $a; } $aryOfAttr = new ArrayOfAttribute(); $aryOfAttr->attribute = $attrArray; // Build LeadRecord $leadRec = new LeadRecord(); $leadRec->leadAttributeList = $aryOfAttr; // Set the unique lead key. if (is_numeric($key)) { $leadRec->Id = $key; // Marketo system ID. } else { $leadRec->Email = $key; // TODO - Add email format validation - should be SMTP email address. } // Build API params $params = new paramsSyncLead(); $params->leadRecord = $leadRec; $params->returnLead = false; // Don't return the full lead record - just the ID. $options = array(); $authHdr = $this->_getAuthenticationHeader(); try { $success = $this->soapClient->__soapCall('syncLead', array($params), $options, $authHdr); $resp = $this->soapClient->__getLastResponse(); if (self::DEBUG) { $req = $this->soapClient->__getLastRequest(); echo "RAW request:\n$req\n"; $resp = $this->soapClient->__getLastResponse(); echo "RAW response:\n$resp\n"; } } catch (SoapFault $ex) { $ok = false; $errCode = 1; $faultCode = null; if (!empty($ex->detail->serviceException->code)) { $errCode = $ex->detail->serviceException->code; } if (!empty($ex->faultCode)) { $faultCode = $ex->faultCode; } switch ($errCode) { case mktWsError::ERR_LEAD_SYNC_FAILED: // Retry once and handle error if retry fails. break; default: } if (!$ok) { if ($faultCode != null) { if (strpos($faultCode, 'Client')) { // This is a client error. Check the other codes and handle. } else if (strpos($faultCode, 'Server')) { // This is a server error. Call Marketo support with details. } else { // W3C spec has changed
// But seriously, Call Marketo support with details. } } else { // Not a good place to be. } } } catch (Exception $ex) { $msg = $ex->getMessage(); $req = $this->soapClient->__getLastRequest(); echo "Error occurred for request: $msg\n$req\n"; var_dump($ex); exit(1); } return $success; } public function getCampaignsForSource() { $retList = null; $params = new paramsGetCampaignsForSource(); $params->source = 'MKTOWS'; // We want campaigns configured for access through the SOAP API $authHdr = $this->_getAuthenticationHeader(); $options = array(); try { $success = $this->soapClient->__soapCall('getCampaignsForSource', array($params), $options, $authHdr); if (self::DEBUG) { $req = $this->soapClient->__getLastRequest(); echo "RAW request:\n$req\n"; $resp = $this->soapClient->__getLastResponse(); echo "RAW response:\n$resp\n"; } if (isset($success->result->returnCount) && $success->result->returnCount > 0) { if (isset($success->result->campaignRecordList->campaignRecord)) { $retList = array(); // campaignRecordList is ArrayOfCampaignRecord from WSDL $campRecList = $success->result->campaignRecordList->campaignRecord; // Force to array when one 1 item is returned (quirk of PHP SOAP) if (!is_array($campRecList)) { $campRecList = array($campRecList); } // $campRec is CampaignRecord from WSDL foreach ($campRecList as $campRec) { $retList[$campRec->name] = $campRec->id; } } } } catch (SoapFault $ex) { if (self::DEBUG) { $req = $this->soapClient->__getLastRequest(); echo "RAW request:\n$req\n"; $resp = $this->soapClient->__getLastResponse(); echo "RAW response:\n$resp\n"; } $ok = false; $errCode = !empty($ex->detail->serviceException->code)? $ex->detail->serviceException->code : 1; $faultCode = !empty($ex->faultCode) ? $ex->faultCode : null; switch ($errCode) { case mktWsError::ERR_CAMP_NOT_FOUND: // Handle error for campaign not found break; default: // Handle other errors } if (!$ok) { if ($faultCode != null) { if (strpos($faultCode, 'Client')) { // This is a client error. Check the other codes and handle. } else if (strpos($faultCode, 'Server')) { // This is a server error. Call Marketo support with details. } else { // W3C spec has changed
// But seriously, Call Marketo support with details. } } else { // Not a good place to be. } } } catch (Exception $ex) { $msg = $ex->getMessage(); $req = $this->soapClient->__getLastRequest(); echo "Error occurred for request: $msg\n$req\n"; var_dump($ex); exit(1); } return $retList; } public function requestCampaign($campId, $leadEmail) { $retStat = false; $leadKey = new LeadKey(); $leadKey->keyType = 'IDNUM'; $leadKey->keyValue = $leadEmail; $leadList = new ArrayOfLeadKey(); $leadList->leadKey = array($leadKey); $params = new paramsRequestCampaign(); $params->campaignId = $campId; $params->leadList = $leadList; $params->source = 'MKTOWS'; $authHdr = $this->_getAuthenticationHeader(); try { $success = $this->soapClient->__soapCall('requestCampaign', array($params), $options, $authHdr); if (self::DEBUG) { $req = $this->soapClient->__getLastRequest(); echo "RAW request:\n$req\n"; $resp = $this->soapClient->__getLastResponse(); echo "RAW response:\n$resp\n"; } if (isset($success->result->success)) { $retStat = $success->result->success; } } catch (SoapFault $ex) { $ok = false; $errCode = !empty($ex->detail->serviceException->code)? $ex->detail->serviceException->code : 1; $faultCode = !empty($ex->faultCode) ? $ex->faultCode : null; switch ($errCode) { case mktWsError::ERR_LEAD_NOT_FOUND: // Handle error for campaign not found break; default: // Handle other errors } if (!$ok) { if ($faultCode != null) { if (strpos($faultCode, 'Client')) { // This is a client error. Check the other codes and handle. } else if (strpos($faultCode, 'Server')) { // This is a server error. Call Marketo support with details. } else { // W3C spec has changed
// But seriously, Call Marketo support with details. } } else { // Not a good place to be. } } } catch (Exception $ex) { $msg = $ex->getMessage(); $req = $this->soapClient->__getLastRequest(); echo "Error occurred for request: $msg\n$req\n"; var_dump($ex); exit(1); } return $retStat; } /** * Enter description here... * * @param string $leadEmail Lead email * @param string $listName Name of static list * @param string $sinceTimestamp Some valid PHP time string like 2009-12-25 01:00:00 * @param int $lastId ID of last activity */ public function wasLeadAddedToListSince($leadId, $listName, $sinceTimestamp, $lastId) { $wasAdded = false; $actRec = null; $leadKey = new LeadKey(); $leadKey->keyType = 'IDNUM'; $leadKey->keyValue = $leadId; $params = new paramsGetLeadActivity(); $params->leadKey = $leadKey; $actTypes = array(); $actTypes[] = 'AddToList'; $actArray = new ArrayOfActivityType(); $actArray->activityType = $actTypes; $filter = new ActivityTypeFilter(); $filter->includeTypes = $actArray; $params->activityFilter = $filter; $startPos = new StreamPosition(); $dtzObj = new DateTimeZone(self::CLIENT_TZ); // Use the correct time zone ! $dtObj = new DateTime($sinceTimestamp, $dtzObj); $startPos->oldestCreatedAt = $dtObj->format(DATE_W3C); $params->startPosition = $startPos; $params->batchSize = 100; $doPage = true; while($doPage) { $authHdr = $this->_getAuthenticationHeader(); try { $success = $this->soapClient->__soapCall('getLeadActivity', array($params), $options, $authHdr); if (self::DEBUG) { $req = $this->soapClient->__getLastRequest(); echo "RAW request:\n$req\n"; $resp = $this->soapClient->__getLastResponse(); echo "RAW response:\n$resp\n"; } if (isset($success->leadActivityList)) { // leadActivityList is LeadActivityList in WSDL $result = $success->leadActivityList; if ($result->returnCount > 0) { // actRecList is ArrayOfActivityRecord from WSDL $actRecList = $result->activityRecordList; // Force to array when one 1 item is returned (quirk of PHP SOAP) if (!is_array($actRecList)) { $actRecList = array($actRecList); } foreach ($actRecList as $actRec) { if ($actRec->id > $lastId && $actRec->mktgAssetName == $listName) { $wasAdded = true; break 2; } } $newStartPos = $success->leadActivityList->newStartPosition; $params->startPosition = $newStartPos; } else { $doPage = false; } } } catch (SoapFault $ex) { $doPage = false; $ok = false; $errCode = !empty($ex->detail->serviceException->code)? $ex->detail->serviceException->code : 1; $faultCode = !empty($ex->faultCode) ? $ex->faultCode : null; switch ($errCode) { case mktWsError::ERR_LEAD_NOT_FOUND: // Handle error for lead not found break; default: // Handle other errors } if (!$ok) { if ($faultCode != null) { if (strpos($faultCode, 'Client')) { // This is a client error. Check the other codes and handle. } else if (strpos($faultCode, 'Server')) { // This is a server error. Call Marketo support with details. } else { // W3C spec has changed
// But seriously, Call Marketo support with details. } } else { // Not a good place to be. } } break; } catch (Exception $ex) { $msg = $ex->getMessage(); $req = $this->soapClient->__getLastRequest(); echo "Error occurred for request: $msg\n$req\n"; var_dump($ex); exit(1); } } return array($wasAdded, $actRec); } } class mktWsError { const ERR_SEVERE_INTERNAL_ERROR = 10001; const ERR_INTERNAL_ERROR = 20011; const ERR_REQUEST_NOT_UNDERSTOOD = 20012; const ERR_ACCESS_DENIED = 20013; const ERR_AUTH_FAILED = 20014; const ERR_REQUEST_LIMIT_EXCEEDED = 20015; const ERR_REQ_EXPIRED = 20016; const ERR_INVALID_REQ = 20017; const ERR_BAD_ENCODING = 20018; const ERR_UNSUPPORTED_OP = 20019; const ERR_LEAD_KEY_REQ = 20101; const ERR_LEAD_KEY_BAD = 20102; const ERR_LEAD_NOT_FOUND = 20103; const ERR_LEAD_DETAIL_REQ = 20104; const ERR_LEAD_ATTRIB_BAD = 20105; const ERR_LEAD_SYNC_FAILED = 20106; const ERR_ACTIVITY_KEY_BAD = 20107; const ERR_PARAMETER_REQ = 20109; const ERR_PARAMETER_BAD = 20110; const ERR_LIST_NOT_FOUND = 20111; const ERR_CAMP_NOT_FOUND = 20113; const ERR_BAD_PARAMETER = 20114; const ERR_BAD_STREAM_POS = 20122; const ERR_STREAM_AT_END = 20123; }
Let me know how this works out for you.
Thanks for this! Do you know where in the code it returns the results from Marketo? When the form is submitted its printing out the info it gets back from marketo and want to be able to use that data somewhere else.
Thanks!
I am able to update records but for some reason am not able to add new records.
Thanks!
You’re welcome Corey. I just ran through a quick test and my leads are getting updated fine. For the data on the marketo side, the getLead function returns that data. If you do a print_r of the $cheakLead variable, you’ll notice it returns an object with an array of objects like below.
[Id] => 5679610
[Email] => contact@ahmeddirie.com
[ForeignSysPersonId] =>
[ForeignSysType] =>
[leadAttributeList] => stdClass Object
(
[attribute] => Array
(
[0] => stdClass Object
(
[attrName] => Company
[attrType] => string
[attrValue] => Test
)
I read that last comment wrong. I updated a record that I newly submitted, so I’m able to do both > create new records and update.
This is my submit code and for some reason I can not get it to submit a new lead for the life of me.
//Creating the array
$marketoArray = array(
‘Company’ => $_POST[‘Company’],
‘FirstName’ => $_POST[‘FirstName’],
‘LastName’ => $_POST[‘LastName’],
‘Email’ => $_POST[‘Email’],
‘Phone’ => $_POST[‘Phone’],
‘Country’ => $_POST[‘Country’],
‘ProductInterestedIn’ => $_POST[‘ProductInterestedIn’],
‘NumberOfEmployees’ => $_POST[‘NumberOfEmployees’],
‘Region’ => $_POST[‘Region’],
‘TypeOfCustomer’ => $_POST[‘TypeOfCustomer’],
‘ServiceToResell’ => $_POST[‘ServiceToResell’],
‘WhoAreYourClients’ => $_POST[‘WhoAreYourClients’],
‘Comments’ => $_POST[‘Comments’],
‘formid’ => $_POST[‘formid’],
‘form_type’ => $_POST[‘form_type’],
‘ListSource’ => ‘API’,
‘LeadSource’ => ‘API’
);
//Marketo SOAP PHP Client Class
require_once(‘marketo_api.php’);
require_once(“agile-forms.php”);
$marketo_user_id = ”;
$marketo_encryption_key = ”;
$marketo_soap_host = ”;
//Connecting to Marketo
$marketo_client = new MarketoAPI($marketo_user_id, $marketo_encryption_key, $marketo_soap_host);
//Checking for the existence of a lead
//If lead exists, setting the lead record and submit the lead to Marketo
$checkLead = $marketo_client->getLead(‘EMAIL’, $marketoArray[‘Email’]);
if ($checkLead == null) {
//This is a new lead
echo “New Lead! “;
$marketo_client->syncLead($marketoArray[‘Email’], $marketoArray);
} else {
//This is an existing lead
$leadId = $checkLead->Id;
$marketo_client->syncLead($leadId, $marketoArray);
}
//Adding the Lead to a campaign
$campaign_name = 1014;
//Getting List of Campaigns
$campaign_list = $marketo_client->getCampaignsForSource();
//Checking if out campaign is available in the list
if (empty($campaign_list[$campaign_name])) {
//No campaign found.
} else {
$campaign_id = $campaign_list[$campaign_name];
//Get Lead ID if new lead. Otherwise, add lead to campaign
if ($leadId) {
$marketo_client->requestCampaign($campaign_id, $leadId);
} else {
$getLead = $marketo_client->getLead(‘EMAIL’, $marketoArray[‘Email’]);
if ($checkLead != null) {
$leadId = $getLead->Id;
$marketo_client->requestCampaign($campaign_id, $leadId);
}
}
}
The marketo api file I copied directly from you. If you could help me with this that would be excellent!
We’re using the exact same code, but it is working for me. Do you get any error message? Check your error logs and see if you have anything there that can be of help. What’s interesting is that you are communicating properly with Marketo because you are able to update an existing lead – just not send one.
One other thing I notice is your campaign name variable is set to 1014. This should be the name of your smart campaign and if the function getCampaignsForSource finds it, it provides the id in the requestCampaign function.
The weird part is I got it working when it was the old code but the new code you provided is what is acting up.
I’m not sure what to tell you Corey. FYI, on line 993, change the debug value to false. I had it set to true during testing. I just updated that in the post.
I got it working thank you! Do you know if there is a way to pass the formid to the api?
That’s great news. I see you’re passing in “formid” in your marketo array. You just have to create that field in Marketo.
Thanks for all your help with everything! I was wondering if you might consider being a paid consultant during our Marketo implementation? If you are interested please send me an email at cshaw@dyn.com. I think you would be a great asset during this implementation as you already have been.
Thanks!
Hello again.
I have another question if you don’t mind. Have you set up or is it posibble to set up progressive profiling with the soap API?
Thanks!
Hi Corey,
There are many ways you can accomplish progressive profiling. Off the top, I think you can manage that with cookies, provided you have their email. This way, your can grab bits of information from the user and keep updating their record in Marketo. I’m guessing this is what you’re referring to?
Okay, pretty much what I am looking to do is when a new client comes to the site they fill out a basic form with basic info and it gets submitted to Marketo (this is currently working). When that same client comes back to fill out another form on the site id like the form to know it’s them based on their cookie data and then not show those basic fields again and this time show a different set of fields and so on for each time the client comes back to the site. Hopefully this makes sense. Any help, advice, or examples would be greatly appreciated!
Thanks!
Hi Corey,
I think there might be a simple way around this. You’ll be relying on storing a limited amount of data onto a cookie, e.g. id of the user – and cross reference that with previous form data the user submitted which you’ve stored on your database. On page load, check for the existence of the cookie, get user data and present the form with minimal fields (since you already have what you need). The post would just need to include the new fields and email which should fire off a lead update on Marketo. If cookie is deleted, well… you’ll have to decide what your process will be for that.
Hello,
Have another quick question for you. For some reason I can’t get the campaign name to work. This is what I have.
//Adding the Lead to a campaign
$campaign_name = “Campaign Test”;
Am I doing this right or is supposed to be the campaign ID instead?
Thanks!
Hello,
I’m trying to use the code exactly as you have it here to submit leads to Marketo, but nothing seems to be coming through.
I tried your suggestion of using print_r($checkLead); to see what it’s passing and it doesn’t return anything.
Is there an extra step needed other than is what is provided here?
Thanks!
Hi Corey,
As long as you know the ID of your campaign, you can just call the following line and skip the getCampaignsForSource()
$marketo_client->requestCampaign($campaign_id, $leadId);
Hi Ian,
Is there any more detail you can provide? Can you confirm that you are connected to the API? What fields are you passing in the array and do those fields match the API field names set in Marketo?
Hey Ahmed,
I honestly don’t know if i’m connected to the api or not. How exactly can you tell? I put in the user id, encryption key and soap end point and assumed that was everything that was required.
I had stripped your demo down here to try to figure out what was wrong, so was only trying to pass the email in from the array.
Thanks for the help
Your tutorial here is exactly what I have been tasked with. Unfortunately, the time frame is today or tomorrow. I am new to Marketo, and now this time crunch has left me a bit stressed. IF you can respond ASAP, I would greatly appreciate it.
Here’s my question. How do I upload the php documents in the tutorial to Marketo? Or is that not possible? Do they need to sit on my client’s server, and the Marketo system just refers to them?
Thanks,
I have been thinking about my previous post. I think I might have this all wrong. I am not supposed to load the api files into Marketo, but rather have them sit on my client’s (the company who wants the leads) server. Is that right? If that is the case, I don’t know if that is a viable solution. I want to query the marketo db to see if the user’s email in present, then take action based on that. Can you tell me how to do that? I really appreciate any help you can offer.
Hello,
How are you doing? I am in a bit of a snag again. I am using the new API that you have above and I am trying to associate the _mkto_trk cookie with the user that filled out of the form but am not having any luck. When I use getLead and query Marketo for my cookie it just brings back an anonymous lead from my computer browsing out site. Any idea how I might be able to associate these? Any advice would be excellent!
Thanks!
Hi JJ, I haven’t attempted that yet. I’ll let you know if I come across this.
Hi Corey,
I’m you can pass in the cookie as key/value in the getLead function and should be similar for syncLead. I’m going to rewrite this class at some point and just focus on the important bits.
There’s a class that benubois wrote for Marketo that is phenomenal, scaled down, and works amazing in comparison to the sample class provided by Marketo. I suggest taking a look at it.
https://github.com/flickerbox/marketo
Would it be possible to integrate this into wordpress? If so, would the files be called in the function.php or the header.php?
Hi Halben,
Personally, I think including it in your function.php would be better than the header file, so that it can be triggered when a certain event occurs (like the submission of a form). As for integration, are you writing your own contact form plugin? If so, you can tie it into that.
Correct me if I’m wrong, I’m using the child theme’s function.php and calling the file from a folder named “marketo” in the child theme.
Would I be making the marketo call like this:
// marketo call
require_once(get_stylesheet_directory() . ‘/marketo/marketo_post.php’);
Will it still run if I add the following into marketo_post.php:
Thanks,
halben
Here is the market_post.php file:
$marketoArray = array ( … array items…);
function marketo_submit_lead($marketoArray)
{
… stuff goes here…
}
if (isset($_POST[‘wp-submit’]))
marketo_submit_lead($marketoArray);
Hello,
I managed to get a successful connection. I have one quick question if you can point me to the right direction.
How would I check when there’s an update made to a lead in the marketo database?
Hello Ahmed,
Can you please look at my code? I’m trying to see if the SFDC type in the mkto DB matches is equal to its drop down value, Consultant. I just want to make sure I’m on the right path. Thanks.
$mkto_array = array(‘SFDCAccountType’ => ‘Consultant’, ‘Email’ => $email_acc);
try {
require_once(‘/include/mkto.php’);
// mkto info goes here & the new client object ….
//check for an existing lead
$leadExist = $mkto_client -> getLead(‘EMAIL’, $mkto_array[‘Email’]);
if ($leadExist != null) {
$leadID = $leadExist -> ID;
$mkto_client -> getLead($leadID, $mkto_array[‘SFDCAccountType’]);
if ($mkto_array[‘SFDCAccountType’] == ‘Consultant’) {
// we check if the SFDCAccountType is equal to Consultant, if so do some stuff here
}
} else {
// Do nothing, exit
exit ;
}
// Do nothing, exit
exit ;
}
Hi Halben,
Your code looks right. I don’t see any issues with the check on SFDC type.
Hello,
Thanks for all your help before, everything is working great! I have noticed that using forms via the API don’t show up as a “landing page” in Marketo. The marketing team is requesting this just for the reporting aspect. Do you know if there is anyway either by code or in Marketo to essentially “register” a custom API form as a landing page so that Marketo recognizes it and can properly use it?
If you have any advice id greatly appreciate it!
Thanks!
Hi Corey,
Thanks for your kind words. For registering a page as a landing page, this is something I haven’t looked into. You might find something about it in the Marketo Enterprise API Design doc, or it could be something simple in the admin area. Best of luck with that. Sorry I couldn’t help.
Hi Ahmed,
I just want to drop by and say thanks a lot for your example. It really helped me out.
Just one quick question if you could please answer regarding to this line of code: $marketo_client = new MarketoAPI…
Is “MarketoAPI” part of the marketo api functions or just a made up name that stores the 3 args?
I have created couple of smart campaigns in marketo but ‘getCampaignsForSource’ return empty. Is there anyway to solve this? I can post leads without any problem though. Thanks in advance
Sorry, My bad I have to activate trigger ‘Campaign is Requested’ . Didn’t activated that. Thats why it didnt showed any Campaigns. Thanks for such a simple and nice guide. Saved my time alot.
Hi Cel, I’m glad it helped you out.
Hi,
This is my leadrec
LeadRecord Object
(
[Id] =>
[Email] =>
[leadAttributeList] => ArrayOfAttribute Object
(
[attribute] => Array
(
[0] => Attribute Object
(
[attrName] => FirstName
[attrType] =>
[attrValue] => Shahid
)
[1] => Attribute Object
(
[attrName] => LastName
[attrType] =>
[attrValue] => Hussain
)
[2] => Attribute Object
(
[attrName] => Email
[attrType] =>
[attrValue] => testing@testing.com
)
)
)
[ForeignSysPersonId] => 101
[ForeignSysType] => CUSTOM
)
but after submitting lead, ForeignSysPersonId and ForeignSysType are blank in getlead call. Any idea what am i doing wrong?
Thanks for the awesome tutorial! It works like a charm!
There’s a bug in your marketo.php code on line 1088 and 1788. Shouldn’y $faultCode == null; should be $faultCode = null; ?
Also, I want to add leads to Marketo with your wonderful code through WordPress. Do you know how to do this?
Hi Yaniv,
Thanks for catching that. I’ve updated that here and will shoot a message over to Marketo to have them update that on their end as well. Haven’t done this for WordPress though. Are you adding a form on a page or doing this through comments?
Hi Ahmed,
A good Tutorial I must say!!
First , I have knowledge in javascript and jquery only.
I am new to this SOAP API concept. Can you kindly tell me the instructions to be done by me in my marketo sandbox:
Any help would be really appreciated.
Best
Faizal Reza
Hello,
Thank you for your indeed helpful tutorial.
I wonder how would I get marketo.php SOAP Client API (from marketo official website/repo)? I tried marketo official github repo but could not find one for php
Thank You
How do I get this to work with the Marketo Munchin cookie script? I’ve set it up on my site, but this code doesn’t send the info from the cookie to Marketo. Thanks.
Thank you for providing this sample! I have noticed an error in the Marketo class though – on line 1178 where it says $faultCode == null;
should be
$faultCode = null;
Thanks for catching that Steve. Not sure how that came back though, considering it was removed in March after Yaniv noticed it.
Thank you for this. Beginner trying to navigate this stuff and this has been the most helpful post. thank you thank you.
Thanks for this article Ahmed!
One quick question, I’m having no problem creating new leads, however I can’t quite figure out how to pass in the cookie with this new code. Any tips? Thanks
Hi Ahmed,
Thanks for sharing this great article. I have facing one problem. I want to add this lead to one of my Group List Created. How can i do this. How should I pass List Name to api so that lead also get stored in specified list
Thanks