You can retrieve information about customers and prospects that are stored within Marketo using the getLead and getMultipleLeads SOAP API. It is often desired to extract this information on a recurring basis to keep another system updated as customers and prospect information is updated or new records are created in Marketo.
We’ll show you the code sample that would be executed on a recurring basis to poll Marketo for updates.
The below diagram depicts the API calls that are made on a set periodic timer. Depending on the use case, the periodic timer could be set to run the below code every 10 minutes.
The first call to getMultipleLeads will set the time range, batchSize and which fields are to be returned. All leads within Marketo that were updated in the specified time range will be returned along with a streamPosition when more records are available than the batchSize specified.
SOAP Request for first call to getMultipleLeads:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
<?xml version="1.0" encoding="UTF-8"?> <ns2:paramsGetMultipleLeads xmlns:ns2="http://www.marketo.com/mktows/"> <leadSelector xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="ns2:LastUpdateAtSelector"> <latestUpdatedAt>2014-02-13T11:51:08.710-08:00</latestUpdatedAt> <oldestUpdatedAt>2014-02-12T11:51:08.713-08:00</oldestUpdatedAt> </leadSelector> <batchSize>2</batchSize> <includeAttributes> <stringItem>FirstName</stringItem> <stringItem>LastName</stringItem> <stringItem>Email</stringItem> </includeAttributes> </ns2:paramsGetMultipleLeads> |
SOAP Response from the first call to getMultipleLeads:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 |
<?xml version="1.0" encoding="UTF-8"?> <ns2:successGetMultipleLeads xmlns:ns2="http://www.marketo.com/mktows/"> <result> <returnCount>2</returnCount><remainingCount>24</remainingCount><newStreamPosition>id:1089965:to:1392234668:tl:1392321068:os:2:rc:24</newStreamPosition><leadRecordList> <leadRecord> <Id>84105</Id> <Email>eimang@marketo.com</Email> <ForeignSysPersonId xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:nil="true" /> <ForeignSysType xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:nil="true" /> <leadAttributeList xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:nil="true"> <attribute> <attrName>FirstName</attrName> <attrType>string</attrType> <attrValue>French</attrValue> </attribute> <attribute> <attrName>LastName</attrName> <attrType>string</attrType> <attrValue>Lead</attrValue> </attribute> </leadAttributeList> </leadRecord> <leadRecord> <Id>1089965</Id> <Email>t@t.com</Email> <ForeignSysPersonId xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:nil="true" /> <ForeignSysType xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:nil="true" /> <leadAttributeList xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:nil="true"> <attribute> <attrName>FirstName</attrName> <attrType>string</attrType> <attrValue>George</attrValue> </attribute> <attribute> <attrName>LastName</attrName> <attrType>string</attrType> <attrValue>of the Jungle</attrValue> </attribute> </leadAttributeList> </leadRecord> </leadRecordList> </result> </ns2:successGetMultipleLeads> |
As long as the <remainingCount/> value is greater than 0, you will make subsequent calls to getMultipleLeads to paginate through the rest by passing the <newStreamPosition/> value returned in the previous call into the <streamPosition/> parameter.
SOAP Request for subsequent call to getMultipleLeads:
1 2 3 4 5 6 7 8 9 10 11 12 |
<?xml version="1.0" encoding="UTF-8"?> <ns2:paramsGetMultipleLeads xmlns:ns2="http://www.marketo.com/mktows/"> <leadSelector xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="ns2:LastUpdateAtSelector"> <latestUpdatedAt>2014-02-13T11:51:08.710-08:00</latestUpdatedAt> <oldestUpdatedAt>2014-02-12T11:51:08.713-08:00</oldestUpdatedAt> </leadSelector><streamPosition>id:1089965:to:1392234668:tl:1392321068:os:2:rc:24</streamPosition><batchSize>2</batchSize> <includeAttributes> <stringItem>FirstName</stringItem> <stringItem>LastName</stringItem> <stringItem>Email</stringItem> </includeAttributes> </ns2:paramsGetMultipleLeads> |
This logic will continue as long as <remainingCount/> is greater than zero.
See below a sample Java program that executes the scenario described above.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 |
import com.marketo.mktows.*; import java.net.URL; import javax.xml.namespace.QName; import java.text.DateFormat; import java.text.SimpleDateFormat; import java.util.Date; import java.util.GregorianCalendar; import javax.crypto.Mac; import javax.crypto.spec.SecretKeySpec; import org.apache.commons.codec.binary.Hex; import javax.xml.bind.JAXBContext; import javax.xml.bind.JAXBElement; import javax.xml.bind.Marshaller; import javax.xml.datatype.DatatypeFactory; import javax.xml.datatype.XMLGregorianCalendar; public class GetMultipleLeads { public static void main(String[] args) { System.out.println("Executing GetMultipleLeads"); try { URL marketoSoapEndPoint = new URL("CHANGE ME" + "?WSDL"); String marketoUserId = "CHANGE ME"; String marketoSecretKey = "CHANGE ME"; QName serviceName = new QName("http://www.marketo.com/mktows/", "MktMktowsApiService"); MktMktowsApiService service = new MktMktowsApiService(marketoSoapEndPoint, serviceName); MktowsPort port = service.getMktowsApiSoapPort(); // Create Signature DateFormat df = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ"); String text = df.format(new Date()); String requestTimestamp = text.substring(0, 22) + ":" + text.substring(22); String encryptString = requestTimestamp + marketoUserId ; SecretKeySpec secretKey = new SecretKeySpec(marketoSecretKey.getBytes(), "HmacSHA1"); Mac mac = Mac.getInstance("HmacSHA1"); mac.init(secretKey); byte[] rawHmac = mac.doFinal(encryptString.getBytes()); char[] hexChars = Hex.encodeHex(rawHmac); String signature = new String(hexChars); // Set Authentication Header AuthenticationHeader header = new AuthenticationHeader(); header.setMktowsUserId(marketoUserId); header.setRequestTimestamp(requestTimestamp); header.setRequestSignature(signature); // Create Request ParamsGetMultipleLeads request = new ParamsGetMultipleLeads(); // Build Request Using LastUpdateAtSelector LastUpdateAtSelector leadSelector = new LastUpdateAtSelector(); GregorianCalendar gc = new GregorianCalendar(); gc.setTimeInMillis(new Date().getTime()); gc.add( GregorianCalendar.DAY_OF_YEAR, -20); DatatypeFactory factory = DatatypeFactory.newInstance(); ObjectFactory objectFactory = new ObjectFactory(); JAXBElement<XMLGregorianCalendar> until = objectFactory.createLastUpdateAtSelectorLatestUpdatedAt(factory.newXMLGregorianCalendar(gc)); GregorianCalendar since = new GregorianCalendar(); since.setTimeInMillis(new Date().getTime()); since.add( GregorianCalendar.DAY_OF_YEAR, -21); leadSelector.setOldestUpdatedAt(factory.newXMLGregorianCalendar(since)); leadSelector.setLatestUpdatedAt(until); request.setLeadSelector(leadSelector); ArrayOfString attributes = new ArrayOfString(); attributes.getStringItems().add("FirstName"); attributes.getStringItems().add("LastName"); attributes.getStringItems().add("Email"); request.setIncludeAttributes(attributes); JAXBElement<Integer> batchSize = new ObjectFactory().createParamsGetMultipleLeadsBatchSize(2); request.setBatchSize(batchSize); SuccessGetMultipleLeads result = null; int count = 0; do { if (count > 0) { // Set the streamPosition on subsequent calls to paginate through large result sets String pos = result.getResult().getNewStreamPosition(); JAXBElement<String> streamPos = new ObjectFactory().createParamsGetMultipleLeadsStreamPosition(pos); request.setStreamPosition(streamPos); } JAXBContext context = JAXBContext.newInstance(ParamsGetMultipleLeads.class); Marshaller m = context.createMarshaller(); m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true); System.out.println("REQUEST:"); m.marshal(request, System.out); result = port.getMultipleLeads(request, header); System.out.println("RESPONSE:"); m.marshal(result, System.out); count = result.getResult().getReturnCount(); } while (result.getResult().getRemainingCount() > 0); } catch(Exception e) { // Update to include appropriate retry/error handling e.printStackTrace(); } } } |
Tips & Tricks:
When extracting large volumes of contacts out of Marketo it is recommended to tune the API request along the following parameters:
- <includeAttributes/>: It is recommended that you only request those fields you are interested in keeping in sync with your system. This reduces the payload of the response and increases query performance.
- <batchSize/>: The API supports up to 1000 records to be returned in a single call. Tuning this value down to 500 records also reduces the payload of the response.
- <LastUpdatedAtSelector/>: It is recommended to set both the <oldestUpdatedAt/> along with the <latestUpdatedAt/> pararameter to limit the date range. For example, instead of making a single request for a year’s worth of data. Break up the API calls to request smaller date ranges.
* This article contains code used to implement custom integrations. Due to its customized nature, The Marketo Technical Support team is unable to troubleshoot custom work. Please do not attempt to implement the following code sample without appropriate technical experience, or access to an experienced developer.