├── .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 | [![Build Status](https://travis-ci.org/jepcastelein/marketo-rest-python.svg?branch=master)](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

Aliquam nec erat at purus 1093 | cursus interdum
vestibulum ligula augue

''' 1094 | email = mc.execute(method='update_email_content_in_editable_section', id=275, htmlId='lt-column', type='Text', 1095 | value=html_content, textValue=None) 1096 | 1097 | # textValue is optional 1098 | # type can be 'Text', 'DynamicContent' or 'Snippet' 1099 | ``` 1100 | 1101 | Get Email Dynamic Content 1102 | ------------------------- 1103 | API Ref: http://developers.marketo.com/documentation/asset-api/get-email-dynamic-content-by-id/ 1104 | ```python 1105 | email = mc.execute(method='get_email_dynamic_content', id=279, dynamicContentId='RVMtU2VjdGlvbiAx', status=None) 1106 | 1107 | # status is optional and can be 'draft' or 'approved' 1108 | ``` 1109 | 1110 | Update Email Dynamic Content 1111 | ---------------------------- 1112 | API Ref: http://developers.marketo.com/documentation/asset-api/update-email-dynamic-content-by-id/ 1113 | ```python 1114 | email = mc.execute(method='update_email_dynamic_content', id=280, dynamicContentId='RVMtY29sdW1uX3N1YnRpdGxl', 1115 | segment='Dutch', value='

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 | --------------------------------------------------------------------------------