├── .gitignore
├── .travis.yml
├── LICENSE.txt
├── README
├── README.md
├── marketorestpython
├── __init__.py
├── client.py
└── helper
│ ├── __init__.py
│ ├── exceptions.py
│ └── http_lib.py
├── python-logo-master-v3-TM.png
├── requirements-tests.txt
├── requirements.txt
├── setup.cfg
├── setup.py
├── test_script.py
└── tests
└── tst_client.py
/.gitignore:
--------------------------------------------------------------------------------
1 | *.egg-info
2 | *.cache
3 | *.pyc
4 | conf.json
5 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: python
2 | python:
3 | - '2.7'
4 | - '3.6'
5 | install:
6 | - pip install -r requirements.txt
7 | - pip install -r requirements-tests.txt
8 | script:
9 | - pytest
10 | env:
11 | global:
12 | - secure: kZ28wlnnWAydcbCvgVlYYE5CKjY8WVdfcAovgVwy/Stb66tOUqnUIR5mTtvTXSj2duHFQHHnCSccO9mBMfBN0/E3jYBAKWo95TModXO/jfw1Yan5gL0A+aytarkMHhzPNlNxFVIiy+UEAFT/UzxFyPIbl3ObHs7yBcmDBujclwZD33ekipx4ezhePUfLMfAL2BKyDwwb+OoNuVbyGsc26DgwUfwtL0hTJMFqytvCNozTZQgsZp5e1CkUt//fTzFTxgziisdo8KrztSYNZnwtqLnmjKLkBy6x/psHEebCsqqW86yCLPHpvIHoSuE8wFXjkOaDOn4pSizwd523OItwvREVOXa9NBLE7TKVV28fx40YtSUquGkMlt0RmxI1d4GtEljVHb1awCTbl2qbG2RxXYm5Ahq4Lc6vR0lrU3oFCYgIg1RtZIo+fmfgR8mX8tVD+YwNjpkTkM/QNphfri0FKjyxCgkTTdza2kOQBQI96KhB7CBwrmV74J9KZ3T4C3zoo9LIpJf1flm2mrxsXI1qutRj4sK7vFiI5tA5WhpH2R2s8oGA15HB10Sfe1U88DOetKcWHw2UEwPqri3MpnMOJCoMdJz9NTOAeMWYoZ8IFiE/6y2E+i0f2qthg69J3XVpWgQf79MXgcQDeGHrgBMZw2KD7X+ehkeAKZ7uoRCq/h8=
13 | - secure: NMh2peEEzn9UPVoyvhPEHCSVoSQSwzOnEUa5MQd85u01XM4yPEiePzbwiTBHl3gL0tJe+o8C2CALAkFUUqhJ2N8gWsNj9MlwvWmEtSUDT72Vtt47g84nLVXO5P+UE+Weak/Skiv9RNBqR1YOEgGScQM03XMjZwNBlVHfPleNEgsMg298ZUf0EtBHZSN5qhIfPWLLa9nKHNq+vogluUl0LGN2zqMRCcKiWiiWXtFdKQ3omxocsLD/GoTbOwlcdmUZkUK9AMp0o+85Jgbn9BZYnFLQacoBOhm4FOiYczbjvdBcw1uFNcbIx7Iswci72CKl5LNHDJaeIirrJ/xnmMWyFtQPrro8DJ/dvrAvm8sLaCtmEZinakP/wX/WwtHKWg07SVt6rOBYf9WkDS3/dS90br7OnTTc1MxgRhfZLENerpmDs8dyFLsY2WF2bol3vBiuvRDu/kTOP1SXrxD6PQUAw1vtzG7R470EgyWg4Xs3kwBeQ667mV12fGiSDv7hohv5Mgme7y0TTlt/HRQ3JvUN2Ftg4l1BOJcaj/TJi4KdLLenjh+mP3Ind3vZqVn4Dw/1IBepehjcRF8ZtB7ZhTXQCcehaSBijASEAVmlSgd4zwuLruxtA5d0QwWG5QBe/k/Skyg4/PeSklWISZEBzgcQ33qhaNa6ECpiqhpklomQK/k=
14 | - MUNCHKIN_ID=874-MZK-132
15 |
--------------------------------------------------------------------------------
/LICENSE.txt:
--------------------------------------------------------------------------------
1 | (The MIT License)
2 |
3 | Copyright (c) 2015 Arunim Samat, Jep Castelein
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining
6 | a copy of this software and associated documentation files (the
7 | "Software"), to deal in the Software without restriction, including
8 | without limitation the rights to use, copy, modify, merge, publish,
9 | distribute, sublicense, and/or sell copies of the Software, and to
10 | permit persons to whom the Software is furnished to do so, subject to
11 | the following conditions:
12 |
13 | The above copyright notice and this permission notice shall be
14 | included in all copies or substantial portions of the Software.
15 |
16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23 |
--------------------------------------------------------------------------------
/README:
--------------------------------------------------------------------------------
1 | This package provides a wrapper to the Marketo REST API,
2 | currently only get leads,update/create leads api are supported.
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | Marketo REST Python
2 | ===================
3 | Python Client that covers most of the Marketo REST API. It handles authentication, error handling and rate limiting
4 | to the standard limit of 100 calls in 20 seconds (defined in http_lib module). This is a fork of the project started by
5 | Arunim Samat at https://github.com/asamat/python_marketo, which had stalled.
6 |
7 | Full Marketo REST API documentation - http://developers.marketo.com/documentation/rest/
8 |
9 | Installation
10 | ============
11 |
12 | `pip install marketorestpython`
13 |
14 | Unit tests
15 | ==========
16 | [](https://travis-ci.org/jepcastelein/marketo-rest-python)
17 |
18 | See tests in `test_script.py` and see `.travis.yml` for automated
19 | testing setup. Travis does not test pull requests.
20 |
21 | To test locally, create a local file `conf.json` and enter your Marketo credentials and
22 | type `pytest` on the command line:
23 | ```json
24 | {
25 | "munchkin_id": "",
26 | "client_id": "",
27 | "client_secret": ""
28 | }
29 | ```
30 | This runs `test_script.py`. It will automatically create and delete Person records and Assets
31 | in Marketo (self-contained). It is recommended to only run it on a sandbox instance.
32 |
33 | Usage
34 | =====
35 | ```python
36 | from marketorestpython.client import MarketoClient
37 | munchkin_id = "" # fill in Munchkin ID, typical format 000-AAA-000
38 | client_id = "" # enter Client ID from Admin > LaunchPoint > View Details
39 | client_secret= "" # enter Client ID and Secret from Admin > LaunchPoint > View Details
40 | api_limit=None
41 | max_retry_time=None
42 | requests_timeout=(3.0, 10.0)
43 | mc = MarketoClient(munchkin_id, client_id, client_secret, api_limit, max_retry_time, requests_timeout=requests_timeout)
44 |
45 | # 'api_limit' and 'max_retry_time' are optional;
46 | # 'api_limit' limits the number of Marketo API calls made by this instance of MarketoClient
47 | # 'max_retry_time' defaults to 300 and sets the time in seconds to retry failed API calls that
48 | # are retryable; if it still fails after the configured time period, it will throw a
49 | # MarketoException
50 | # 'requests_timeout' can be an int, float, or tuple of ints or floats to pass as a timeout
51 | # argument to calls made by the requests library. Defaults to None, i.e., no timeout.
52 | # See requests docs for more info: http://docs.python-requests.org/en/master/user/advanced/
53 | ```
54 | Then use mc.execute(method='') to call the various methods (see documentation below)
55 |
56 | For very specific use cases where you only have the access_token, you can also pass that in directly; you are then
57 | responsible for requesting the initial access_token and renewing it when it expires.
58 | ```python
59 | from marketorestpython.client import MarketoClient
60 | munchkin_id = "" # fill in Munchkin ID, typical format 000-AAA-000
61 | access_token = "" # enter access_token
62 | mc = MarketoClient(munchkin_id, access_token=access_token)
63 | ```
64 |
65 |
66 | Lead, List, Activity and Campaign Objects
67 | =========================================
68 |
69 | Get Lead by Id
70 | --------------
71 | API Ref: http://developers.marketo.com/documentation/rest/get-lead-by-id/
72 | ```python
73 | lead = mc.execute(method='get_lead_by_id', id=3482141, fields=['firstName', 'middleName', 'lastName', 'department'])
74 |
75 | # fields is optional
76 | ```
77 |
78 | Get Multiple Leads by Filter Type
79 | ---------------------------------
80 | API Ref: http://developers.marketo.com/documentation/rest/get-multiple-leads-by-filter-type/
81 | ```python
82 | lead = mc.execute(method='get_multiple_leads_by_filter_type', filterType='email', filterValues=['a@b.com','c@d.com'],
83 | fields=['firstName', 'middleName', 'lastName'], batchSize=None)
84 |
85 | # fields and batchSize are optional
86 | # max 100 filterValues
87 | # max 1000 results, otherwise you'll get error 1003 ('Too many results match the filter')
88 | ```
89 |
90 | Get Multiple Leads by List Id
91 | -----------------------------
92 | API Ref: http://developers.marketo.com/documentation/rest/get-multiple-leads-by-list-id/
93 | ```python
94 | mc.execute(method='get_multiple_leads_by_list_id', listId='676',
95 | fields=['email','firstName','lastName','company','postalCode'], batchSize=None)
96 |
97 | # fields and batchSize are optional
98 | # static lists only (does not work with smart lists)
99 | ```
100 |
101 | Get Multiple Leads by List Id Yield (Generator)
102 | -----------------------------------------------
103 | API Ref: http://developers.marketo.com/documentation/rest/get-multiple-leads-by-list-id/
104 | ```python
105 | for leads in mc.execute(method='get_multiple_leads_by_list_id_yield', listId='676',
106 | fields=['email','firstName','lastName'], batchSize=None, return_full_result=False):
107 | print(len(leads))
108 |
109 | # OR:
110 |
111 | leads = mc.execute(method='get_multiple_leads_by_list_id_yield', listId='676',
112 | fields=['email','firstName','lastName'], batchSize=None, return_full_result=False)
113 | lead_chunk = next(leads) # keep calling next until no more Leads
114 |
115 | # this is a generator, so it will return chunks of Leads rather that all Leads on the
116 | # List at once; therefore, it's useful for Lists with large numbers of Leads
117 | # fields and batchSize are optional; batchSize defaults to 300, which is the max
118 | # set return_full_result to True to get the nextPageToken and requestId returned; actual
119 | # result will be in the 'result' key
120 | # static lists only (does not work with smart lists)
121 | ```
122 |
123 | Get Multiple Leads by Program Id
124 | --------------------------------
125 | API Ref: http://developers.marketo.com/documentation/rest/get-multiple-leads-by-program-id/
126 | ```python
127 | mc.execute(method='get_multiple_leads_by_program_id', programId='1014',
128 | fields=['email','firstName','lastName','company','postalCode'], batchSize=None)
129 |
130 | # fields and batchSize are optional
131 | ```
132 |
133 | Get Multiple Leads by Program Id Yield (Generator)
134 | --------------------------------------------------
135 | API Ref: http://developers.marketo.com/documentation/rest/get-multiple-leads-by-program-id/
136 | ```python
137 | for leads in mc.execute(method='get_multiple_leads_by_program_id_yield', programId='1014',
138 | fields=['email','firstName','lastName','company','postalCode'], batchSize=None):
139 | print(len(leads))
140 |
141 | # this is a generator, so it will return chunks of Leads rather that all Program Members
142 | # at once; therefore, it's useful for Programs with large numbers of Members
143 | # fields and batchSize are optional
144 | ```
145 |
146 |
147 | Change Lead Program Status
148 | --------------------------
149 | API Ref: http://developers.marketo.com/documentation/rest/change-lead-program-status/
150 | ```python
151 | status = mc.execute(method = 'change_lead_program_status', id=1097, leadIds=[51,10,11,24], status="Registered")
152 | ```
153 |
154 | Create/Update Leads
155 | -------------------
156 | API Ref: http://developers.marketo.com/documentation/rest/createupdate-leads/
157 | ```python
158 | leads = [{"email":"joe@example.com","firstName":"Joe"},{"email":"jill@example.com","firstName":"Jill"}]
159 | lead = mc.execute(method='create_update_leads', leads=leads, action='createOnly', lookupField='email',
160 | asyncProcessing='false', partitionName='Default')
161 |
162 | # action, lookupField and asyncProcessing are optional (defaults are 'email' and 'false')
163 | # action can be "createOrUpdate" (default if omitted), "createOnly", "updateOnly" or "createDuplicate"
164 | # partitionName is required if Marketo instance has more than 1 Lead Partition
165 | # max batch size is 300
166 | ```
167 |
168 | Associate Lead
169 | --------------
170 | API Ref: http://developers.marketo.com/documentation/rest/associate-lead/
171 | ```python
172 | lead = mc.execute(method='associate_lead', id=2234, cookie='id:287-GTJ-838%26token:_mch-marketo.com-1396310362214-46169')
173 | ```
174 |
175 | Push Lead
176 | ---------
177 | API Ref: http://developers.marketo.com/rest-api/endpoint-reference/lead-database-endpoint-reference/#!/Leads/pushToMarketoUsingPOST
178 | ```python
179 | leads = [
180 | {"email":"lead1@example.com","firstName":"Joe", "cookies":"id:662-XAB-092&token:_mch-castelein.net-1487035251303-23757"},
181 | {"email":"lead2@example.com","firstName":"Jillian"}
182 | ]
183 | lead = mc.execute(method='push_lead', leads=leads, lookupField='email', programName='Big Launch Webinar',
184 | programStatus='Registered', source='example source', reason='example reason')
185 |
186 | # leads, lookupField and programName are required
187 | # all others are optional
188 | # to associate Cookie ID, put it in a field called 'cookies' (see example above)
189 | # to associate mkt_tok, put it in a field called 'mktToken' (see http://developers.marketo.com/rest-api/lead-database/leads/#push_lead_to_marketo)
190 | ```
191 |
192 | Submit Form
193 | ------------
194 | API docs: https://developers.marketo.com/rest-api/lead-database/leads/#submit_form
195 | ```python
196 | input = {
197 | "leadFormFields":{
198 | "firstName":"Marge",
199 | "lastName":"Simpson",
200 | "email":"marge.simpson@fox.com",
201 | "pMCFField":"PMCF value"
202 | },
203 | "visitorData":{
204 | "pageURL":"https://na-sjst.marketo.com/lp/063-GJP-217/UnsubscribePage.html",
205 | "queryString":"Unsubscribed=yes",
206 | "leadClientIpAddress":"192.150.22.5",
207 | "userAgentString":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/84.0.4147.89 Safari/537.36"
208 | },
209 | "cookie":"id:063-GJP-217&token:_mch-marketo.com-1594662481190-60776"
210 | }
211 | response = mc.execute(method='submit_form', formId=1029, input=input)
212 |
213 | # please note that `input` doesn't need to contain a list, the method does that.
214 | ```
215 |
216 | Merge Lead
217 | ----------
218 | API Ref: http://developers.marketo.com/documentation/rest/merge-lead/
219 | ```python
220 | lead = mc.execute(method='merge_lead', id=3482183, leadIds=[3482182], mergeInCRM=False)
221 |
222 | # mergeInCRM is optional (default is False)
223 | # returns True if successful
224 | ```
225 |
226 | Get Smart Campaigns by Lead ID
227 | ------------------------------
228 | API Ref: https://developers.marketo.com/rest-api/endpoint-reference/lead-database-endpoint-reference/#!/Leads/getSmartCampaignMembershipUsingGET
229 | ```python
230 | results = mc.execute(method='get_smart_campaigns_by_lead_id', lead_id=39881)
231 | ```
232 |
233 | Get Lead Partitions
234 | -------------------
235 | API Ref: http://developers.marketo.com/documentation/rest/get-lead-partitions/
236 | ```python
237 | lead = mc.execute(method='get_lead_partitions')
238 | ```
239 |
240 | Add Leads to List
241 | -----------------
242 | API Ref: http://developers.marketo.com/documentation/rest/add-leads-to-list/
243 | ```python
244 | lead = mc.execute(method='add_leads_to_list', listId=1, id=[1,2,3])
245 |
246 | # max batch size is 300
247 | ```
248 |
249 | Remove Leads from List
250 | ----------------------
251 | API Ref: http://developers.marketo.com/documentation/rest/remove-leads-from-list/
252 | ```python
253 | lead = mc.execute(method='remove_leads_from_list', listId=1, id=[1,2,3])
254 |
255 | # max batch size is 300
256 | ```
257 |
258 | Member of List
259 | --------------
260 | API Ref: http://developers.marketo.com/documentation/rest/member-of-list/
261 | ```python
262 | lead = mc.execute(method='member_of_list', listId=728, id=[3482093,3482095,3482096])
263 | ```
264 |
265 | Import Lead
266 | -----------
267 | API Ref: http://developers.marketo.com/documentation/rest/import-lead/
268 | ```python
269 | lead = mc.execute(method='import_lead', file='../folder/test.csv', format='csv', lookupField='email', listId=None, partitionName='Default')
270 |
271 | # lookupField and listId are optional. Email is the default for lookupField.
272 | # partitionName is required when the Marketo instance has more than 1 Lead Partition
273 | ```
274 |
275 | Get Import Lead Status
276 | ----------------------
277 | API Ref: http://developers.marketo.com/documentation/rest/get-import-lead-status/
278 | ```python
279 | lead = mc.execute(method='get_import_lead_status', id=900)
280 |
281 | # specify the batchId that is returned in 'Import Lead'
282 | ```
283 |
284 | Get Import Failure File
285 | -----------------------
286 | API Ref: http://developers.marketo.com/documentation/rest/get-import-failure-file/
287 | ```python
288 | batch_id = 899
289 | failed_leads = mc.execute(method='get_import_failure_file', id=batch_id)
290 | file_name = "import-failure-for-batch-" + str(batch_id) + ".csv"
291 | if failed_leads is not '':
292 | f = open(file_name, encoding='utf-8', mode='w')
293 | f.write(failed_leads)
294 | f.close()
295 |
296 | # specify the batchId that is returned in 'Import Lead'
297 | ```
298 |
299 | Get Import Warning File
300 | -----------------------
301 | API Ref: http://developers.marketo.com/documentation/rest/get-import-warning-file/
302 | ```python
303 | batch_id = 899
304 | warning_leads = mc.execute(method='get_import_warning_file', id=batch_id)
305 | file_name = "import-warning-for-batch-" + str(batch_id) + ".csv"
306 | if warning_leads is not '':
307 | f = open(file_name, encoding='utf-8', mode='w')
308 | f.write(warning_leads)
309 | f.close()
310 |
311 | # specify the batchId that is returned in 'Import Lead'
312 | ```
313 |
314 | Describe
315 | --------
316 | API Ref: http://developers.marketo.com/documentation/rest/describe/
317 | ```python
318 | lead_fields = mc.execute(method='describe')
319 | ```
320 |
321 | Describe2
322 | --------
323 | API Ref: https://developers.marketo.com/rest-api/endpoint-reference/lead-database-endpoint-reference/#!/Leads/describeUsingGET_6
324 | ```python
325 | lead_fields = mc.execute(method='describe2')
326 | ```
327 |
328 | Describe Program Member
329 | -----------------------
330 | API Ref: https://developers.marketo.com/rest-api/endpoint-reference/lead-database-endpoint-reference/#!/Program_Members/describeProgramMemberUsingGET2
331 | ```python
332 | program_member_fields = mc.execute(method='describe_program_member')
333 | ```
334 |
335 | Get Activity Types
336 | ------------------
337 | API Ref: http://developers.marketo.com/documentation/rest/get-activity-types/
338 | ```python
339 | activity_types = mc.execute(method = 'get_activity_types')
340 | ```
341 |
342 | Get Paging Token
343 | ----------------
344 | API Ref: http://developers.marketo.com/documentation/rest/get-paging-token/
345 | ```python
346 | mc.execute(method='get_paging_token', sinceDatetime='2014-10-06')
347 |
348 | # sinceDatetime format: 2015-10-06T13:22:17-08:00 or 2015-10-06T13:22-0700 or 2015-10-06
349 | # This call is optional, you can directly pass in the datetime into 'Get Lead Activity' and 'Get Lead Changes'
350 | # Returns the paging token
351 | ```
352 |
353 | Get Lead Activities
354 | -------------------
355 | API Ref: http://developers.marketo.com/documentation/rest/get-lead-activities/
356 | ```python
357 | mc.execute(method='get_lead_activities', activityTypeIds=['23','22'], nextPageToken=None,
358 | sinceDatetime='2015-10-06', untilDatetime='2016-04-30',
359 | batchSize=None, listId=None, leadIds=[1,2])
360 |
361 | # sinceDatetime format: 2015-10-06T13:22:17-08:00 or 2015-10-06T13:22-0700 or 2015-10-06
362 | # either nextPageToken or sinceDatetime need to be specified
363 | # untilDatetime, batchSize, listId and leadIds are optional; batchsize defaults to 300 (max)
364 | # unless you specify untilDatetime, the function loops until it has all activities until right now,
365 | # then returns them (which could potentially be a lot of data)
366 | ```
367 |
368 | Get Lead Activities Yield (Generator)
369 | ----------------------------------
370 | API Ref: http://developers.marketo.com/documentation/rest/get-lead-activities/
371 | ```python
372 | for activities in mc.execute(method='get_lead_activities_yield', activityTypeIds=['23','22'], nextPageToken=None,
373 | sinceDatetime='2015-10-06', untilDatetime='2016-04-30',
374 | batchSize=None, listId=None, leadIds=[1,2], return_full_result=False,
375 | max_empty_more_results=None):
376 | print(len(activities))
377 |
378 | # sinceDatetime format: 2015-10-06T13:22:17-08:00 or 2015-10-06T13:22-0700 or 2015-10-06
379 | # either nextPageToken or sinceDatetime need to be specified
380 | # untilDatetime, batchSize, listId and leadIds are optional; batchsize defaults to 300 (max)
381 | # set return_full_result to get the nextPageToken and requestId returned; actual
382 | # result will be in the 'result' key
383 | # sometimes Marketo responds with 0 results but indicates there may be more
384 | # results in the next call; max_empty_more_results defines how many times "0 results"
385 | # is acceptable until it gives up
386 | # this is a generator, so it will return chunks of Leads rather that all Activities
387 | # at once; therefore, it's useful for retrieving large numbers of Activities
388 | ```
389 |
390 | Get Lead Changes
391 | ----------------
392 | API Ref: http://developers.marketo.com/documentation/rest/get-lead-changes/
393 | ```python
394 | lead = mc.execute(method='get_lead_changes', fields=['firstName','lastName'], nextPageToken=None,
395 | sinceDatetime='2015-09-01', untilDatetime='2017-01-01', batchSize=None, listId=None)
396 |
397 | # sinceDatetime format: 2015-10-06T13:22:17-08:00 or 2015-10-06T13:22-0700 or 2015-10-06
398 | # either nextPageToken or sinceDatetime need to be specified
399 | # untilDatetime, batchSize and listId are optional; batchsize defaults to 300 (max)
400 | # this will potentially return a lot of records: the function loops until it has all activities, then returns them
401 | ```
402 |
403 | Get Lead Changes Yield (Generator)
404 | ----------------------------------
405 | API Ref: http://developers.marketo.com/documentation/rest/get-lead-changes/
406 | ```python
407 | for leads in mc.execute(method='get_lead_changes_yield', fields=['firstName','lastName'], nextPageToken=None,
408 | sinceDatetime='2015-09-01', untilDatetime='2017-01-01', batchSize=None, listId=None,
409 | leadIds=[1,2], return_full_result=False, max_empty_more_results=None):
410 | print(len(leads))
411 |
412 | # sinceDatetime format: 2015-10-06T13:22:17-08:00 or 2015-10-06T13:22-0700 or 2015-10-06
413 | # either nextPageToken or sinceDatetime need to be specified
414 | # untilDatetime, batchSize, listId and leadIds are optional; batchsize defaults to 300 (max)
415 | # set return_full_result to get the nextPageToken and requestId returned; actual
416 | # result will be in the 'result' key
417 | # sometimes Marketo responds with 0 results but indicates there may be more
418 | # results in the next call; max_empty_more_results defines how many times "0 results"
419 | # is acceptable until it gives up
420 | ```
421 |
422 | Add Custom Activities
423 | ---------------------
424 | API Ref: http://developers.marketo.com/documentation/rest/add-custom-activities/
425 | ```python
426 | custom_activities = [
427 | {
428 | "leadId": 46,
429 | "activityDate": "2016-03-05T09:51:00-08:00",
430 | "activityTypeId": 100004,
431 | "primaryAttributeValue":"Blue",
432 | "attributes":[
433 | {
434 | "name": "Attribute 1",
435 | "value": "First Attribute"
436 | },
437 | {
438 | "name": "Attribute 2",
439 | "value": "Second Attribute"
440 | }
441 | ]
442 | }
443 | ]
444 | result = mc.execute(method = 'add_custom_activities', input=custom_activities)
445 |
446 | # Currently, Custom Activities need to be set up by Marketo Technical Support or Consulting Services
447 | # max batch size is 300
448 | ```
449 |
450 |
451 | Get Daily Usage
452 | ---------------
453 | API Ref: http://developers.marketo.com/documentation/rest/get-daily-usage/
454 | ```python
455 | lead = mc.execute(method='get_daily_usage')
456 | ```
457 |
458 | Get Last 7 Days Usage
459 | ---------------------
460 | API Ref: http://developers.marketo.com/documentation/rest/get-last-7-days-usage/
461 | ```python
462 | lead = mc.execute(method='get_last_7_days_usage')
463 | ```
464 |
465 | Get Daily Errors
466 | ----------------
467 | API Ref: http://developers.marketo.com/documentation/rest/get-daily-errors/
468 | ```python
469 | lead = mc.execute(method='get_daily_errors')
470 | ```
471 |
472 | Get Last 7 Days Errors
473 | ----------------------
474 | API Ref: http://developers.marketo.com/documentation/rest/get-last-7-days-errors/
475 | ```python
476 | lead = mc.execute(method='get_last_7_days_errors')
477 | ```
478 |
479 | Delete Lead
480 | -----------
481 | API Ref: http://developers.marketo.com/documentation/rest/delete-lead/
482 | ```python
483 | lead = mc.execute(method='delete_lead', id=[1,2])
484 |
485 | # max batch size is 300
486 | ```
487 |
488 | Get Deleted Leads
489 | -----------------
490 | API Ref: http://developers.marketo.com/documentation/rest/get-deleted-leads/
491 | ```python
492 | lead = mc.execute(method='get_deleted_leads', nextPageToken=None, sinceDatetime=date.today(), batchSize=None)
493 |
494 | # sinceDatetime format: 2015-10-06T13:22:17-08:00 or 2015-10-06T13:22-0700 or 2015-10-06
495 | # either nextPageToken or sinceDatetime need to be specified
496 | # batchSize is optional
497 | # will return first and last name, Marketo ID and time of deletion, but no additional Lead attributes
498 | ```
499 |
500 | Update Leads Partition
501 | ----------------------
502 | API Ref: http://developers.marketo.com/documentation/rest/update-leads-partition/
503 | ```python
504 | new_partitions = [{'id': 3482156, 'partitionName': 'Default'}, {'id': 3482141, 'partitionName': 'Europe'}]
505 | lead = mc.execute(method='update_leads_partition', input=new_partitions)
506 | ```
507 |
508 |
509 | Folders
510 | =============
511 |
512 | Create Folder
513 | -------------
514 | API Ref: http://developers.marketo.com/documentation/asset-api/create-folder/
515 | ```python
516 | folder = mc.execute(method='create_folder', name='folder2', parentId=115, parentType="Folder", description='optional')
517 |
518 | # parentType is "Folder" or "Program"
519 | # description is optional
520 | ```
521 |
522 | Get Folder by Id
523 | ----------------
524 | API Ref: http://developers.marketo.com/documentation/asset-api/get-folder-by-id/
525 | ```python
526 | folder = mc.execute(method='get_folder_by_id', id=3, type='Folder')
527 |
528 | # type is 'Folder' or 'Program'; this is required because a Folder and a Program can have the same Id
529 | # will throw KeyError when no folder found
530 | ```
531 |
532 | Get Folder by Name
533 | ------------------
534 | API Ref: http://developers.marketo.com/documentation/asset-api/get-folder-by-name/
535 | ```python
536 | folder = mc.execute(method='get_folder_by_name', name='test', type='Folder', root=115, workSpace='Europe')
537 |
538 | # type, root and workSpace are optional
539 | # will throw KeyError when no folder found
540 | ```
541 |
542 | Get Folder Contents
543 | -------------------
544 | API Ref: http://developers.marketo.com/documentation/asset-api/get-folder-contents/
545 | ```python
546 | assets = mc.execute(method='get_folder_contents', id=1205, type='Program', maxReturn=None)
547 |
548 | # type is Folder or Program
549 | # maxReturn is optional; default for maxReturn is 20 and max is 200
550 | # function will loop and return all results
551 | ```
552 |
553 | Update Folder
554 | -------------
555 | API Ref: http://developers.marketo.com/documentation/asset-api/update-folder/
556 | ```python
557 | folder = mc.execute(method='update_folder', id=141, name="New Name", description=None, isArchive=None)
558 |
559 | # name, description and isArchive are optional
560 | # use the id as returned by 'Browse Folders' or 'Get Folder by Name
561 | # can only be used to update Folders, not Programs
562 | ```
563 |
564 | Delete Folder
565 | -------------------
566 | API Ref: http://developers.marketo.com/documentation/asset-api/delete-folder-by-id/
567 | ```python
568 | folder = mc.execute(method='delete_folder', id=789)
569 |
570 | # can only be used to delete Folders, not Programs
571 | ```
572 |
573 | Browse Folders
574 | --------------
575 | API Ref: http://developers.marketo.com/documentation/asset-api/browse-folders
576 | ```python
577 | lead = mc.execute(method='browse_folders', root=3, maxDepth=5, maxReturn=200, workSpace='Default')
578 |
579 | # maxDepth, maxReturn and workSpace are optional; default for maxReturn is 20 and max is 200
580 | # use the id as returned by 'Browse Folders' or 'Get Folder by Name
581 | # function will loop and return all results
582 | # will throw KeyError when no folder found
583 | ```
584 |
585 | Browse Folders (Yield)
586 | --------------
587 | API Ref: http://developers.marketo.com/documentation/asset-api/browse-folders
588 | ```python
589 | for folders in mc.execute(method='browse_folders_yield', root=3, maxDepth=5, maxReturn=200, workSpace='Default',
590 | offset=0, return_full_result=False):
591 | print(folders)
592 | ```
593 |
594 | Tokens
595 | =======
596 |
597 | Create Token
598 | ------------
599 | API Ref: http://developers.marketo.com/documentation/asset-api/create-token-by-folder-id/
600 | ```python
601 | token = mc.execute(method='create_token', id="28", folderType="Folder", name="test", value="testing 2", type="text")
602 |
603 | # this can also be used to update the value of a token
604 | ```
605 |
606 | Get Tokens
607 | ----------
608 | API Ref: http://developers.marketo.com/documentation/asset-api/get-tokens-by-folder-id/
609 | ```python
610 | tokens = mc.execute(method='get_tokens', id="28", folderType="Folder")
611 | ```
612 |
613 | Delete Tokens
614 | -------------
615 | API Ref: http://developers.marketo.com/documentation/asset-api/delete-tokens-by-folder-id/
616 | ```python
617 | tokens = mc.execute(method='delete_tokens', id="28", folderType="Folder", name="test", type="text")
618 | ```
619 |
620 | Static Lists
621 | =====
622 |
623 | Get Static List by Id
624 | --------------
625 | API Ref: http://developers.marketo.com/rest-api/assets/static-lists/#by_id
626 | ```python
627 | lead = mc.execute(method='get_list_by_id', id=724)
628 | ```
629 |
630 | Get Static List by Name
631 | --------------
632 | API Ref: https://developers.marketo.com/rest-api/endpoint-reference/asset-endpoint-reference/#!/Static_Lists/getStaticListByNameUsingGET
633 | ```python
634 | lead = mc.execute(method='get_list_by_name', name='My Test List')
635 | ```
636 |
637 | Get Multiple Lists (OLD)
638 | ------------------
639 | API Ref: http://developers.marketo.com/rest-api/endpoint-reference/lead-database-endpoint-reference/#!/Static_Lists/getListsUsingGET
640 | ```python
641 | lead = mc.execute(method='get_multiple_lists', id=[724,725], name=None, programName=None, workspaceName=None, batchSize=300)
642 |
643 | # NOTE: this call has different options compared to 'browse_lists' below
644 | # all parameters are optional; no parameters returns all lists
645 | ```
646 |
647 | Get Static Lists
648 | ------------------
649 | API Ref: http://developers.marketo.com/rest-api/assets/static-lists/#browse
650 | ```python
651 | lead = mc.execute(method='browse_lists', folderId=8, folderType='Folder', offset=None,
652 | maxReturn=None, earliestUpdatedAt=None, latestUpdatedAt=None)
653 |
654 | # NOTE: this call has different options compared to 'get_multiple_lists' above
655 | # all parameters are optional; no parameters returns all lists
656 | ```
657 |
658 | Get Static Lists (Yield)
659 | ------------------
660 | API Ref: http://developers.marketo.com/rest-api/assets/static-lists/#browse
661 | ```python
662 | for lists in mc.execute(method='browse_lists_yield', folderId=8, folderType='Folder', offset=0,
663 | maxReturn=20, earliestUpdatedAt=None, latestUpdatedAt=None, return_full_result=False):
664 | print(lists)
665 |
666 | # all parameters are optional; no parameters returns all lists
667 | ```
668 |
669 | Create Static List
670 | -----------
671 | API Ref: http://developers.marketo.com/rest-api/assets/static-lists/#create_and_update
672 | ```python
673 | lead = mc.execute(method='create_list', folderId=8, folderType='Folder', name='Test List', description='Optional')
674 |
675 | # 'folderType' is either 'Folder' or 'Program'
676 | # description is optional
677 | ```
678 |
679 | Update Static List
680 | ----------
681 | API Ref: http://developers.marketo.com/rest-api/assets/static-lists/#create_and_update
682 | ```python
683 | lead = mc.execute(method='update_list', id=123, name='new name', description='new description')
684 |
685 | # 'id' and either 'name' or 'description' need to be specified (or all of them)
686 | ```
687 |
688 | Delete List
689 | -----------
690 | API Ref: http://developers.marketo.com/rest-api/assets/static-lists/#delete
691 | ```python
692 | lead = mc.execute(method='delete_list', id=123)
693 | ```
694 |
695 | Smart Lists
696 | =====
697 |
698 | Get Smart List by Id
699 | -------------------
700 | API ref: https://developers.marketo.com/rest-api/endpoint-reference/asset-endpoint-reference/#!/Smart_Lists/getSmartListByIdUsingGET
701 | ```python
702 | smart_list = mc.execute(method='get_smart_list_by_id', id=123, return_full_result=False)
703 | # set return_full_result to get the nextPageToken and requestId returned; actual
704 | # result will be in the 'result' key
705 | ```
706 |
707 | Get Smart List by Name
708 | -------------------
709 | API ref: https://developers.marketo.com/rest-api/endpoint-reference/asset-endpoint-reference/#!/Smart_Lists/getSmartListByNameUsingGET
710 | ```python
711 | smart_list = mc.execute(method='get_smart_list_by_name', name='Abc', return_full_result=False)
712 | # set return_full_result to get the nextPageToken and requestId returned; actual
713 | # result will be in the 'result' key
714 | ```
715 |
716 | Get Smart Lists
717 | -------------------
718 | API ref: https://developers.marketo.com/rest-api/endpoint-reference/asset-endpoint-reference/#!/Smart_Lists/getSmartListsUsingGET
719 | ```python
720 | for smart_lists in mc.execute(method='get_smart_lists', folderId=123, folderType='Folder', offset=None,
721 | maxReturn=None, earliestUpdatedAt=None, latestUpdatedAt=None, return_full_result=False):
722 | print(smart_lists)
723 | # all parameters are optional; no parameters returns all lists
724 | # maxReturn defaults to 200
725 | # offset defaults to 0; it is automatically incremented, so it's only for when you want to start at a specific offset
726 | # set return_full_result to get the nextPageToken and requestId returned; actual
727 | # result will be in the 'result' key
728 | ```
729 |
730 | Delete Smart List
731 | -------------------
732 | API ref: https://developers.marketo.com/rest-api/endpoint-reference/asset-endpoint-reference/#!/Smart_Lists/deleteSmartListByIdUsingPOST
733 | ```python
734 | smart_list = mc.execute(method='delete_smart_list', id=123)
735 | # set return_full_result to get the nextPageToken and requestId returned; actual
736 | # result will be in the 'result' key
737 | ```
738 |
739 | Clone Smart List
740 | -------------------
741 | API ref: https://developers.marketo.com/rest-api/endpoint-reference/asset-endpoint-reference/#!/Smart_Lists/cloneSmartListUsingPOST
742 | ```python
743 | smart_list = mc.execute(method='clone_smart_list', id=123, name='cloned smart list', folderId=123, folderType='Folder',
744 | return_full_result=False, description=None)
745 | # set return_full_result to get the nextPageToken and requestId returned; actual
746 | # result will be in the 'result' key
747 | # description is optional
748 | ```
749 |
750 | Smart Campaigns
751 | ================
752 |
753 |
754 | Get Smart Campaign by Id
755 | -----------------------
756 | API Ref: https://developers.marketo.com/rest-api/endpoint-reference/asset-endpoint-reference/#!/Smart_Campaigns/getSmartCampaignByIdUsingGET
757 | ```python
758 | campaign = mc.execute(method='get_smart_campaign_by_id', id=1170)
759 | ```
760 |
761 | Get Smart Campaign by Name
762 | -----------------------
763 | API Ref: https://developers.marketo.com/rest-api/endpoint-reference/asset-endpoint-reference/#!/Smart_Campaigns/getSmartCampaignByNameUsingGET
764 | ```python
765 | campaign = mc.execute(method='get_smart_campaign_by_name', name='my smart campaign name')
766 | ```
767 |
768 | Get Campaign by Id - SUPERCEDED
769 | ------------------
770 | Use "Get Smart Campaign by Id" instead.
771 |
772 | API Ref: http://developers.marketo.com/documentation/rest/get-campaign-by-id/
773 | ```python
774 | campaign = mc.execute(method='get_campaign_by_id', id=1170)
775 | ```
776 |
777 | Get Smart Campaigns (Generator)
778 | -------------------
779 | API Ref: https://developers.marketo.com/rest-api/endpoint-reference/asset-endpoint-reference/#!/Smart_Campaigns/getAllSmartCampaignsGET
780 | ```python
781 | for campaigns in mc.execute(method='get_smart_campaigns', earliestUpdatedAt=None, latestUpdatedAt=None,
782 | folderId=None, folderType=None,
783 | maxReturn=200, offset=0,
784 | return_full_result=False):
785 | print(campaigns)
786 |
787 | # all parameters are optional; folderId and folderType need to be specified together;
788 | # folderType can be "Folder" or "Program"
789 | # set return_full_result to True to get the full API response including requestId (not just the 'result' key)
790 | ```
791 |
792 | Get Multiple Campaigns - SUPERCEDED
793 | ----------------------
794 | Use "Get Smart Campaigns" instead.
795 |
796 | API Ref: http://developers.marketo.com/documentation/rest/get-multiple-campaigns/
797 | ```python
798 | lead = mc.execute(method='get_multiple_campaigns', id=[1170,1262], name=None, programName=None, workspaceName=None, batchSize=None)
799 |
800 | # all parameters are optional
801 | ```
802 |
803 | Schedule Campaign
804 | -----------------
805 | API Ref: http://developers.marketo.com/documentation/rest/schedule-campaign/
806 | ```python
807 | # date format: 2015-11-08T15:43:12-08:00
808 | from datetime import datetime, timezone, timedelta
809 | now = datetime.now(timezone.utc)
810 | now_no_ms = now.replace(microsecond=0)
811 | now_plus_7 = now_no_ms + timedelta(minutes = 7)
812 | time_as_txt = now_plus_7.astimezone().isoformat()
813 | print(time_as_txt)
814 | lead = mc.execute(method='schedule_campaign', id=1878, runAt=time_as_txt, tokens={'my.Campaign Name': 'new token value'}, cloneToProgramName=None)
815 |
816 | # runAt is optional; default is 5 minutes from now; if specified, it needs to be at least 5 minutes from now
817 | # tokens and cloneToProgramName are optional
818 | # returns True
819 | ```
820 |
821 | Request Campaign
822 | ----------------
823 | API Ref: http://developers.marketo.com/documentation/rest/request-campaign/
824 | ```python
825 | lead = mc.execute(method='request_campaign', id=1880, leads=[46,38], tokens={'my.increment': '+2'})
826 |
827 | # tokens is optional
828 | # returns True
829 | ```
830 |
831 | Activate Smart Campaign
832 | -----------------------
833 | API Ref: https://developers.marketo.com/rest-api/endpoint-reference/asset-endpoint-reference/#!/Smart_Campaigns/activateSmartCampaignUsingPOST
834 | ```python
835 | campaign = mc.execute(method='activate_smart_campaign', id=1880)
836 | ```
837 |
838 | Deactivate Smart Campaign
839 | -----------------------
840 | API Ref: https://developers.marketo.com/rest-api/endpoint-reference/asset-endpoint-reference/#!/Smart_Campaigns/deactivateSmartCampaignUsingPOST
841 | ```python
842 | campaign = mc.execute(method='deactivate_smart_campaign', id=1880)
843 | ```
844 |
845 | Create Smart Campaign
846 | ---------------------
847 | API Ref: https://developers.marketo.com/rest-api/endpoint-reference/asset-endpoint-reference/#!/Smart_Campaigns/createSmartCampaignUsingPOST
848 | ```python
849 | campaign = mc.execute(method='create_smart_campaign', name='New Smart Campaign', folderId=898, folderType='Folder',
850 | description=None)
851 | ```
852 |
853 | Update Smart Campaign
854 | --------------------
855 | API Ref: https://developers.marketo.com/rest-api/endpoint-reference/asset-endpoint-reference/#!/Smart_Campaigns/updateSmartCampaignUsingPOST
856 | ```python
857 | campaign = mc.execute(method='update_smart_campaign', id=1880, name='New Name', description=None)
858 | ```
859 |
860 | Clone Smart Campaign
861 | --------------------
862 | API Ref: https://developers.marketo.com/rest-api/endpoint-reference/asset-endpoint-reference/#!/Smart_Campaigns/cloneSmartCampaignUsingPOST
863 | ```python
864 | campaign = mc.execute(method='clone_smart_campaign', id=1880, name='New Name', folderId=898, folderType='Folder',
865 | isExecutable=False, description=None)
866 | # isExecutable and description are optional
867 | ```
868 |
869 | Delete Smart Campaign
870 | --------------------
871 | API Ref: https://developers.marketo.com/rest-api/endpoint-reference/asset-endpoint-reference/#!/Smart_Campaigns/deleteSmartCampaignUsingPOST
872 | ```python
873 | campaign = mc.execute(method='delete_smart_campaign', id=1880)
874 | ```
875 |
876 | Get Smart List by Smart Campaign Id
877 | --------------------------
878 | API Ref: https://developers.marketo.com/rest-api/endpoint-reference/asset-endpoint-reference/#!/Smart_Campaigns/getSmartListBySmartCampaignIdUsingGET
879 | ```python
880 | smart_list = mc.execute(method='get_smart_list_by_smart_campaign_id', id=123, includeRules=True,
881 | return_full_result=False)
882 | # set includeRules to False if you do not want to get all triggers and filters of the smart list in the response
883 | ```
884 |
885 |
886 | Email Templates
887 | ===============
888 |
889 | Create Email Template
890 | ---------------------
891 | API Ref: http://developers.marketo.com/documentation/asset-api/create-email-template/
892 | ```python
893 | template = mc.execute(method='create_email_template', folderId=14, folderType="Folder", name="API Email Template",
894 | content="email_template.html", description="Hello Description")
895 |
896 | # description is optional
897 | # content should contain path to HTML file
898 | ```
899 |
900 | Get Email Template by Id
901 | ------------------------
902 | API Ref: http://developers.marketo.com/documentation/asset-api/get-email-template-by-id/
903 | ```python
904 | template = mc.execute(method='get_email_template_by_id', id=41, status='approved')
905 |
906 | # status is optional; values are 'draft' or 'approved'; a single email can have both an approved and a draft version
907 | ```
908 |
909 | Get Email Template by Name
910 | ------------------------
911 | API Ref: http://developers.marketo.com/documentation/asset-api/get-email-template-by-name/
912 | ```python
913 | template = mc.execute(method='get_email_template_by_name', name='API Email Template', status='approved')
914 |
915 | # status is optional: values are 'draft' or 'approved'; a single email can have both an approved and a draft version
916 | ```
917 |
918 | Update Email Template
919 | ---------------------
920 | API Ref: http://developers.marketo.com/documentation/asset-api/update-email-template/
921 | ```python
922 | template = mc.execute(method='update_email_template', id=41, name='API Email Template', description=None)
923 |
924 | # name and description are optional, but - of course - you want to pass in at least 1 of them
925 | # this is only to update name and description, use 'Update Email Template Content' to update the HTML
926 | ```
927 |
928 | Delete Email Template
929 | ---------------------
930 | API Ref: http://developers.marketo.com/documentation/asset-api/delete-email-template-by-id/
931 | ```python
932 | template = mc.execute(method='delete_email_template', id=41)
933 | ```
934 |
935 | Get Email Templates
936 | -------------------
937 | API Ref: http://developers.marketo.com/documentation/asset-api/get-email-templates/
938 | ```python
939 | template = mc.execute(method='get_email_templates', status='draft', maxReturn=None)
940 |
941 | # status and maxReturn are optional; status is 'draft' or 'approved'; default for maxReturn is 20 and max is 200
942 | # if you specify status, it will return an approved email with a draft for both status='draft' AND status='approved'
943 | ```
944 |
945 | Get Email Template Used By
946 | -------------------
947 | API Ref: https://developers.marketo.com/rest-api/endpoint-reference/asset-endpoint-reference/#!/Email_Templates/getEmailTemplateUsedByUsingGET
948 |
949 | ```python
950 | template = mc.execute(method='get_email_template_used_by', id=41, maxReturn=None)
951 |
952 | # maxReturn is optional; default for maxReturn is 20 and max is 200
953 | ```
954 |
955 |
956 | Get Email Template Content
957 | --------------------------
958 | API Ref: http://developers.marketo.com/documentation/asset-api/get-email-template-content-by-id/
959 | ```python
960 | template = mc.execute(method='get_email_template_content', id=39, status='approved')
961 | with open('email-template-content.html', 'w', encoding='utf-8') as f:
962 | f.write(template[0]['content'])
963 |
964 | # status is optional: values are 'draft' or 'approved'
965 | ```
966 |
967 | Update Email Template Content
968 | -----------------------------
969 | API Ref: http://developers.marketo.com/documentation/asset-api/update-email-template-content-by-id/
970 | ```python
971 | template = mc.execute(method='update_email_template_content', id=42, content='email-template-content.html')
972 |
973 | # 'content' points to a file
974 | ```
975 |
976 | Approve Email Template
977 | ----------------------
978 | API Ref: http://developers.marketo.com/documentation/asset-api/approve-email-template-by-id/
979 | ```python
980 | template = mc.execute(method='approve_email_template', id=42)
981 | ```
982 |
983 | Unapprove Email Template
984 | ----------------------
985 | API Ref: http://developers.marketo.com/documentation/asset-api/unapprove-email-template-by-id/
986 | ```python
987 | template = mc.execute(method='unapprove_email_template', id=42)
988 | ```
989 |
990 | Discard Email Template Draft
991 | ----------------------------
992 | API Ref: http://developers.marketo.com/documentation/asset-api/discard-email-template-draft-by-id/
993 | ```python
994 | template = mc.execute(method='discard_email_template_draft', id=42)
995 | ```
996 |
997 | Clone Email Template
998 | --------------------
999 | API Ref: http://developers.marketo.com/documentation/asset-api/clone-email-template/
1000 | ```python
1001 | template = mc.execute(method='clone_email_template', id=42, name='cloned template', folderId=14, folderType='Folder')
1002 |
1003 | # folderId 14 is the Email Templates folder in the Default workspace
1004 | ```
1005 |
1006 | Emails
1007 | ======
1008 |
1009 | Create Email
1010 | ------------
1011 | API Ref: http://developers.marketo.com/documentation/asset-api/create-email/
1012 | ```python
1013 | email = mc.execute(method='create_email', folderId=13, folderType="Folder", name="API Email", template=30,
1014 | description='Hello Description', subject='Subject for API Email', fromName='Info',
1015 | fromEmail='info@example.com', replyEmail=None, operational=None)
1016 |
1017 | # description, subject, fromName, fromEmail, replyEmail and operational are optional
1018 | # without subject, fromName and fromEmail you can't approve the email
1019 | # this is where you create the email shell, in 'Update Email Content in Editable Section' you specify the email body
1020 | ```
1021 |
1022 | Get Email by Id
1023 | ---------------
1024 | API Ref: http://developers.marketo.com/documentation/asset-api/get-email-by-id/
1025 | ```python
1026 | email = mc.execute(method='get_email_by_id', id=263, status='draft')
1027 |
1028 | # status is optional: values are 'draft' or 'approved'
1029 | ```
1030 |
1031 | Get Email by Name
1032 | -----------------
1033 | API Ref: http://developers.marketo.com/documentation/asset-api/get-email-by-name/
1034 | ```python
1035 | email = mc.execute(method='get_email_by_name', name='API Email', status='draft', folderId=None, folderType=None)
1036 |
1037 | # status, folderId and folderType are optional; folderId and folderType need to be specified together
1038 | ```
1039 |
1040 | Delete Email
1041 | ------------
1042 | API Ref: http://developers.marketo.com/documentation/asset-api/delete-email-by-id/
1043 | ```python
1044 | email = mc.execute(method='delete_email', id=263)
1045 | ```
1046 |
1047 | Update Email
1048 | ------------
1049 | API Ref: http://developers.marketo.com/documentation/asset-api/update-email/
1050 | ```python
1051 | email = mc.execute(method='update_email', id=264, name="API Email 2", description='Hello New Description', preHeader=None, operational=None, published=None, textOnly=None, webView=None)
1052 |
1053 | # name and description are optional, but - of course - you want to pass in at least 1 of them
1054 | ```
1055 |
1056 | Get Emails
1057 | ----------
1058 | API Ref: http://developers.marketo.com/documentation/asset-api/get-emails/
1059 | ```python
1060 | email = mc.execute(method='get_emails', status='approved', folderId=13, folderType='Folder', maxReturn=None)
1061 |
1062 | # status, folderId, folderType and maxReturn are optional; folderId and folderType need to be specified together
1063 | # default for maxReturn is 20 and max is 200
1064 | # status can be 'draft' or 'approved'
1065 | ```
1066 |
1067 | Get Email Content
1068 | -----------------
1069 | API Ref: http://developers.marketo.com/documentation/asset-api/get-email-content-by-id
1070 | ```python
1071 | email = mc.execute(method='get_email_content', id=40, status=None)
1072 |
1073 | # status is optional and can be 'draft' or 'approved'
1074 | ```
1075 |
1076 | Update Email Content
1077 | --------------------
1078 | API Ref: http://developers.marketo.com/documentation/asset-api/update-email-content-by-id
1079 | ```python
1080 | email = mc.execute(method='update_email_content', id=13, type='Text', subject='New Subject Line',
1081 | fromEmail='jep@example.com', fromName='Jep', replyTo='jep@example.com')
1082 |
1083 | # subject, fromEmail, fromName and replyTo are optional
1084 | # type should be 'Text' or 'DynamicContent'; if you need a combination of text and dynamic, make 2 calls
1085 | ```
1086 |
1087 | Update Email Content in Editable Section
1088 | ----------------------------------------
1089 | API Ref: http://developers.marketo.com/documentation/asset-api/update-email-content-in-editable-section/
1090 | ```python
1091 | html_content = '''Dear {{lead.First Name:default=friend}}, Donec
1092 | Scelerisque Leosera
Dutch text
', type='HTML') 1116 | ``` 1117 | 1118 | Approve Email 1119 | ------------- 1120 | API Ref: http://developers.marketo.com/documentation/asset-api/approve-email-by-id 1121 | ```python 1122 | email = mc.execute(method='approve_email', id=117) 1123 | ``` 1124 | 1125 | Unapprove Email 1126 | --------------- 1127 | API Ref: http://developers.marketo.com/documentation/asset-api/unapprove-email-by-id 1128 | ```python 1129 | email = mc.execute(method='unapprove_email', id=117) 1130 | ``` 1131 | 1132 | Discard Email Draft 1133 | ------------------- 1134 | API Ref: http://developers.marketo.com/documentation/asset-api/discard-email-draft-by-id/ 1135 | ```python 1136 | email = mc.execute(method='discard_email_draft', id=117) 1137 | ``` 1138 | 1139 | Clone Email 1140 | ----------- 1141 | API Ref: http://developers.marketo.com/documentation/asset-api/clone-email 1142 | ```python 1143 | email = mc.execute(method='clone_email', id=117, name='clone of MHE', folderId=13, folderType='Folder', 1144 | description='description', operational=None) 1145 | 1146 | # description and operational are optional; operational defaults to false 1147 | ``` 1148 | 1149 | Send Sample Email 1150 | ----------------- 1151 | API Ref: http://developers.marketo.com/documentation/asset-api/send-sample-email/ 1152 | ```python 1153 | email = mc.execute(method='send_sample_email', id=117, emailAddress='jep@example.com', textOnly=None, leadId=46) 1154 | 1155 | # textOnly and leadId are optional; textOnly will send the text version of the email in additional to the html version 1156 | ``` 1157 | 1158 | Get Email Full Content 1159 | ----------------- 1160 | API Ref: https://developers.marketo.com/rest-api/endpoint-reference/asset-endpoint-reference/#!/Emails/getEmailFullContentUsingGET 1161 | ```python 1162 | email = mc.execute(method='get_email_full_content', id=117, status=None, leadId=None, type=None) 1163 | 1164 | # status, leadId, and type are optional; status defaults to approved if asset is approved, draft if not. 1165 | # leadId defines the lead to impersonate 1166 | # default for type is HTML 1167 | ``` 1168 | 1169 | Update Email Full Content 1170 | ----------------- 1171 | API Ref: https://developers.marketo.com/rest-api/endpoint-reference/asset-endpoint-reference/#!/Emails/createEmailFullContentUsingPOST 1172 | ```python 1173 | email = mc.execute(method='update_email_full_content', id=117, content='email_content.html') 1174 | 1175 | # NOTE: Replaces the HTML of an Email that has had its relationship broken from its template; currently appears there is no way to set text only content 1176 | # content should be an HTML document to update with (cannot include JavaScript or script tags) 1177 | ``` 1178 | 1179 | Get Email Variables 1180 | ------------------- 1181 | 1182 | API Ref: https://developers.marketo.com/rest-api/endpoint-reference/asset-endpoint-reference/#!/Emails/getEmailVariablesUsingGET 1183 | ```python 1184 | variables = mc.execute(method='get_email_variables', id=1124) 1185 | ``` 1186 | 1187 | Update Email Variable 1188 | ------------------- 1189 | 1190 | API Ref: https://developers.marketo.com/rest-api/endpoint-reference/asset-endpoint-reference/#!/Emails/updateVariableUsingPOST 1191 | ```python 1192 | variable = mc.execute(method='update_email_variable', id=1124, name='preheaderBackgroundColor', value='#81898c', 1193 | moduleId='preheader') 1194 | ``` 1195 | 1196 | Landing pages 1197 | ============= 1198 | 1199 | Get Landing Pages 1200 | ----------------- 1201 | API Ref: http://developers.marketo.com/documentation/marketo-rest-apis-web-page-objects/get-landing-pages/ 1202 | ```python 1203 | lp = mc.execute(method='get_landing_pages', maxReturn=None, status=None, folderId=None, folderType=None) 1204 | 1205 | # status, folderId, folderType and maxReturn are optional; folderId and folderType need to be specified together 1206 | # default for maxReturn is 20 and max is 200 1207 | # status can be 'draft' or 'approved' 1208 | ``` 1209 | 1210 | Create Landing Page 1211 | ------------------- 1212 | API Ref: http://developers.marketo.com/documentation/marketo-rest-apis-web-page-objects/create-landing-page/ 1213 | ```python 1214 | lp = mc.execute(method='create_landing_page', name='API LP', folderId=894, 1215 | folderType='Folder', template=42, description=None, title=None, 1216 | keywords=None, robots=None, customHeadHTML=None, facebookOgTags=None, 1217 | prefillForm=None, mobileEnabled=None) 1218 | 1219 | # description, title, keywords, robots, customHeadHTML, facebookOgTags, 1220 | # prefillForm and mobileEnabled are optional 1221 | # prefillForm and mobileEnabled default to false 1222 | ``` 1223 | 1224 | Get Landing Page by Id 1225 | ----------------------- 1226 | API Ref: http://developers.marketo.com/documentation/marketo-rest-apis-web-page-objects/get-landing-page-by-id/ 1227 | ```python 1228 | lp = mc.execute(method='get_landing_page_by_id', id=360, status=None) 1229 | 1230 | # status is optional and can be 'draft' or 'approved' 1231 | ``` 1232 | 1233 | Get Landing Page by Name 1234 | ------------------------ 1235 | API Ref: http://developers.marketo.com/documentation/marketo-rest-apis-web-page-objects/get-landing-page-by-name/ 1236 | ```python 1237 | lp = mc.execute(method='get_landing_page_by_name', name='Landing page Demo', status=None) 1238 | 1239 | # status is optional and can be 'draft' or 'approved' 1240 | ``` 1241 | 1242 | Delete Landing Page 1243 | ------------------- 1244 | API Ref: http://developers.marketo.com/documentation/marketo-rest-apis-web-page-objects/delete-landing-page/ 1245 | ```python 1246 | lp = mc.execute(method='delete_landing_page', id=411) 1247 | ``` 1248 | 1249 | Update Landing Page Metadata 1250 | ---------------------------- 1251 | API Ref: http://developers.marketo.com/documentation/marketo-rest-apis-web-page-objects/update-landing-page-metadata/ 1252 | ```python 1253 | lp = mc.execute(method='update_landing_page', id=410, description=None, title=None, 1254 | keywords=None, robots=None, customHeadHTML=None, facebookOgTags=None, 1255 | prefillForm=None, mobileEnabled=None, styleOverRide=None, urlPageName=None) 1256 | 1257 | # description, title, keywords, robots, customHeadHTML, facebookOgTags, 1258 | # prefillForm, mobileEnabled, styleOverRide and urlPageName are optional 1259 | # urlPageName is used to change the URL of the page 1260 | ``` 1261 | 1262 | Get Landing Page Content 1263 | ------------------------ 1264 | API Ref: http://developers.marketo.com/documentation/marketo-rest-apis-web-page-objects/get-landing-page-content/ 1265 | ```python 1266 | lp = mc.execute(method='get_landing_page_content', id=410, status='draft') 1267 | 1268 | # status is optional and can be 'draft' or 'approved' 1269 | ``` 1270 | 1271 | 1272 | Create Landing Page Content Section 1273 | ----------------------------------- 1274 | API Ref: http://developers.marketo.com/documentation/marketo-rest-apis-web-page-objects/add-landing-page-content-section/ 1275 | ```python 1276 | lp = mc.execute(method='create_landing_page_content_section', id=410, type='RichText', value='Subtitle
', 1277 | backgroundColor=None, borderColor=None, borderStyle=None, borderWidth=None, height=None, 1278 | layer=None, left=100, opacity=1.0, top=50, width=300, hideDesktop=None, hideMobile=None, 1279 | contentId=None) 1280 | 1281 | # contentId is required for Guided Landing pages 1282 | # backgroundColor, borderColor, borderStyle, borderWidth, height, layer, left, opacity, top, width, 1283 | # hideDesktop and hideMobile are optional 1284 | # height defaults to auto; layer defaults to 15; specify opacity as fractional and use 1.0 for 100% 1285 | # backgroundColor, borderColor, borderStyle and borderWidth don't seem to do anything at this time 1286 | ``` 1287 | 1288 | Update Landing Page Content Section 1289 | ----------------------------------- 1290 | API Ref: http://developers.marketo.com/documentation/marketo-rest-apis-web-page-objects/update-landing-page-content-section/ 1291 | ```python 1292 | lp = mc.execute(method='update_landing_page_content_section', id=410, contentId=2200, type='RichText', 1293 | value='Updated Title
', backgroundColor=None, borderColor=None, borderStyle=None, 1294 | borderWidth=None, height=None, zIndex=15, left=50, opacity=1.0, top=50, width=300, 1295 | hideDesktop=None, hideMobile=None, imageOpenNewWindow=None, linkUrl=None) 1296 | 1297 | # make section dynamic: 1298 | lp = mc.execute(method='update_landing_page_content_section', id=410, contentId=2218, 1299 | type='DynamicContent', value=1003) 1300 | 1301 | # backgroundColor, borderColor, borderStyle, borderWidth, height, layer, left, opacity, top, width, 1302 | # hideDesktop and hideMobile are optional 1303 | # height defaults to auto; layer defaults to 15; specify opacity as fractional and use 1.0 for 100% 1304 | # contentId changes when the page is approved 1305 | # in case of type=DynamicContent, the value is the id of the Segmentation 1306 | # backgroundColor, borderColor, borderStyle and borderWidth don't seem to do anything 1307 | ``` 1308 | 1309 | Delete Landing Page Content Section 1310 | ----------------------------------- 1311 | API Ref: http://developers.marketo.com/documentation/marketo-rest-apis-web-page-objects/delete-landing-page-content-section/ 1312 | ```python 1313 | lp = mc.execute(method='delete_landing_page_content_section', id=410, contentId=2215) 1314 | 1315 | # use 'Get Landing page Content' to find the contentId (which changes when page is approved) 1316 | ``` 1317 | 1318 | Get Landing Page Dynamic Content 1319 | -------------------------------- 1320 | API Ref: http://developers.marketo.com/documentation/marketo-rest-apis-web-page-objects/get-dynamic-content-section/ 1321 | ```python 1322 | lp = mc.execute(method='get_landing_page_dynamic_content', id=410, ...) 1323 | ``` 1324 | 1325 | Update Landing Page Dynamic Content 1326 | ----------------------------------- 1327 | API Ref: http://developers.marketo.com/documentation/marketo-rest-apis-web-page-objects/update-dynamic-content-section/ 1328 | ```python 1329 | lp = mc.execute(method='update_landing_page_dynamic_content', id=410, ...) 1330 | ``` 1331 | 1332 | 1333 | Approve Landing Page 1334 | -------------------- 1335 | API Ref: http://developers.marketo.com/documentation/marketo-rest-apis-web-page-objects/discard-landing-page-draft/ 1336 | ```python 1337 | lp = mc.execute(method='approve_landing_page', id=410) 1338 | ``` 1339 | 1340 | Unapprove Landing Page 1341 | ---------------------- 1342 | API Ref: http://developers.marketo.com/documentation/marketo-rest-apis-web-page-objects/unapprove-landing-page/ 1343 | ```python 1344 | lp = mc.execute(method='unapprove_landing_page', id=410) 1345 | ``` 1346 | 1347 | Discard Landing Page Draft 1348 | -------------------------- 1349 | API Ref: http://developers.marketo.com/documentation/marketo-rest-apis-web-page-objects/discard-landing-page-draft/ 1350 | ```python 1351 | lp = mc.execute(method='discard_landing_page_draft', id=410) 1352 | ``` 1353 | 1354 | Clone Landing Page 1355 | ------------------ 1356 | API Ref: http://developers.marketo.com/documentation/marketo-rest-apis-web-page-objects/clone-landing-page/ 1357 | ```python 1358 | lp = mc.execute(method='clone_landing_page', id=410, name='cloned landing page', folderId=894, 1359 | folderType='Folder', description=None, template=42) 1360 | 1361 | # description is optional 1362 | # template should be optional but is currently required 1363 | ``` 1364 | 1365 | Forms 1366 | ===== 1367 | 1368 | Get Forms: 1369 | ---------- 1370 | API Ref: http://developers.marketo.com/documentation/marketo-rest-apis-web-page-objects/get-forms/ 1371 | ```python 1372 | forms = mc.execute(method='get_forms', status=None, folderId=None, folderType=None, maxReturn=None) 1373 | 1374 | # status, folderId, folderType and maxReturn are optional 1375 | ``` 1376 | 1377 | Get Form by Id 1378 | ---------- 1379 | API Ref: http://developers.marketo.com/documentation/marketo-rest-apis-web-page-objects/get-form-by-id/ 1380 | ```python 1381 | form = mc.execute(method='get_form_by_id', id=50, status=None) 1382 | 1383 | # status is optional and can be 'draft' or 'approved' 1384 | ``` 1385 | 1386 | Get Form by Name 1387 | ---------- 1388 | API Ref: http://developers.marketo.com/documentation/marketo-rest-apis-web-page-objects/get-form-by-name/ 1389 | ```python 1390 | form = mc.execute(method='get_form_by_name', name='Form Demo', status=None) 1391 | 1392 | # status is optional and can be 'draft' or 'approved' 1393 | ``` 1394 | 1395 | Get Form Fields List 1396 | ---------- 1397 | API Ref: http://developers.marketo.com/documentation/marketo-rest-apis-web-page-objects/get-form-fields-list/ 1398 | ```python 1399 | fields = mc.execute(method='get_form_fields', id=50, status=None) 1400 | 1401 | # status is optional and can be 'draft' or 'approved' 1402 | ``` 1403 | 1404 | Add Field to Form 1405 | ---------- 1406 | API Ref: http://developers.marketo.com/documentation/marketo-rest-apis-web-page-objects/add-field-to-form/ 1407 | ```python 1408 | field = mc.execute(method='create_form_field', id=104, fieldId='AnnualRevenue', label='Rev', labelWidth=200, 1409 | fieldWidth=200, instructions='fill out this field', 1410 | required=True, formPrefill=True, initiallyChecked=None, values=None, labelToRight=None, 1411 | hintText='hint', defaultValue=100, minValue=100, maxValue=1000000, multiSelect=None, 1412 | maxLength=None, maskInput=None, visibleLines=None) 1413 | 1414 | # only id and fieldId are required, all others are optional 1415 | ``` 1416 | 1417 | Create Form 1418 | ----------- 1419 | API Ref: http://developers.marketo.com/documentation/marketo-rest-apis-web-page-objects/create-form/ 1420 | ```python 1421 | form = mc.execute(method='create_form', name='API Form 4', folderId=140, folderType='Folder', 1422 | description='optional description', language='Dutch', locale='nl_NL', progressiveProfiling=True, 1423 | labelPosition='above', fontFamily='Droid Sans Mono', fontSize='12px', knownVisitor=None) 1424 | 1425 | # description, language, locale, progressiveProfiling, labelPosition, fontFamily, fontSize, knownVisitor, theme are optional 1426 | # locale examples: en_US, en_UK, fr_FR, de_DE, zh_CN, ja_JP, hi_IN, nl_NL, nl_BE 1427 | # fontFamily/fontSize and theme are mutually exclusive 1428 | # fontFamily doesn't seem to work 1429 | # labelPosition is left or above (lower case) 1430 | # TODO: knownVisitor needs further explanation 1431 | ``` 1432 | 1433 | Get Form Thank You Page 1434 | ------------------ 1435 | API Ref: http://developers.marketo.com/documentation/marketo-rest-apis-web-page-objects/get-form-thank-you-page/ 1436 | ```python 1437 | # not implemented yet 1438 | ``` 1439 | 1440 | Update Form Thank You Page 1441 | -------------------------- 1442 | API Ref: http://developers.marketo.com/documentation/marketo-rest-apis-web-page-objects/update-form-thank-you-page/ 1443 | ```python 1444 | # not implemented yet 1445 | ``` 1446 | 1447 | Update Form Metadata 1448 | ----------------- 1449 | API Ref: http://developers.marketo.com/documentation/marketo-rest-apis-web-page-objects/update-form/ 1450 | ```python 1451 | form = mc.execute('update_form', id=50, name=None, description=None, language=None, locale=None, progressiveProfiling=None, 1452 | labelPosition=None, fontFamily=None, fontSize=None, knownVisitor=None, formTheme=None, 1453 | customcss=None) 1454 | 1455 | # id is required, all others are optional 1456 | ``` 1457 | 1458 | Discard Form Draft 1459 | -------------- 1460 | API Ref: http://developers.marketo.com/documentation/marketo-rest-apis-web-page-objects/discard-form-draft/ 1461 | ```python 1462 | form = mc.execute(method='discard_form_draft', id) 1463 | ``` 1464 | 1465 | Approve Form 1466 | ------------ 1467 | API Ref: http://developers.marketo.com/documentation/marketo-rest-apis-web-page-objects/approve-form/ 1468 | ```python 1469 | form = mc.execute(method='approve_form', id) 1470 | ``` 1471 | 1472 | Unapprove Form 1473 | -------------- 1474 | API Ref: http://developers.marketo.com/documentation/marketo-rest-apis-web-page-objects/unapprove-form/ 1475 | ```python 1476 | form = mc.execute(method='unapprove_form', id) 1477 | ``` 1478 | 1479 | Clone Form 1480 | ---------- 1481 | API Ref: http://developers.marketo.com/documentation/marketo-rest-apis-web-page-objects/clone-form/ 1482 | ```python 1483 | form = mc.execute(method='clone_form', id=50, name='new form name', folderId=12, folderType='Folder', description=None) 1484 | ``` 1485 | 1486 | Delete Form 1487 | ----------- 1488 | API Ref: http://developers.marketo.com/documentation/marketo-rest-apis-web-page-objects/delete-form/ 1489 | ```python 1490 | form = mc.execute(method='delete_form', id=50) 1491 | ``` 1492 | 1493 | Update Form Field 1494 | ----------------- 1495 | API Ref: http://developers.marketo.com/documentation/marketo-rest-apis-web-page-objects/update-form-field/ 1496 | ```python 1497 | field = mc.execute(method='update_form_field', id=104, fieldId='AnnualRevenue', label='Revenue', labelWidth=150, 1498 | fieldWidth=150, instructions='please fill out this field', 1499 | required=False, formPrefill=True, initiallyChecked=None, values=None, labelToRight=None, 1500 | hintText='hint', defaultValue=100, minValue=100, maxValue=1000000, multiSelect=None, 1501 | maxLength=None, maskInput=None, visibleLines=None) 1502 | 1503 | # only id and fieldId are required, all others are optional 1504 | ``` 1505 | 1506 | Remove Form Field 1507 | ----------------- 1508 | API Ref: http://developers.marketo.com/documentation/marketo-rest-apis-web-page-objects/remove-form-field/ 1509 | ```python 1510 | field = mc.execute(method='delete_form_field', id=104, fieldId='AnnualRevenue') 1511 | ``` 1512 | 1513 | Update Form Field Visibility Rules 1514 | ---------------------------------- 1515 | API Ref: http://developers.marketo.com/documentation/marketo-rest-apis-web-page-objects/update-form-field-visibility-rules/ 1516 | ```python 1517 | not yet implemented 1518 | ``` 1519 | 1520 | Add Rich Text Form Field 1521 | ------------------ 1522 | API Ref: http://developers.marketo.com/documentation/marketo-rest-apis-web-page-objects/add-rich-text-form-field/ 1523 | ```python 1524 | not yet implemented 1525 | ``` 1526 | 1527 | Add Fieldset 1528 | ------------ 1529 | API Ref: http://developers.marketo.com/documentation/marketo-rest-apis-web-page-objects/add-fieldset/ 1530 | ```python 1531 | not yet implemented 1532 | ``` 1533 | 1534 | Remove Field from Fieldset 1535 | -------------------------- 1536 | API Ref: http://developers.marketo.com/documentation/marketo-rest-apis-web-page-objects/remove-field-from-fieldset/ 1537 | ```python 1538 | not yet implemented 1539 | ``` 1540 | 1541 | Get Available Form Fields 1542 | ------------------ 1543 | API Ref: http://developers.marketo.com/documentation/marketo-rest-apis-web-page-objects/get-available-form-fields/ 1544 | ```python 1545 | not yet implemented 1546 | ``` 1547 | 1548 | Change Form Field Positions 1549 | -------------------------- 1550 | API Ref: http://developers.marketo.com/documentation/marketo-rest-apis-web-page-objects/change-form-field-positions/ 1551 | ```python 1552 | not yet implemented 1553 | ``` 1554 | 1555 | Update Submit Button 1556 | -------------------- 1557 | API Ref: http://developers.marketo.com/documentation/marketo-rest-apis-web-page-objects/update-submit-button/ 1558 | ```python 1559 | not yet implemented 1560 | ``` 1561 | 1562 | 1563 | Files 1564 | ======== 1565 | 1566 | Create File 1567 | ------------- 1568 | API Ref: http://developers.marketo.com/documentation/asset-api/create-a-file/ 1569 | ```python 1570 | lead = mc.execute(method='create_file', name='Marketo-Logo.jpg', file='Marketo-Logo.jpg', folder=115, description=None) 1571 | 1572 | # NOTE: the behavior of the call will change; this describes current behavior 1573 | # description is optional 1574 | # insertOnly is documented in the API Ref but it is non-functional 1575 | # 'name' needs to match the 'file' name, otherwise you get error 709 "Upload file name and/or extension is 1576 | # different from name in parameter" 1577 | # in 'file', specify a path if file is not in the same folder as the Python script 1578 | ``` 1579 | 1580 | Get File by Id 1581 | -------------- 1582 | API Ref: http://developers.marketo.com/documentation/asset-api/get-file-by-id/ 1583 | ```python 1584 | try: 1585 | file = mc.execute(method='get_file_by_id', id=16837) 1586 | except KeyError: 1587 | file = False 1588 | ``` 1589 | 1590 | Get File by Name 1591 | ---------------- 1592 | API Ref: http://developers.marketo.com/documentation/asset-api/get-file-by-name/ 1593 | ```python 1594 | try: 1595 | file = mc.execute(method='get_file_by_name', name='clogo8.jpg') 1596 | except KeyError: 1597 | file = False 1598 | ``` 1599 | 1600 | List Files 1601 | ---------- 1602 | API Ref: http://developers.marketo.com/documentation/asset-api/list-files/ 1603 | ```python 1604 | lead = mc.execute(method='list_files', folder=709, maxReturn=None) 1605 | 1606 | # folder and maxReturn are optional; default for maxReturn is 20 and max is 200 1607 | ``` 1608 | 1609 | Update File Content 1610 | ------------- 1611 | API Ref: http://developers.marketo.com/documentation/asset-api/update-file-content/ 1612 | ```python 1613 | file = mc.execute(method='update_file_content', id=23307, file='Marketo-Logo-Large.jpg') 1614 | 1615 | # in 'file', specify a path if file is not in the same folder as the Python script 1616 | ``` 1617 | 1618 | Snippets 1619 | ======== 1620 | 1621 | Create Snippet 1622 | -------------- 1623 | API Ref: http://developers.marketo.com/documentation/asset-api/create-snippet/ 1624 | ```python 1625 | snippet = mc.execute(method='create_snippet', folderId=132, folderType="Folder", name="API Snippet", description=None) 1626 | 1627 | # description is optional 1628 | ``` 1629 | 1630 | Get Snippet By Id 1631 | ----------------- 1632 | API Ref: http://developers.marketo.com/documentation/asset-api/get-snippet-by-id/ 1633 | ```python 1634 | snippet = mc.execute(method='get_snippet_by_id', id=9) 1635 | ``` 1636 | 1637 | Delete Snippet 1638 | -------------- 1639 | API Ref: http://developers.marketo.com/documentation/asset-api/delete-snippet-by-id/ 1640 | ```python 1641 | snippet = mc.execute(method='delete_snippet', id=9) 1642 | ``` 1643 | 1644 | Update Snippet 1645 | -------------- 1646 | API Ref: http://developers.marketo.com/documentation/asset-api/update-snippet/ 1647 | ```python 1648 | snippet = mc.execute(method='update_snippet', id=9, name="API Snippet 2", description='Hello New Description') 1649 | ``` 1650 | 1651 | Get Snippets 1652 | ------------ 1653 | API Ref: http://developers.marketo.com/documentation/asset-api/update-snippet/ 1654 | ```python 1655 | snippets = mc.execute(method='get_snippets', maxReturn=None) 1656 | 1657 | # maxReturn is optional; default for maxReturn is 20 and max is 200 1658 | ``` 1659 | 1660 | Get Snippet Content 1661 | ------------------- 1662 | API Ref: http://developers.marketo.com/documentation/asset-api/get-snippet-content-by-id/ 1663 | ```python 1664 | snippet = mc.execute(method='get_snippet_content', id=9, status=None) 1665 | 1666 | # status is optional and can be 'draft' or 'approved' 1667 | ``` 1668 | 1669 | Update Snippet Content 1670 | ---------------------- 1671 | API Ref: http://developers.marketo.com/documentation/asset-api/update-snippet-content-by-id/ 1672 | ```python 1673 | html_content = 'Hello World
' 1674 | snippet = mc.execute(method='update_snippet_content', id=9, type='HTML', content=html_content) 1675 | ``` 1676 | 1677 | Approve Snippet 1678 | --------------- 1679 | API Ref: http://developers.marketo.com/documentation/asset-api/approve-snippet-by-id/ 1680 | ```python 1681 | snippet = mc.execute(method='approve_snippet', id=9) 1682 | ``` 1683 | 1684 | Unapprove Snippet 1685 | ------------------- 1686 | API Ref: http://developers.marketo.com/documentation/asset-api/unapprove-snippet-by-id/ 1687 | ```python 1688 | snippet = mc.execute(method='unapprove_snippet', id=9) 1689 | ``` 1690 | 1691 | Discard Snippet Draft 1692 | --------------------- 1693 | API Ref: http://developers.marketo.com/documentation/asset-api/discard-snippet-draft-by-id/ 1694 | ```python 1695 | snippet = mc.execute(method='discard_snippet_draft', id=9) 1696 | ``` 1697 | 1698 | Clone Snippet 1699 | -------------- 1700 | API Ref: http://developers.marketo.com/documentation/asset-api/clone-snippet/ 1701 | ```python 1702 | snippet = mc.execute(method='clone_snippet', id=9, name='Cloned Snippet', folderId=132, folderType='Folder', 1703 | description=None) 1704 | 1705 | # description is optional 1706 | ``` 1707 | 1708 | Update Snippet Dynamic Content 1709 | ------------------- 1710 | API Ref: http://developers.marketo.com/documentation/asset-api/update-snippet-dynamic-content-by-id/ 1711 | ```python 1712 | snippet = mc.execute(method='update_snippet_dynamic_content', id=9, segmentId=1008, 1713 | value='Text in Dutch
', type='HTML') 1714 | ``` 1715 | 1716 | Get Snippet Dynamic Content 1717 | ------------------- 1718 | API Ref: http://developers.marketo.com/documentation/asset-api/get-snippet-dynamic-content-by-id/ 1719 | ```python 1720 | snippet = mc.execute(method='get_snippet_dynamic_content', id=9) 1721 | ``` 1722 | 1723 | Segmentations 1724 | ============= 1725 | 1726 | Get Segmentations 1727 | ----------------- 1728 | API Ref: http://developers.marketo.com/documentation/asset-api/get-segmentation-by-id/ 1729 | ```python 1730 | segmentations = mc.execute(method='get_segmentations', status='approved') 1731 | 1732 | # status is optional; values are 'draft' or 'approved' 1733 | ``` 1734 | 1735 | Get Segments 1736 | ----------------- 1737 | API Ref: http://developers.marketo.com/documentation/asset-api/get-segments/ 1738 | ```python 1739 | segments = mc.execute(method='get_segments', id=1001, status=None) 1740 | 1741 | # status is optional; values are 'draft' or 'approved' 1742 | ``` 1743 | 1744 | 1745 | Landing Page Templates 1746 | =============== 1747 | 1748 | Create Landing Page Template 1749 | --------------------- 1750 | API Ref: http://developers.marketo.com/documentation/asset-api/create-landing-page-template/ 1751 | ```python 1752 | template = mc.execute(method='create_landing_page_template', name='API LP Template', folderId=11, 1753 | folderType='Folder', description='Description', templateType='freeForm') 1754 | 1755 | # description and templateType are optional; templateType can be freeForm (default) or guided 1756 | ``` 1757 | 1758 | Get Landing Page Template by Id 1759 | ------------------------ 1760 | API Ref: http://developers.marketo.com/documentation/asset-api/get-landing-page-template-by-id/ 1761 | ```python 1762 | template = mc.execute(method='get_landing_page_template_by_id', id=30, status='approved') 1763 | 1764 | # status is optional; values are 'draft' or 'approved'; a single landing page can have both an approved and a draft 1765 | # version 1766 | ``` 1767 | 1768 | Get Landing Page Template by Name 1769 | ------------------------ 1770 | API Ref: http://developers.marketo.com/documentation/asset-api/get-landing-page-template-by-name/ 1771 | ```python 1772 | template = mc.execute(method='get_landing_page_template_by_name', name='API LP Template', status='draft') 1773 | 1774 | # status is optional: values are 'draft' or 'approved'; a single landing page can have both an approved and a draft 1775 | # version 1776 | ``` 1777 | 1778 | Update Landing Page Template 1779 | --------------------- 1780 | API Ref: http://developers.marketo.com/documentation/asset-api/update-landing-page-template/ 1781 | ```python 1782 | template = mc.execute(method='update_landing_page_template', id=59, name='API LP Template 2', description=None) 1783 | 1784 | # name and description are optional, but - of course - you want to pass in at least 1 of them 1785 | # this is only to update name and description, use 'Update Landing Page Template Content' to update the HTML 1786 | ``` 1787 | 1788 | Delete Landing Page Template 1789 | --------------------- 1790 | API Ref: N/A 1791 | ```python 1792 | template = mc.execute(method='delete_landing_page_template', id=64) 1793 | ``` 1794 | 1795 | Get Landing Page Templates 1796 | ------------------- 1797 | API Ref: http://developers.marketo.com/documentation/asset-api/get-multiple-landing-page-templates/ 1798 | ```python 1799 | template = mc.execute(method='get_landing_page_templates', status='approved', folderId=842, folderType='Folder') 1800 | 1801 | # status, folderId, folderType and maxReturn are optional; status is 'draft' or 'approved' 1802 | # default for maxReturn is 20 and max is 200 1803 | # if you specify status, it will return an approved landing page with a draft for both status='draft' AND status='approved' 1804 | ``` 1805 | 1806 | Get Landing Page Template Content 1807 | -------------------------- 1808 | API Ref: http://developers.marketo.com/documentation/asset-api/get-landing-page-template-content/ 1809 | ```python 1810 | template = mc.execute(method='get_landing_page_template_content', id=30) 1811 | with open('landing-page-template-content-2.html', 'w', encoding='utf-8') as f: 1812 | f.write(template[0]['content']) 1813 | 1814 | # status is optional: values are 'draft' or 'approved' 1815 | ``` 1816 | 1817 | Update Landing Page Template Content 1818 | ----------------------------- 1819 | API Ref: http://developers.marketo.com/documentation/asset-api/update-landing-page-template-content-by-id/ 1820 | ```python 1821 | template = mc.execute(method='update_landing_page_template_content', id=59, content='LP-template-content.html') 1822 | 1823 | # 'content' points to a file 1824 | ``` 1825 | 1826 | Approve Landing Page Template 1827 | ---------------------- 1828 | API Ref: N/A 1829 | ```python 1830 | template = mc.execute(method='approve_landing_page_template', id=61) 1831 | ``` 1832 | 1833 | Unapprove Landing Page Template 1834 | ---------------------- 1835 | API Ref: N/A 1836 | ```python 1837 | template = mc.execute(method='unapprove_landing_page_template', id=61) 1838 | ``` 1839 | 1840 | Discard Landing Page Template Draft 1841 | ---------------------------- 1842 | API Ref: N/A 1843 | ```python 1844 | template = mc.execute(method='discard_landing_page_template_draft', id=42) 1845 | ``` 1846 | 1847 | Clone Landing Page Template 1848 | -------------------- 1849 | API Ref: N/A 1850 | ```python 1851 | template = mc.execute(method='clone_landing_page_template', id=42, name='cloned landing page template', 1852 | folderId=11, folderType='Folder') 1853 | 1854 | # folderId 11 is the Landing Page Templates folder in the Default workspace 1855 | ``` 1856 | 1857 | 1858 | Programs 1859 | ======== 1860 | 1861 | Create Program 1862 | -------------- 1863 | API Ref: http://developers.marketo.com/documentation/programs/create-a-program/ 1864 | ```python 1865 | tags = {'Language': 'English'} 1866 | costs = '[{"startDate":"2015-01-01","cost":2000,"note":""}]' 1867 | program = mc.execute(method='create_program', folderId=28, folderType='Folder', name='Program Name', 1868 | description='new Program', type='Default', channel='Operational', tags=tags, costs=costs) 1869 | 1870 | # description, tags and costs are optional 1871 | # the 'note' parameter in 'costs' is currently required but will be made optional in a future release 1872 | ``` 1873 | 1874 | Get Program by Id 1875 | ----------------- 1876 | API Ref: http://developers.marketo.com/documentation/programs/get-program-by-id/ 1877 | ```python 1878 | try: 1879 | lead = mc.execute(method='get_program_by_id', id=1014) 1880 | except KeyError: 1881 | lead = False 1882 | ``` 1883 | 1884 | Get Program by Name 1885 | ------------------- 1886 | API Ref: http://developers.marketo.com/documentation/programs/get-program-by-name/ 1887 | ```python 1888 | try: 1889 | lead = mc.execute(method='get_program_by_name', name='Email Program Test') 1890 | except KeyError: 1891 | lead = False 1892 | ``` 1893 | 1894 | Get Program by Tag Type 1895 | ----------------------- 1896 | API Ref: http://developers.marketo.com/documentation/programs/get-programs-by-tag-type/ 1897 | ```python 1898 | try: 1899 | program = mc.execute(method='get_program_by_tag_type', tagType='Language', tagValue='English', maxReturn=20) 1900 | except KeyError: 1901 | program = False 1902 | # maxReturn defaults to 20 and can be set to 200 max; this loops and gets all programs with the specific Tag & Value 1903 | ``` 1904 | 1905 | Update Program 1906 | -------------- 1907 | API Ref: http://developers.marketo.com/documentation/programs/update-program/ 1908 | ```python 1909 | tags = {'Language': 'English'} 1910 | program = mc.execute(method='update_program', id=1160, name='Updated Name', description='description update', tags=tags) 1911 | 1912 | # the 'costs' and 'costsDestructiveUpdate' parameters as mentioned in the docs are not implemented yet 1913 | ``` 1914 | 1915 | Delete Program 1916 | -------------- 1917 | API Ref: http://developers.marketo.com/documentation/programs/delete-program-by-id/ 1918 | ```python 1919 | program = mc.execute(method='delete_program', id=1208) 1920 | ``` 1921 | 1922 | Browse Programs 1923 | --------------- 1924 | API Ref: http://developers.marketo.com/documentation/programs/browse-programs/ 1925 | ```python 1926 | lead = mc.execute(method='browse_programs', status='completed', maxReturn=200) 1927 | 1928 | # status and maxReturn are optional; default for maxReturn is 20 and max is 200 1929 | ``` 1930 | 1931 | Clone Program 1932 | ------------- 1933 | API Ref: http://developers.marketo.com/documentation/programs/clone-program/ 1934 | ```python 1935 | program = mc.execute(method='clone_program', id=1207, name="Program Clone", folderId=28, folderType='Folder', 1936 | description="this is a description") 1937 | 1938 | # description is optional 1939 | ``` 1940 | 1941 | Approve Program 1942 | --------------- 1943 | API Ref: http://developers.marketo.com/documentation/programs/approve-program/ 1944 | ```python 1945 | program = mc.execute(method='approve_program', id=1208) 1946 | ``` 1947 | 1948 | Unapprove Program 1949 | ----------------- 1950 | API Ref: http://developers.marketo.com/documentation/programs/unapprove-program/ 1951 | ```python 1952 | program = mc.execute(method='approve_program', id=1208) 1953 | ``` 1954 | 1955 | Get Smart List by Program Id 1956 | -------------------------- 1957 | API Ref: https://developers.marketo.com/rest-api/endpoint-reference/asset-endpoint-reference/#!/Programs/getSmartListByProgramIdUsingGET 1958 | ```python 1959 | smart_list = mc.execute(method='get_smart_list_by_program_id', id=123, includeRules=True, 1960 | return_full_result=False) 1961 | # only works to get the built-in Smart List for Email Programs 1962 | # set includeRules to False if you do not want to get all filters of the smart list in the response 1963 | ``` 1964 | 1965 | Get Channels 1966 | ------------ 1967 | API Ref: http://developers.marketo.com/documentation/programs/get-channels/ 1968 | ```python 1969 | channels = mc.execute(method='get_channels', maxReturn=None) 1970 | 1971 | # maxReturn is optional; default for maxReturn is 20 and max is 200 1972 | ``` 1973 | 1974 | Get Channel by Name 1975 | ------------------- 1976 | API Ref: http://developers.marketo.com/documentation/programs/get-channel-by-name/ 1977 | ```python 1978 | try: 1979 | channel = mc.execute(method='get_channel_by_name', name="Nurture") 1980 | except KeyError: 1981 | channel = False 1982 | ``` 1983 | 1984 | Get Tags 1985 | -------- 1986 | API Ref: http://developers.marketo.com/documentation/programs/get-tags/ 1987 | ```python 1988 | tags = mc.execute(method='get_tags', maxReturn=None) 1989 | 1990 | # maxReturn is optional; default for maxReturn is 20 and max is 200 1991 | ``` 1992 | 1993 | Get Tag by Name 1994 | --------------- 1995 | API Ref: http://developers.marketo.com/documentation/programs/get-tag-by-name/ 1996 | ```python 1997 | try: 1998 | tag = mc.execute(method='get_tag_by_name', name="Language") 1999 | except KeyError: 2000 | tag = False 2001 | ``` 2002 | 2003 | Custom Object Types 2004 | =================== 2005 | 2006 | Create/Update Custom Object Type 2007 | ----------------------------------- 2008 | API Ref: https://developers.marketo.com/rest-api/endpoint-reference/lead-database-endpoint-reference/#!/Custom_Objects/syncCustomObjectTypeUsingPOST 2009 | ```python 2010 | resultType = mc.execute(method='create_update_custom_object_type', apiName='transactions', displayName='Transactions', action='createOnly', description='Transactions custom object for the transactions') 2011 | ``` 2012 | 2013 | Delete Custom Object Type 2014 | ------------------------- 2015 | API Ref: https://developers.marketo.com/rest-api/endpoint-reference/lead-database-endpoint-reference/#!/Custom_Objects/deleteCustomObjectsUsingPOST 2016 | ```python 2017 | result = mc.execute(method='delete_custom_object_type', apiName='transactions') 2018 | ``` 2019 | 2020 | Approve Custom Object Type 2021 | -------------------------- 2022 | API Ref: https://developers.marketo.com/rest-api/endpoint-reference/lead-database-endpoint-reference/#!/Custom_Objects/approveCustomObjectTypeUsingPOST 2023 | ```python 2024 | result = mc.execute(method='approve_custom_object_type', apiName='transactions') 2025 | ``` 2026 | 2027 | Discard Custom Object Type Draft 2028 | -------------------------------- 2029 | API Ref: https://developers.marketo.com/rest-api/endpoint-reference/lead-database-endpoint-reference/#!/Custom_Objects/discardCustomObjectTypeUsingPOST 2030 | ```python 2031 | result = mc.execute(method='discard_custom_object_type', apiName='transactions') 2032 | ``` 2033 | 2034 | Add Custom Object Type Fields 2035 | ----------------------------- 2036 | API Ref: https://developers.marketo.com/rest-api/endpoint-reference/lead-database-endpoint-reference/#!/Custom_Objects/addCustomObjectTypeFieldsUsingPOST 2037 | ```python 2038 | fields = [{"displayName": "Email", "description": "Email", "name": "email", "dataType": "link", "relatedTo": {"name": "lead", "field": "email"}}, 2039 | {"displayName": "Transaction ID", "description": "Transaction ID", "name": "txid", "dataType": "integer", "isDedupeField": True}, 2040 | {"displayName": "Total", "description": "Transaction total", "name": "total", "dataType": "float"}] 2041 | result = mc.execute(method='add_field_custom_object_type', apiName='transactions',fields=fields) 2042 | ``` 2043 | 2044 | List Custom Object Types 2045 | ------------------------ 2046 | API Ref: https://developers.marketo.com/rest-api/endpoint-reference/lead-database-endpoint-reference/#!/Custom_Objects/listCustomObjectTypesUsingGET 2047 | ```python 2048 | coTypes = mc.execute(method='get_list_of_custom_object_types') 2049 | ``` 2050 | 2051 | Describe Custom Object Type 2052 | --------------------------- 2053 | API Ref: https://developers.marketo.com/rest-api/endpoint-reference/lead-database-endpoint-reference/#!/Custom_Objects/describeCustomObjectTypeUsingGET 2054 | ```python 2055 | description = mc.execute(method='describe_custom_object_type') 2056 | ``` 2057 | 2058 | ** Not currently implemented ** 2059 | 2060 | Delete Custom Object Type Fields 2061 | -------------------------------- 2062 | https://developers.marketo.com/rest-api/endpoint-reference/lead-database-endpoint-reference/#!/Custom_Objects/deleteCustomObjectTypeFieldsUsingPOST 2063 | 2064 | Update Custom Object Type Field 2065 | ------------------------------- 2066 | https://developers.marketo.com/rest-api/endpoint-reference/lead-database-endpoint-reference/#!/Custom_Objects/updateCustomObjectTypeFieldUsingPOST 2067 | 2068 | Get Custom Object Type Field Data Types 2069 | --------------------------------------- 2070 | https://developers.marketo.com/rest-api/endpoint-reference/lead-database-endpoint-reference/#!/Custom_Objects/getCustomObjectTypeFieldDataTypesUsingGET 2071 | 2072 | Get Custom Object Linkable Objects 2073 | ---------------------------------- 2074 | https://developers.marketo.com/rest-api/endpoint-reference/lead-database-endpoint-reference/#!/Custom_Objects/getCustomObjectTypeLinkableObjectsUsingGET 2075 | 2076 | Get Custom Object Dependent Assets 2077 | ---------------------------------- 2078 | https://developers.marketo.com/rest-api/endpoint-reference/lead-database-endpoint-reference/#!/Custom_Objects/getCustomObjectTypeDependentAssetsUsingGET 2079 | 2080 | 2081 | Custom Objects 2082 | ============== 2083 | 2084 | Get List of Custom Objects 2085 | -------------------------- 2086 | API Ref: http://developers.marketo.com/documentation/custom-api/get-list-of-custom-objects/ 2087 | ```python 2088 | result = mc.execute(method='get_list_of_custom_objects', names=['Order', 'Test']) 2089 | 2090 | # names is optional 2091 | ``` 2092 | 2093 | Describe Custom Object 2094 | ---------------------- 2095 | API Ref: http://developers.marketo.com/documentation/custom-api/describe-custom-object/ 2096 | ```python 2097 | result = mc.execute(method='describe_custom_object', name='Campaigns') 2098 | ``` 2099 | 2100 | Create/Update Custom Objects 2101 | ---------------------------- 2102 | API Ref: http://developers.marketo.com/documentation/custom-api/createupdateupsert-custom-objects/ 2103 | ```python 2104 | custom_objects = [{'TK_ID': 'abc123', 'PartNo_1': 'ABC', 'CatalogDescription_1': 'ABC Description'}, 2105 | {'TK_ID': 'abc123', 'PartNo_1': 'DEF', 'CatalogDescription_1': 'DEF Description'}] 2106 | result = mc.execute(method='create_update_custom_objects', name='Campaigns', input=custom_objects, action=None, dedupeBy=None) 2107 | 2108 | # action and dedupeBy are optional 2109 | ``` 2110 | 2111 | Delete Custom Objects 2112 | --------------------- 2113 | API Ref: http://developers.marketo.com/documentation/custom-api/delete-custom-objects/ 2114 | ```python 2115 | custom_objects = [{'TK_ID': 'abc123', 'PartNo_1': 'ABC'}] 2116 | result = mc.execute(method='delete_custom_objects', name='Campaigns', input=custom_objects, deleteBy=None) 2117 | 2118 | # dedupeBy is optional 2119 | # in the example above there are 2 dedupe fields 2120 | ``` 2121 | 2122 | Get Custom Objects 2123 | ------------------ 2124 | API Ref: http://developers.marketo.com/documentation/custom-api/get-custom-objects/ 2125 | ```python 2126 | query = [{'TK_ID': 'abc123', 'ListID': 123},{'TK_ID': 'abc123', 'ListID': 12396}] 2127 | result = mc.execute(method='get_custom_objects', input=query, name='Campaigns', filterType='dedupeFields', 2128 | fields=['TK_ID', 'ListID', 'PartNo_1'], batchSize=None) 2129 | 2130 | query2 = [{'marketoGUID': 'eadc92fb-17ef-4e4d-bb20-73aee1a0d57e'}] 2131 | result2 = mc.execute(method='get_custom_objects', input=query2, name='Campaigns', filterType='idField') 2132 | 2133 | query3 = [{'TK_ID': 'abc123'}] 2134 | result3 = mc.execute(method='get_custom_objects', input=query3, name='Campaigns', filterType='TK_ID') 2135 | 2136 | # fields and batchSize are optional 2137 | # in the first example there are two dedupeFields, which is why the dictionary has two keys; the 'link' field is also 2138 | # searchable, but then 'filterType' needs to be the name of that field. 2139 | ``` 2140 | 2141 | Opportunity Object 2142 | ================== 2143 | 2144 | Describe Opportunity 2145 | -------------------- 2146 | API Ref: http://developers.marketo.com/documentation/opportunity-api/describe-opportunity/ 2147 | ```python 2148 | result = mc.execute(method='describe_opportunity') 2149 | ``` 2150 | 2151 | Create/Update Opportunities 2152 | --------------------------- 2153 | API Ref: http://developers.marketo.com/documentation/opportunity-api/createupdateupsert-opportunities/ 2154 | ```python 2155 | opportunities = [{'externalOpportunityId': 'O000004', 'externalCompanyId': 'C000003', 'name': 'Test Opportunity', 2156 | 'amount': 5000, 'closeDate': '2016-06-30', 'isClosed': False, 'stage': 'Qualification', 2157 | 'externalSalesPersonId': 'sam@test.com'}] 2158 | result = mc.execute(method='create_update_opportunities', input=opportunities, action=None, dedupeBy=None) 2159 | 2160 | # action and dedupeBy are optional 2161 | # action can be createOnly, updateOnly or createOrUpdate (default) 2162 | # dedupeBy is dedupeFields (default) or idField 2163 | ``` 2164 | 2165 | Delete Opportunities 2166 | -------------------- 2167 | API Ref: http://developers.marketo.com/documentation/opportunity-api/delete-opportunities/ 2168 | ```python 2169 | opportunities = [{"externalOpportunityId": "O000004"}] 2170 | result = mc.execute(method='delete_opportunities', input=opportunities, deleteBy=None) 2171 | 2172 | # deleteBy is optional; it can be dedupeFields (default) or idField 2173 | ``` 2174 | 2175 | Get Opportunities 2176 | ----------------- 2177 | API Ref: http://developers.marketo.com/documentation/opportunity-api/get-opportunities/ 2178 | ```python 2179 | result = mc.execute(method='get_opportunities', filterType='externalOpportunityId', filterValues=['O000003'], 2180 | fields=['name', 'amount', 'closeDate', 'stage']) 2181 | #result = mc.execute(method='get_opportunities', filterType='externalCompanyId', filterValues=['C000003']) 2182 | 2183 | # fields and batchSize are optional; default and maximum batch size is 300 2184 | ``` 2185 | 2186 | Describe Opportunity Roles 2187 | -------------------- 2188 | API Ref: http://developers.marketo.com/documentation/opportunity-api/describe-opportunity-role/ 2189 | ```python 2190 | result = mc.execute(method='describe_opportunity_role') 2191 | ``` 2192 | 2193 | Create/Update Opportunities Roles 2194 | --------------------------------- 2195 | API Ref: http://developers.marketo.com/documentation/opportunity-api/createupdateupsert-opportunities-roles/ 2196 | ```python 2197 | opportunities_roles = [{'externalOpportunityId': 'O000004', 'leadId': 2, 'role': 'Technical Buyer', 'isPrimary': False}] 2198 | result = mc.execute(method='create_update_opportunities_roles', input=opportunities_roles, action=None, dedupeBy=None) 2199 | 2200 | # action and dedupeBy are optional 2201 | # action can be createOnly, updateOnly or createOrUpdate (default) 2202 | # dedupeBy is dedupeFields (default) or idField 2203 | ``` 2204 | 2205 | Delete Opportunity Roles 2206 | ------------------------ 2207 | API Ref: http://developers.marketo.com/documentation/opportunity-api/delete-opportunity-roles/ 2208 | ```python 2209 | opportunities = [{'externalOpportunityId': 'O000004', 'leadId': 2, 'role': 'Technical Buyer'}] 2210 | result = mc.execute(method='delete_opportunity_roles', input=opportunities, deleteBy=None) 2211 | 2212 | # deleteBy is optional; it can be dedupeFields (default, all 3 fields shown) or idField 2213 | ``` 2214 | 2215 | Get Opportunity Roles 2216 | --------------------- 2217 | API Ref: http://developers.marketo.com/documentation/opportunity-api/get-opportunity-roles/ 2218 | ```python 2219 | result = mc.execute(method='get_opportunity_roles', filterType='externalOpportunityId', filterValues=['O000003']) 2220 | #result = mc.execute(method='get_opportunity_roles', filterType='marketoGUID', filterValues=['63ea3a3f-1b35-4723-850e-99b41b14a636']) 2221 | #result = mc.execute(method='get_opportunity_roles', filterType='leadId', filterValues=['2']) 2222 | 2223 | # fields and batchSize are optional; default and maximum batch size is 300 2224 | ``` 2225 | 2226 | 2227 | Company Object 2228 | ============== 2229 | 2230 | Describe Company 2231 | ---------------- 2232 | API Ref: http://developers.marketo.com/documentation/company-api/describe-company/ 2233 | ```python 2234 | company = mc.execute(method='describe_company') 2235 | ``` 2236 | 2237 | Create/Update Companies 2238 | ----------------------- 2239 | API Ref: http://developers.marketo.com/documentation/company-api/createupdateupsert-companies/ 2240 | ```python 2241 | companies = [{'externalCompanyId': 'C000001', 'company': 'Acme 1', 'website': 'http://www.acme1.com', 2242 | 'numberOfEmployees': 856, 'billingCity': 'San Mateo', 'billingState': 'CA'}, 2243 | {'externalCompanyId': 'C000002', 'company': 'Acme 2', 'website': 'http://www.acme2.com', 2244 | 'numberOfEmployees': 114, 'billingCity': 'Redmond', 'billingState': 'WA'}] 2245 | company = mc.execute(method='create_update_companies', input=companies, action=None, dedupeBy=None) 2246 | 2247 | # action and dedupeBy are optional 2248 | ``` 2249 | 2250 | Delete Companies 2251 | ----------- 2252 | API Ref: http://developers.marketo.com/documentation/company-api/delete-companies/ 2253 | ```python 2254 | companies = [{'externalCompanyId': 'C000003'}] 2255 | company = mc.execute(method='delete_companies', input=companies, deleteBy=None) 2256 | 2257 | # deleteBy is optional; values can be dedupeFields (default) or idField 2258 | ``` 2259 | OR: 2260 | ```python 2261 | companies = [{'id': 8}] 2262 | company = mc.execute(method='delete_companies', input=companies, deleteBy='idField') 2263 | ``` 2264 | 2265 | Get Companies 2266 | ----------- 2267 | API Ref: http://developers.marketo.com/documentation/company-api/get-companies/ 2268 | ```python 2269 | result = mc.execute(method='get_companies', filterType='company', filterValues=['Acme 1', 'Acme 2'], 2270 | fields=['company', 'billingCity', 'billingState', 'website', 'numberOfEmployees'], batchSize=None) 2271 | 2272 | # fields and batchSize are optional 2273 | # filterType can be: externalCompanyId, id, externalSalesPersonId, company 2274 | ``` 2275 | 2276 | Sales Person Object 2277 | ============== 2278 | 2279 | Describe Sales Person 2280 | ---------------- 2281 | API Ref: http://developers.marketo.com/documentation/sales-persons/describe-sales-person/ 2282 | ```python 2283 | salesperson = mc.execute(method='describe_sales_person') 2284 | ``` 2285 | 2286 | Create/Update Sales Persons 2287 | ----------------------- 2288 | API Ref: http://developers.marketo.com/documentation/sales-persons/createupdateupsert-sales-persons/ 2289 | ```python 2290 | salespeople = [{"externalSalesPersonId":"sam@test.com", "email":"sam@test.com", "firstName":"Sam", "lastName":"Sanosin"}, 2291 | {"externalSalesPersonId":"david@test.com", "email":"david@test.com", "firstName":"David", "lastName":"Aulassak"}] 2292 | result = mc.execute(method='create_update_sales_persons', input=salespeople, action=None, dedupeBy=None) 2293 | 2294 | # action and dedupeBy are optional 2295 | ``` 2296 | 2297 | Delete Sales Persons 2298 | ----------- 2299 | API Ref: http://developers.marketo.com/documentation/sales-persons/delete-sales-persons/ 2300 | ```python 2301 | salespeople = [{"externalSalesPersonId":"sam@test.com"}] 2302 | result = mc.execute(method='delete_sales_persons', input=salespeople, deleteBy=None) 2303 | 2304 | # deleteBy is optional; values can be dedupeFields (default) or idField 2305 | ``` 2306 | 2307 | Get Sales Persons 2308 | ----------- 2309 | API Ref: http://developers.marketo.com/documentation/sales-persons/get-sales-persons/ 2310 | ```python 2311 | result = mc.execute(method='get_sales_persons', filterType='externalSalesPersonId', filterValues=['sam@test.com'], 2312 | fields=None, batchSize=None) 2313 | 2314 | # fields and batchSize are optional 2315 | # filterType can be: externalSalesPersonId, id, email 2316 | ``` 2317 | 2318 | Bulk Export Leads/Activities/Custom Objects/Program Members 2319 | ============== 2320 | 2321 | > Replace 'activities' with 'leads', 'custom_objects' or 'program_members' in below to get the equivalent for leads, 2322 | > custom objects and program members export. For Custom Objects, the `object_name` attribute is always required. 2323 | 2324 | List Bulk Export Activities Jobs 2325 | ---------------- 2326 | API Ref: http://developers.marketo.com/rest-api/endpoint-reference/lead-database-endpoint-reference/#!/Bulk_Export_Activities/getExportActivitiesUsingGET 2327 | ```python 2328 | export_jobs = mc.execute(method='get_activities_export_jobs_list') 2329 | ``` 2330 | 2331 | List Bulk Export Custom Objects Jobs 2332 | ---------------- 2333 | ```python 2334 | export_jobs = mc.execute(method='get_activities_export_jobs_list', object_name='pet_c') 2335 | 2336 | # `object_name` is required; this is the same for all Custom Object bulk export calls 2337 | ``` 2338 | 2339 | Create Bulk Export Activities Job 2340 | ---------------- 2341 | API Ref: http://developers.marketo.com/rest-api/endpoint-reference/lead-database-endpoint-reference/#!/Bulk_Export_Activities/createExportActivitiesUsingPOST 2342 | ```python 2343 | new_export_job_details = mc.execute(method='create_activities_export_job', fields=['string', 'string'], filters={'createdAt': {'endAt': '2017-11-02', 'startAt': '2017-11-01'}}) 2344 | ``` 2345 | 2346 | Create Bulk Export Custom Object Job 2347 | ---------------- 2348 | ```python 2349 | new_export_job_details = mc.execute(method='create_custom_objects_export_job', object_name='pet_c', fields=['string', 'string'], filters={'staticListId': 1025}) 2350 | 2351 | # `object_name`, `fields` and `filters` are all required 2352 | ``` 2353 | 2354 | Cancel Bulk Export Activities Job 2355 | ---------------- 2356 | API Ref: http://developers.marketo.com/rest-api/endpoint-reference/lead-database-endpoint-reference/#!/Bulk_Export_Activities/cancelExportActivitiesUsingPOST 2357 | ```python 2358 | new_export_job_details = mc.execute(method='cancel_activities_export_job', job_id='284742ec-1e5a-46f2-b164-498a41fcaaf6') 2359 | ``` 2360 | 2361 | Enqueue Bulk Export Activities Job 2362 | ---------------- 2363 | API Ref: http://developers.marketo.com/rest-api/endpoint-reference/lead-database-endpoint-reference/#!/Bulk_Export_Activities/enqueueExportActivitiesUsingPOST 2364 | ```python 2365 | enqueued_job_details = mc.execute(method='enqueue_activities_export_job', job_id='284742ec-1e5a-46f2-b164-498a41fcaaf6') 2366 | ``` 2367 | 2368 | Get Bulk Export Activities Job Status 2369 | ---------------- 2370 | API Ref: http://developers.marketo.com/rest-api/endpoint-reference/lead-database-endpoint-reference/#!/Bulk_Export_Activities/getExportActivitiesStatusUsingGET 2371 | ```python 2372 | export_job_status = mc.execute(method='get_activities_export_job_status', job_id='284742ec-1e5a-46f2-b164-498a41fcaaf6') 2373 | ``` 2374 | 2375 | Get Bulk Export Activities File 2376 | ---------------- 2377 | API Ref: http://developers.marketo.com/rest-api/endpoint-reference/lead-database-endpoint-reference/#!/Bulk_Export_Activities/getExportActivitiesFileUsingGET 2378 | ```python 2379 | export_file_contents = mc.execute(method='get_activities_export_job_file', job_id='284742ec-1e5a-46f2-b164-498a41fcaaf6') 2380 | ``` 2381 | Or use streaming: 2382 | ```python 2383 | with mc.execute(method='get_activities_export_job_file', job_id='284742ec-1e5a-46f2-b164-498a41fcaaf6', stream=True) as r: 2384 | with open('filename.csv', 'wb') as f: 2385 | for chunk in r.iter_content(chunk_size=1024): 2386 | if chunk: 2387 | f.write(chunk) 2388 | # set your preferred chunk_size 2389 | ``` 2390 | 2391 | Named Account Object 2392 | ============== 2393 | 2394 | Describe Named Accounts 2395 | ---------------- 2396 | ```python 2397 | mc.execute(method='describe_named_accounts') 2398 | ``` 2399 | 2400 | Get Named Accounts 2401 | ----------------- 2402 | ```python 2403 | for accounts in mc.execute(method='get_named_accounts', filterType='name', filterValues='Acme', 2404 | fields='name,score1,annualRevenue', batchSize=None, return_full_result=False, 2405 | nextPageToken=None): 2406 | print(accounts) 2407 | 2408 | # filterType may be any single field returned in the searchableFields member of the describe result for named accounts 2409 | # specify up to 300 filterValues comma-separated or as a list; you are out of luck if your filterValues have commas 2410 | # default and maximum batchSize is 300 (in the response) 2411 | # return_full_result=True will return requestId and nextPageToken 2412 | # nextPageToken: optional; normally you wouldn't need it, unless you are resuming a prior export 2413 | ``` 2414 | 2415 | Get Named Account Lists 2416 | ----------------- 2417 | ```python 2418 | for lists in mc.execute(method='get_named_account_lists', filterType='dedupeFields', filterValues='Accounts Tier 1', 2419 | batchSize=None, return_full_result=False, nextPageToken=None): 2420 | print(lists) 2421 | 2422 | # instead of 'dedupeFields' you can also use 'idField', which would be the marketoGUID 2423 | # specify up to 300 filterValues comma-separated or as a list; you are out of luck if your filterValues have commas 2424 | # default and maximum batchSize is 300 (in the response) 2425 | # return_full_result=True will return requestId and nextPageToken 2426 | # nextPageToken: optional; normally you wouldn't need it, unless you are resuming a prior export 2427 | ``` 2428 | 2429 | Get Named Account List Members 2430 | ------------------ 2431 | ```python 2432 | for accounts in mc.execute(method='get_named_account_list_members', id='d5080d12-a40c-4b9f-ae01-453bdf662fdd', 2433 | fields='name,score1', batchSize=None, return_full_result=False, nextPageToken=None): 2434 | print(accounts) 2435 | 2436 | # default and maximum batchSize is 300 2437 | # return_full_result=True will return requestId and nextPageToken 2438 | # nextPageToken: optional; normally you wouldn't need it, unless you are resuming a prior export 2439 | ``` 2440 | 2441 | Other Named Account Methods 2442 | ------ 2443 | There are stubs for other Named Account methods in `client.py` but those aren't implemented yet. 2444 | 2445 | 2446 | 2447 | 2448 | Programming Conventions 2449 | ======================= 2450 | Conventions used for functions: 2451 | * functions mirror as closely as possible how the functions work in the Marketo REST API; exceptions: 2452 | get_lead_activities, get_lead_changes and get_deleted_leads where you can pass in a datetime directly rather 2453 | than having to use get_paging_token (which you can still use, if you want to) 2454 | * name of the function is exactly the same as on the Marketo Developer website, but lowercase with spaces replaced by 2455 | underscores, and "by Id" removed in case "by Id" is the only option 2456 | * variables are written exactly the same as in the Marketo REST API, even though they should be lower case according to 2457 | PEP8 2458 | * all required variables are checked on whether they're passed in, if not we raise a ValueError 2459 | * functions return the 'result' node from the Marketo REST API response; if there is no 'result' node, 'success' is 2460 | returned (which is true/false) 2461 | * if the Marketo REST API returns an error, it will raise a Python error with error code and details, which can be 2462 | handled in your code through try/except 2463 | * the variable in with the API response is loaded is called 'result' also (so result['result'] is what is returned) 2464 | * the client will loop if the number of results is greater than the batch size; it will then return all results 2465 | together; this is not always ideal, because large data sets may take lots of processing time and memory; 2466 | * batchSize is offered as a parameter (if available), but should usually be left blank 2467 | * calls that support both GET and POST are implemented as POST to handle more data (for example: long lists of fields) 2468 | * folder IDs are split up in Id and Type parameters 2469 | * some parameters names shadow build-ins, which is not ideal, but done for consistency with the Marketo API parameters 2470 | -------------------------------------------------------------------------------- /marketorestpython/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jepcastelein/marketo-rest-python/140975d26984bf65d1a4435a073c96135c2a7db4/marketorestpython/__init__.py -------------------------------------------------------------------------------- /marketorestpython/helper/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jepcastelein/marketo-rest-python/140975d26984bf65d1a4435a073c96135c2a7db4/marketorestpython/helper/__init__.py -------------------------------------------------------------------------------- /marketorestpython/helper/exceptions.py: -------------------------------------------------------------------------------- 1 | 2 | class MarketoException(Exception): 3 | message = None 4 | code = None 5 | def __init__(self, exc = {'message':None,'code':None}): 6 | self.message = exc['message'] 7 | self.code = exc['code'] 8 | 9 | def __str__(self): 10 | return "Marketo API Error Code {}: {}".format(self.code, self.message) 11 | -------------------------------------------------------------------------------- /marketorestpython/helper/http_lib.py: -------------------------------------------------------------------------------- 1 | import mimetypes 2 | import time 3 | 4 | import backoff 5 | import requests 6 | 7 | from marketorestpython.helper.exceptions import MarketoException 8 | 9 | retryable_error_codes = { 10 | '502': 'Bad Gateway', 11 | '604': 'Request timed out', 12 | '606': 'Max rate limit exceeded', 13 | '608': 'API Temporarily Unavailable', 14 | '615': 'Concurrent access limit reached', 15 | '713': 'Transient Error', 16 | '1014': 'Failed to create Object', 17 | '1016': 'Too many imports', 18 | '1019': 'Import in progress', 19 | '1022': 'Object in use', 20 | '1029': 'Too many jobs in queue' 21 | } 22 | 23 | 24 | def fatal_marketo_error_code(e): 25 | # Given a MarketoException, decide whether it is fatal or retryable. 26 | return e.code not in retryable_error_codes or 'Export daily quota' in e.message 27 | 28 | 29 | class HttpLib: 30 | num_calls_per_second = 5 # five calls per second max (at 100/20 rate limit) 31 | 32 | def __init__(self, max_retry_time_conf, requests_timeout): 33 | global max_retry_time 34 | max_retry_time = max_retry_time_conf 35 | self.requests_timeout = requests_timeout 36 | 37 | def lookup_max_time(): 38 | # this function is needed to dynamically set the max_time for backoff; should not have 'self' 39 | global max_retry_time 40 | return max_retry_time 41 | 42 | def _rate_limited(maxPerSecond): 43 | minInterval = 1.0 / float(maxPerSecond) 44 | def decorate(func): 45 | lastTimeCalled = [0.0] 46 | def rateLimitedFunction(*args,**kargs): 47 | elapsed = time.time() - lastTimeCalled[0] 48 | leftToWait = minInterval - elapsed 49 | if leftToWait>0: 50 | time.sleep(leftToWait) 51 | ret = func(*args,**kargs) 52 | lastTimeCalled[0] = time.time() 53 | return ret 54 | return rateLimitedFunction 55 | return decorate 56 | 57 | @backoff.on_exception(backoff.expo, MarketoException, 58 | max_time=lookup_max_time, 59 | giveup=fatal_marketo_error_code) 60 | @_rate_limited(num_calls_per_second) 61 | def get(self, endpoint, args=None, mode=None, stream=False): 62 | headers = {'Accept-Encoding': 'gzip'} 63 | r = requests.get(endpoint, params=args, headers=headers, stream=stream, timeout=self.requests_timeout) 64 | if mode == 'nojson': 65 | return r 66 | else: 67 | r_json = r.json() 68 | if mode == 'accesstoken' or r_json.get('success'): 69 | return r_json 70 | else: 71 | raise MarketoException(r_json['errors'][0]) 72 | 73 | @backoff.on_exception(backoff.expo, MarketoException, 74 | max_time=lookup_max_time, 75 | giveup=fatal_marketo_error_code) 76 | @_rate_limited(num_calls_per_second) 77 | def post(self, endpoint, args, data=None, files=None, filename=None, 78 | mode=None, stream=False): 79 | if mode == 'nojsondumps': 80 | headers = {'Content-type': 'application/x-www-form-urlencoded; charset=utf-8'} 81 | r = requests.post(endpoint, params=args, data=data, headers=headers, timeout=self.requests_timeout) 82 | elif files is None: 83 | headers = {'Content-type': 'application/json; charset=utf-8'} 84 | r = requests.post(endpoint, params=args, json=data, headers=headers, timeout=self.requests_timeout) 85 | elif files is not None: 86 | mimetype = mimetypes.guess_type(files)[0] 87 | file = {filename: (files, open(files, 'rb'), mimetype)} 88 | r = requests.post(endpoint, params=args, json=data, files=file, timeout=self.requests_timeout) 89 | r_json = r.json() 90 | if r_json.get('success'): 91 | return r_json 92 | else: 93 | raise MarketoException(r_json['errors'][0]) 94 | 95 | @backoff.on_exception(backoff.expo, MarketoException, 96 | max_time=lookup_max_time, giveup=fatal_marketo_error_code) 97 | @_rate_limited(num_calls_per_second) 98 | def delete(self, endpoint, args, data): 99 | headers = {'Content-type': 'application/json; charset=utf-8'} 100 | r = requests.delete(endpoint, params=args, json=data, headers=headers, timeout=self.requests_timeout) 101 | r_json = r.json() 102 | if r_json.get('success'): 103 | return r.json() 104 | else: 105 | raise MarketoException(r_json['errors'][0]) 106 | -------------------------------------------------------------------------------- /python-logo-master-v3-TM.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jepcastelein/marketo-rest-python/140975d26984bf65d1a4435a073c96135c2a7db4/python-logo-master-v3-TM.png -------------------------------------------------------------------------------- /requirements-tests.txt: -------------------------------------------------------------------------------- 1 | pytest==4.2.0 2 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | backoff==1.8.0 2 | requests==2.21.0 3 | pytz==2019.3 4 | -------------------------------------------------------------------------------- /setup.cfg: -------------------------------------------------------------------------------- 1 | [metadata] 2 | description-file = README.md -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | import os 2 | import sys 3 | 4 | try: 5 | from setuptools import setup 6 | except ImportError: 7 | from distutils.core import setup 8 | 9 | # Don't import analytics-python module here, since deps may not be installed 10 | # sys.path.insert(0, os.path.join(os.path.dirname(__file__), 'pymarketo')) 11 | 12 | # OLD DO NOT USE: 13 | # python setup.py register -r pypi 14 | # python setup.py sdist upload -r pypi 15 | 16 | # NEW PYPI UPLOAD METHOD: 17 | # python setup.py sdist 18 | # twine upload dist/* 19 | 20 | long_description = ''' 21 | Marketo Python REST is a Python client that wraps the Marketo Rest API. 22 | Originally developed by asamat with contributions from sandipsinha and osamakhn 23 | ''' 24 | 25 | setup( 26 | name='marketorestpython', 27 | version= '0.5.24', 28 | url='https://github.com/jepcastelein/marketo-rest-python', 29 | author='Jep Castelein', 30 | author_email='jep@castelein.net', 31 | packages=['marketorestpython', 'marketorestpython.helper'], 32 | license='MIT License', 33 | install_requires=[ 34 | 'backoff', 35 | 'requests', 36 | 'pytz' 37 | ], 38 | keywords = ['Marketo', 'REST API', 'Wrapper', 'Client'], 39 | description='Python Client for the Marketo REST API', 40 | long_description=long_description 41 | ) 42 | -------------------------------------------------------------------------------- /test_script.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | import json, os, uuid, time, logging 4 | from random import randint 5 | from marketorestpython.client import MarketoClient 6 | 7 | logging.basicConfig(level=logging.INFO) 8 | logger = logging.getLogger() 9 | 10 | try: 11 | # Travis testing 12 | MUNCHKIN_ID = os.environ['MUNCHKIN_ID'] 13 | CLIENT_ID = os.environ['CLIENT_ID'] 14 | CLIENT_SECRET = os.environ['CLIENT_SECRET'] 15 | except KeyError: 16 | # local testing 17 | with open('conf.json', 'r', encoding='utf-8') as f: 18 | creds = json.loads(f.read()) 19 | MUNCHKIN_ID = creds['munchkin_id'] 20 | CLIENT_ID = creds['client_id'] 21 | CLIENT_SECRET = creds['client_secret'] 22 | 23 | mc = MarketoClient(munchkin_id=MUNCHKIN_ID, client_id=CLIENT_ID, client_secret=CLIENT_SECRET) 24 | 25 | segmentation_id = 1001 26 | 27 | lead_id_1 = None 28 | lead_id_2 = None 29 | file_id = None 30 | list_folder_id = None 31 | smart_list_folder_id = None 32 | new_folder_id = None 33 | list_id = None 34 | files_folder_id = None 35 | bulk_lead_export_id = None 36 | list_name = uuid.uuid4() 37 | cloned_smart_list_id = None 38 | 39 | 40 | def test_create_update_leads(): 41 | random_number = randint(100, 999) 42 | email1 = "joe{}@example.com".format(random_number) 43 | email2 = "jill{}@example.com".format(random_number) 44 | leads = [{"email": email1, "firstName": "Joey"}, {"email": email2, "firstName": "Jillian"}] 45 | response = mc.execute(method='create_update_leads', leads=leads) 46 | global lead_id_1 47 | lead_id_1 = response[0]['id'] 48 | global lead_id_2 49 | lead_id_2 = response[1]['id'] 50 | assert response[0]['status'] in ['created','updated'] and response[1]['status'] in ['created','updated'] 51 | 52 | 53 | def test_get_folder_by_name(): 54 | global list_folder_id 55 | global smart_list_folder_id 56 | list_folder = mc.execute(method='get_folder_by_name', name='Group Lists') 57 | smart_list_folder = mc.execute(method='get_folder_by_name', name='Group Smart Lists') 58 | print(list_folder) 59 | list_folder_id = list_folder[0]['id'] 60 | smart_list_folder_id = smart_list_folder[0]['id'] 61 | print('list_folder_id: {}'.format(list_folder_id)) 62 | print('smart_list_folder_id: {}'.format(smart_list_folder_id)) 63 | logger.info('smart_list_folder: {}'.format(smart_list_folder_id)) 64 | assert list_folder_id and smart_list_folder_id 65 | 66 | 67 | def test_create_folder(): 68 | global new_folder_id 69 | new_folder = mc.execute(method='create_folder', name='temp test folder', 70 | parentId=19, 71 | parentType='Folder', description='temp description') 72 | new_folder_id = new_folder[0]['id'] 73 | print(new_folder_id) 74 | assert new_folder_id 75 | 76 | 77 | def test_create_token(): 78 | global new_folder_id 79 | token_value = 'Important—
' 80 | new_token = mc.execute(method='create_token', id=new_folder_id, 81 | folderType='Folder', 82 | type='rich text', name='test token', 83 | value=token_value) 84 | # this assert is failing in Python 2.7 because of unicode issues; passes in 3.6 85 | # assert new_token[0]['tokens'][0]['value'] == token_value 86 | assert new_token 87 | 88 | 89 | def test_delete_folder(): 90 | global new_folder_id 91 | deleted_folder = mc.execute(method='delete_folder', id=new_folder_id) 92 | assert deleted_folder 93 | 94 | 95 | def test_create_list(): 96 | global list_folder_id 97 | global list_id 98 | global list_name 99 | static_list = mc.execute(method='create_list', name=list_name, folderId=list_folder_id, folderType='Folder') 100 | print(static_list) 101 | list_id = static_list[0]['id'] 102 | assert static_list 103 | 104 | 105 | def test_update_list(): 106 | global list_id 107 | global list_name 108 | static_list = mc.execute(method='update_list', id=list_id, name='{} (renamed)'.format(list_name), 109 | description='added description') 110 | print(static_list) 111 | assert static_list 112 | 113 | 114 | def test_get_list_by_id(): 115 | global list_id 116 | global list_name 117 | static_list = mc.execute(method='get_list_by_id', id=list_id) 118 | assert static_list[0]['name'] == '{} (renamed)'.format(list_name) 119 | 120 | 121 | def test_get_list_by_name(): 122 | global list_id 123 | global list_name 124 | new_list_name = '{} (renamed)'.format(list_name) 125 | static_list = mc.execute(method='get_list_by_name', name=new_list_name) 126 | assert static_list[0]['id'] == list_id 127 | 128 | 129 | def test_get_multiple_lists(): 130 | global list_id 131 | global list_name 132 | new_list_name = '{} (renamed)'.format(list_name) 133 | static_list = mc.execute(method='get_multiple_lists', name=new_list_name) 134 | assert static_list[0]['id'] == list_id 135 | 136 | 137 | def test_browse_lists(): 138 | global list_folder_id 139 | static_lists = mc.execute(method='browse_lists', folderId=list_folder_id, folderType='Folder', 140 | earliestUpdatedAt='2019-02-01') 141 | assert len(static_lists) >= 1 142 | 143 | 144 | def test_add_leads_to_list(): 145 | global lead_id_1 146 | global lead_id_2 147 | global list_id 148 | add_to_list = mc.execute(method='add_leads_to_list', listId=list_id, id=[lead_id_1, lead_id_2]) 149 | assert add_to_list[0]['status'] == 'added' and add_to_list[1]['status'] == 'added' 150 | 151 | 152 | def test_create_lead_export_job(): 153 | global list_id 154 | global bulk_lead_export_id 155 | job = mc.execute(method='create_leads_export_job', fields=['firstName', 'lastName', 'email'], 156 | filters={'staticListId': list_id}) 157 | bulk_lead_export_id = job[0]['exportId'] 158 | assert job[0]['status'] == 'Created' 159 | 160 | 161 | def test_enqueue_lead_export_job(): 162 | global bulk_lead_export_id 163 | enqueued_job_details = mc.execute(method='enqueue_leads_export_job', 164 | job_id=bulk_lead_export_id) 165 | assert enqueued_job_details[0]['status'] == 'Queued' 166 | 167 | 168 | def test_cancel_lead_export_job(): 169 | global bulk_lead_export_id 170 | cancelled_job = mc.execute(method='cancel_leads_export_job', 171 | job_id=bulk_lead_export_id) 172 | assert cancelled_job[0]['status'] == 'Cancelled' 173 | 174 | 175 | def test_segments(): 176 | segments = mc.execute(method='get_segments', id=segmentation_id) 177 | assert segments 178 | 179 | 180 | def test_get_files_folder_by_name(): 181 | global files_folder_id 182 | files_folder = mc.execute(method='get_folder_by_name', name='Images and Files') 183 | print(files_folder ) 184 | files_folder_id = files_folder [0]['id'] 185 | print(list_folder_id) 186 | 187 | 188 | def test_create_file(): 189 | global file_id 190 | file = mc.execute(method='create_file', name='python-logo-master-v3-TM.png', file='python-logo-master-v3-TM.png', 191 | folder=files_folder_id, description='test file', insertOnly=False) 192 | print(file) 193 | file_id = file[0]['id'] 194 | assert file 195 | 196 | 197 | def test_update_file_content(): 198 | global file_id 199 | file = mc.execute(method='update_file_content', id=file_id, file='python-logo-master-v3-TM.png') 200 | assert file 201 | 202 | 203 | def get_file_by_id(): 204 | global file_id 205 | file = mc.execute(method='get_file_by_id', id=file_id) 206 | assert file 207 | 208 | 209 | def list_files(): 210 | files = mc.execute(method='list_files', folder=files_folder_id, offset=0, maxReturn=10) 211 | assert files 212 | 213 | 214 | def test_error_handling(): 215 | try: 216 | token = mc.execute(method='get_paging_token', sinceDatetime='2015-04-0113') 217 | e_dict = None 218 | print(token) 219 | except Exception as e: 220 | print('error: {}'.format(e)) 221 | e_dict = eval(str(e)) 222 | if 'code' in e_dict: 223 | print('code: {}'.format(e_dict['code'])) 224 | else: 225 | print('e_dict: {}'.format(e_dict)) 226 | assert e_dict['code'] == '1001' 227 | 228 | 229 | def test_delete_list(): 230 | global list_id 231 | list = mc.execute(method='delete_list', id = list_id) 232 | print(list) 233 | assert list 234 | 235 | 236 | def test_delete_leads(): 237 | global lead_id_1 238 | global lead_id_2 239 | response = mc.execute(method='delete_lead', id=[lead_id_1, lead_id_2]) 240 | assert response[0]['status'] == 'deleted' and response[1]['status'] == 'deleted' 241 | 242 | 243 | def test_get_smart_campaign_by_id(): 244 | campaign = mc.execute(method='get_smart_campaign_by_id', id=1109) 245 | assert campaign[0]['id'] == 1109 246 | 247 | 248 | def test_get_smart_campaigns(): 249 | first_campaigns = None 250 | second_campaigns = None 251 | third_campaigns = None 252 | for campaigns in mc.execute(method='get_smart_campaigns'): 253 | first_campaigns = campaigns 254 | logger.info('found {} campaigns'.format(len(campaigns))) 255 | break 256 | for campaigns in mc.execute(method='get_smart_campaigns', folderId=1031, folderType='Program'): 257 | second_campaigns = campaigns 258 | logger.info('found {} campaigns in Program 1031'.format(len(campaigns))) 259 | break 260 | for campaigns in mc.execute(method='get_smart_campaigns', offset=5, maxReturn=10): 261 | third_campaigns = campaigns 262 | logger.info('found {} campaigns with maxReturn=10'.format(len(campaigns))) 263 | break 264 | assert len(first_campaigns) > 20 and len(second_campaigns) == 2 and len(third_campaigns) == 10 265 | 266 | 267 | def test_activate_smart_campaign(): 268 | campaign = mc.execute(method='activate_smart_campaign', id=1109) 269 | assert campaign[0]['id'] == 1109 270 | 271 | 272 | def test_deactivate_smart_campaign(): 273 | campaign = mc.execute(method='deactivate_smart_campaign', id=1109) 274 | assert campaign[0]['id'] == 1109 275 | 276 | 277 | def test_get_smart_list_by_id(): 278 | original_smart_list = mc.execute(method='get_smart_list_by_id', id=5944) 279 | assert original_smart_list[0]['id'] == 5944 280 | 281 | 282 | def test_get_smart_list_by_name(): 283 | original_smart_list = mc.execute(method='get_smart_list_by_name', name='Do not delete') 284 | assert original_smart_list[0]['id'] == 5944 285 | 286 | 287 | def test_clone_smart_list(): 288 | global cloned_smart_list_id 289 | cloned_smart_list = mc.execute(method='clone_smart_list', id=5944, name='temp smart list', 290 | folderId=smart_list_folder_id, folderType='Folder', return_full_result=False) 291 | cloned_smart_list_id = cloned_smart_list[0]['id'] 292 | assert cloned_smart_list_id 293 | 294 | 295 | def get_smart_lists(): 296 | my_list_batch = [] 297 | for my_lists in mc.execute(method='get_smart_lists', folderId=smart_list_folder_id, folderType='Folder'): 298 | my_list_batch += my_lists 299 | assert len(my_list_batch) > 1 # we have the original and the cloned smart list 300 | 301 | 302 | def test_delete_smart_list(): 303 | deleted_smart_list = mc.execute(method='delete_smart_list', id=cloned_smart_list_id) 304 | assert deleted_smart_list 305 | 306 | def test_get_smart_list_by_smart_campaign_id(): 307 | campaign_smart_list = mc.execute(method='get_smart_list_by_smart_campaign_id', id=1125) 308 | assert len(campaign_smart_list) == 1 # there is only 1 trigger in this specific Smart Campaign's Smart List 309 | 310 | def test_get_smart_list_by_program_id(): 311 | email_program_smart_list = mc.execute(method='get_smart_list_by_program_id', id=1027) 312 | assert len(email_program_smart_list) == 1 # there is only 1 trigger in this specific Program's Smart List 313 | 314 | 315 | ''' 316 | mc2 = MarketoClient(munchkin_id=MUNCHKIN_ID, client_id=CLIENT_ID, client_secret=CLIENT_SECRET, max_retry_time=30) 317 | 318 | 319 | def test_max_retry_time(): 320 | day = 1 321 | time_elapsed = 0 322 | for i in range(11): 323 | start_time = time.time() 324 | export_filter = { 325 | "createdAt": { 326 | "startAt": "2018-07-0{}".format(day), 327 | "endAt": "2018-07-0{}".format(day+1) 328 | }, 329 | "activityTypeIds": [1] 330 | } 331 | job = mc2.execute(method='create_activities_export_job', filters=export_filter) 332 | job_id = job[0]['exportId'] 333 | try: 334 | enqueue = mc2.execute(method='enqueue_activities_export_job', job_id=job_id) 335 | except Exception as e: 336 | e_dict = eval(str(e)) 337 | logger.info('error: {}'.format(e_dict)) 338 | time_elapsed = time.time() - start_time 339 | break 340 | day += 1 341 | assert 30 < time_elapsed < 35 342 | ''' -------------------------------------------------------------------------------- /tests/tst_client.py: -------------------------------------------------------------------------------- 1 | import time 2 | import pytest 3 | 4 | from mock import patch, Mock 5 | 6 | from marketorestpython.client import MarketoClient 7 | 8 | 9 | @pytest.fixture 10 | def client(): 11 | return MarketoClient('123-FDY-456', 'randomclientid', 'supersecret') 12 | 13 | 14 | def test_marketo_client(client): 15 | assert client.host == 'https://123-FDY-456.mktorest.com' 16 | assert client.client_id == 'randomclientid' 17 | assert client.client_secret == 'supersecret' 18 | assert client.API_CALLS_MADE == 0 19 | assert client.API_LIMIT is None 20 | 21 | client = MarketoClient('123-FDY-456', 'randomclientid', 'supersecret', 20, requests_timeout=1.0) 22 | assert client.API_LIMIT == 20 23 | assert client.requests_timeout == 1.0 24 | 25 | invalid_requests_timeouts = ["a string", -1, (1,2,3), (1, -1), (1,"a string"), (1,)] 26 | for invalid_requests_timeout in invalid_requests_timeouts: 27 | with pytest.raises(AssertionError): 28 | MarketoClient('123-FDY-456', 'randomclientid', 'supersecret', 20, requests_timeout=invalid_requests_timeout) 29 | 30 | 31 | @patch('marketorestpython.client.HttpLib') 32 | def test_api_call(m_http_lib, client): 33 | get_request_mock = Mock(return_value={ 34 | 'access_token': '1234', 'expires_in': 1000, 'scope': '1' 35 | }) 36 | request_mock = Mock(get=get_request_mock) 37 | m_http_lib.return_value = request_mock 38 | args = (1, 2, 3) 39 | kwargs = {'a': 1, 'b': 2} 40 | client._api_call('get', '/test', *args, **kwargs) 41 | get_request_mock.assert_called_with(*(('/test',) + args), **kwargs) 42 | assert client.API_CALLS_MADE == 1 43 | 44 | limit = 4 45 | client = MarketoClient('123-FDY-456', 'randomclientid', 'supersecret', limit) 46 | with pytest.raises(Exception) as excinfo: 47 | for i in xrange(limit): 48 | client._api_call('get', '/test', *args, **kwargs) 49 | assert excinfo.value == { 50 | 'message': 'API Calls exceeded the limit : %s' % limit, 51 | 'code': '416' 52 | } 53 | 54 | 55 | @patch('marketorestpython.client.MarketoClient._api_call') 56 | def test_authenticate(m_client_api_call, client): 57 | m_client_api_call.return_value = None 58 | with pytest.raises(Exception): 59 | client.authenticate() 60 | 61 | access_token = "cdf01657-110d-4155-99a7-f986b2ff13a0:int" 62 | token_type = "bearer" 63 | expires_in = 3599 64 | scope = "apis@acmeinc.com" 65 | m_client_api_call.return_value = { 66 | "access_token": access_token, 67 | "token_type": token_type, 68 | "expires_in": expires_in, 69 | "scope": scope 70 | } 71 | 72 | client.authenticate() 73 | m_client_api_call.assert_called_with( 74 | 'get', 75 | client.host + '/identity/oauth/token', 76 | { 77 | 'grant_type': 'client_credentials', 78 | 'client_id': client.client_id, 79 | 'client_secret': client.client_secret, 80 | } 81 | ) 82 | 83 | assert client.token == access_token 84 | assert client.token_type == token_type 85 | assert client.expires_in == expires_in 86 | assert client.valid_until > time.time() 87 | assert client.scope == scope 88 | 89 | # credentials should still be valid 90 | client.authenticate() 91 | assert m_client_api_call.call_count == 2 92 | 93 | # test error handling 94 | client = MarketoClient('123-FDY-456', 'randomclientid', 'supersecret') 95 | m_client_api_call.return_value = { 96 | 'error': 'invalid_client', 97 | 'error_description': 'invalid secret' 98 | } 99 | with pytest.raises(Exception) as excinfo: 100 | client.authenticate() 101 | assert excinfo.value == 'invalid secret' 102 | --------------------------------------------------------------------------------