Explore how to use the Marketo Engage REST API to automate marketing operations tasks. This article covers common use cases for Marketo Engage admins, including streamlining campaign creation, reverting unwanted data changes, and translating engagement insights into actionable sales actions.
I have a background in Applied and Computational Mathematics, which sets me apart from most Marketo Engage practitioners. When I started working in marketing operations, I realized that much of the work could be automated. Automation can lead me to be more efficient in my job and have faster career growth. Using API to automate the day-to-day operations allows me to focus on more strategic subjects instead of being buried in operational tasks.
In this article, I share how I used the Marketo Engage REST API, introducing three of my favorite use cases to demonstrate its power. Let me show you how the REST API can become your ally in improving your efficiency in Marketo Engage, leading you to have more time to focus on strategic matters.
- Use case 1—Streamline campaign creation: How much time do you spend creating Marketo Engage campaigns? I'd bet this process consumes at least 2 hours of your day, and it is most likely this number is higher, depending on your career level. But the worst part of this task is that 90% of the campaign creation work is manual work, from copying to pasting. So, this task is a perfect candidate for automation!
- Use case 2—Revert unwanted data changes: Dealing with dirty data is the marketing operations team’s nightmare. You receive a list with many junk values and import it without cleaning it beforehand. Maybe you were too busy, and it went unnoticed. When you see the results in the Marketo Engage database, your heart skips a beat. Don't worry; let me show you how you can quickly fix a bad list import using an efficient method like REST API.
- Use case 3—Translate insights into sales actions: How many times do you have sales representatives asking you: "Why is this lead an MQL? What topics is this person engaged with?" To answer these questions, you have to dig into the Activity Log to identify why a person qualified as an MQL. In the demo section below, you will learn how to automate this data translation process using the REST API.
Now, buckle up, and get ready to learn how I use the REST API for these business scenarios.
Use case 1: Streamline campaign creation
Marketo Engage is a powerful tool for scaling marketing operations, with templates and tokens that help streamline processes. But let’s face it—there’s still many manual work involved. If you work in marketing operations, you probably spend a significant amount of time cloning programs, updating tokens, and activating Smart Campaigns.
If you are managing just a few campaigns per week, you might be able to keep up. But if you’re handling dozens—or even hundreds of campaigns, doing everything manually just isn’t practical. Mistakes happen, and ensuring consistency across campaigns becomes a real challenge. That’s where the Marketo Engage REST API comes in. By automating these repetitive tasks, you can save time, reduce errors, and maintain consistency across all your marketing efforts.
With the REST API, you can quickly clone entire programs while keeping everything structured and uniform. Even the most experienced Marketo Engage practitioners make mistakes, and automation minimizes the risk and helps maintain data integrity.
This process still allows your campaigns to be customized to fit your marketing needs. REST API allows you to modify key elements such as Tokens, while keeping your campaign structure consistent.
Watch the demo video below, where I explain how to use the sample codes provided and adjust them to cater to your organization’s needs.
Find the codes demonstrated in the video below for your offline use in the "Sample Codes" section.
Use case 2: Revert unwanted data changes
Imagine this scenario: You are already swamped with tasks when your marketers urgently request that you upload a lead list to Marketo Engage. You get it done quickly, only to hear from your SDRs that the data is all wrong! Job titles are incorrect, old leads have been overwritten, and everything is a mess.
This is a nightmare scenario for any Marketing Operations professional. Manually fixing these errors can take hours, if not days. But don’t worry, Marketo Engage’s REST API has a solution—it’s like a time machine for your data, allowing you to track and revert unwanted changes effortlessly.
By using the REST API, you can pull a log of recent data value changes, identify incorrect updates, and restore the original information in just a few steps. Instead of scrambling to clean up the data mess manually, you can automate the rollback process and ensure that your database remains accurate and reliable.
In the video below, let’s explore how you can use the REST API to reverse bad data imports and keep your Marketo Engage instance clean and error-free.
Find the codes demonstrated in the video below for your offline use in the "Sample Codes" section.
Use case 3: Translate insights into sales actions
For sales teams, context is everything—especially when it comes to understanding why a lead has become a Marketing Qualified Lead (MQL). But too often, the data behind that qualification is buried in layers of engagement metrics, making it time-consuming for sales representatives to piece together a person's story on their own.
That’s where automation comes in to address the struggle. By integrating Marketo Engage with AI, you can transform engagement data into clear, actionable insights that help sales teams focus on what really matters—closing deals.
Using the Marketo Engage REST API, you can pull recent engagement activities, process them through Generative AI to generate a concise summary, and push that summary back into Marketo Engage for visibility. This means sales representatives no longer have to sift through a person’s Activity Logs to understand how a lead became an MQL. Instead, they get a simple, AI-generated explanation of the lead’s journey. The summary includes which products or services they have shown interest in and any key actions they have taken with your brand.
By giving sales instant access to this information in Salesforce, they can approach conversations with confidence, personalize their outreach, and ultimately, close more deals faster.
This use case is meant to use the REST API when a lead transitions to an MQL. Therefore, it runs for just one lead at a time. If you are considering applying this method for a larger batch of leads, the Bulk API would be a better fit.
Let’s dive into the video below to see how this setup works in practice.
Find the codes demonstrated in the video below for your offline use in the "Sample Codes" section.
Key takeaways
That’s a wrap on how to streamline your marketing operations tasks with Marketo Engage REST APIs.
I covered three powerful use cases that you can use the REST APIs for:
- Automating campaign cloning to cut down on manual work and ensure consistency.
- Tracking and reverting unwanted data changes to save hours of cleanup time.
- Providing sales teams with instant insights into MQLs to enable more effective follow-up conversations.
These automation techniques aren’t just about saving time—they help ensure accuracy, maintain data integrity, and empower marketing and sales teams to work smarter.
It might be overwhelming to see so many possibilities by using the REST API, so I have a few tips for you:
- Start small. Try something simple first. Create your first API call and get the results. This first call helps you get excited about all you can do. Imagine yourself creating your first program!
- Learn how to code, and don’t be scared of it! Coding is easier than it looks. Many times, it can be just like writing in weird English. I prefer Python, and you can find great Python courses online to enroll in and learn.
- Connect with the community. There are many Marketo Engage API experts out there sharing their knowledge. Many times, you can even find their complete code online.
If you found this article useful, be sure to check out Adobe Experience League for more peer insights and best practices. Thanks for reading, and happy automating!
Sample codes
Streamline campaign creation
import requests
import pandas as pd
import json
import urllib.parse
MUNCHKIN = "YOUR-MUNCHKIN-ID"
client_id = "YOUR-CLIENT-ID"
client_secret= "YOUR-CLIENT-SECRET"
def get_access_token():
global client_id
global client_secret
global MUNCHKIN
params={'grant_type': 'client_credentials', 'client_id': client_id, 'client_secret': client_secret}
headers={'Accept-Encoding': 'gzip'}
url="https://"+MUNCHKIN+".mktorest.com/identity/oauth/token"
response=requests.get(url=url,params=params,headers=headers)
data=response.json()
return data['access_token']
templateID=5200
folderName="Active Webinars"
programName="WB-2025-02-20-Test"
eventName="Webinar Test"
eventDate="2025-02-20"
url="https://"+MUNCHKIN+".mktorest.com/rest/asset/v1/folder/byName.json"
token=get_access_token()
params={"name": folderName,
"type": "Folder",
"Content-Type": "application/x-www-form-urlencoded"}
headers={'Authorization': 'Bearer ' + token}
response=requests.get(url=url,params=params, headers=headers)
data=response.json()
print(data)
folderID=data['result'][0]["id"]
url="https://"+MUNCHKIN+".mktorest.com/rest/asset/v1/program/
↪"+str(templateID)+"/clone.json"
token=get_access_token()
params={"Content-Type": "application/x-www-form-urlencoded"}
headers={'Authorization': 'Bearer ' + token}
body="name="+programName+"&folder={'id':"+str(folderID)+",'type':'Folder'}" url=url+"?"+body
response=requests.post(url=url,params=params,headers=headers)
data=response.json()
print(data)
programid=data['result'][0]['id']
url="https://"+MUNCHKIN+".mktorest.com/rest/asset/v1/smartCampaigns.json"
token=get_access_token()
params={"Content-Type": "application/x-www-form-urlencoded"}
headers={'Authorization': 'Bearer ' + token}
body="folder={'id':"+str(programid)+",'type':'Program'}"
url=url+"?"+body
response=requests.get(url=url, params=params, headers=headers)
data=response.json()
campaigns=[]
for campaign in data['result']:
campaigns.append(campaign['id'])
print(campaigns)
for campaign in campaigns:
url="https://"+MUNCHKIN+".mktorest.com/rest/asset/v1/smartCampaign/
↪"+str(campaign)+"/activate.json"
token=get_access_token()
headers={'Authorization': 'Bearer ' + token}
response=requests.post(url=url,headers=headers)
data=response.json()
print(data)
url = "https://"+MUNCHKIN+".mktorest.com/rest/asset/v1/folder/
↪"+str(programid)+"/tokens.json"
token=get_access_token()
headers = {
"Authorization": f"Bearer {token}",
"Content-Type": "application/x-www-form-urlencoded"}
payload = {
"name": "Webinar Name",
"value": eventName,
"type": "text",
"folderType": "Program"}
response = requests.post(url, headers=headers, data=payload)
data=response.json()
data
url = "https://"+MUNCHKIN+".mktorest.com/rest/asset/v1/folder/
↪"+str(programid)+"/tokens.json"
token=get_access_token()
headers = {
"Authorization": f"Bearer {token}",
"Content-Type": "application/x-www-form-urlencoded"}
payload = {
"name": "Webinar Date",
"value": eventDate,
"type": "date",
"folderType": "Program"}
response = requests.post(url, headers=headers, data=payload)
data=response.json()
data
Revert unwanted data changes
import pandas as pd
import csv
import json
import ast
import requests
import math
MUNCHKIN = "YOUR-MUNCHKIN-ID"
client_id = "YOUR-CLIENT-ID"
client_secret= "YOUR-CLIENT-SECRET"
def get_access_token():
global client_id
global client_secret
global MUNCHKIN
params={'grant_type': 'client_credentials',
'client_id': client_id,
'client_secret': client_secret}
headers={'Accept-Encoding': 'gzip'}
url="https://"+MUNCHKIN+".mktorest.com/identity/oauth/token" response=requests.get(url=url,params=params,headers=headers)
data=response.json()
return data['access_token']
sinceDate="2025-04-22T00:00:00-00:00"
field='Job Title'
fieldRest='Title'
listID=299
url="https://"+MUNCHKIN+".mktorest.com/rest/v1/activities/pagingtoken.json"
token=get_access_token()
params={'sinceDatetime':sinceDate}
headers={'Authorization': 'Bearer ' + token,}
response=requests.get(url=url,params=params, headers=headers)
data=response.json()
nextPageToken=data['nextPageToken']
data
url="https://"+MUNCHKIN+".mktorest.com/rest/v1/activities.json"
params={'nextPageToken': nextPageToken,
'activityTypeIds':[13],
'listId': listID}
headers={'Authorization': 'Bearer ' + token,}
response=requests.get(url=url,params=params,headers=headers)
data=response.json()
print(data) act=data['result']
while data['moreResult']==True:
nextPageToken=data['nextPageToken']
token=get_access_token()
params={'nextPageToken': nextPageToken,
'activityTypeIds':[13],
'listId': listID}
headers={'Authorization': 'Bearer ' + token}
response=requests.get(url=url,params=params,headers=headers) data=response.json()
print(data)
act=act+(data['result'])
df=pd.json_normalize(act)
df=df[df['primaryAttributeValue']==field]
df=df.sort_values('activityDate')
df=df.reset_index()
df=df.drop(columns=['index'])
df
df1=pd.json_normalize(df['attributes'])
i=4
while i<len(df1.columns):
df1=df1.drop(columns=[list(df1.columns)[i]])
i=i+1
df1.columns=['New_Value','Old_Value','Reason','Source']
df1.New_Value=pd.json_normalize(df1.New_Value)['value']
df1.Old_Value=pd.json_normalize(df1.Old_Value)['value']
df1.Reason=pd.json_normalize(df1.Reason)['value']
df1.Source=pd.json_normalize(df1.Source)['value']
df=pd.merge(df,df1,left_index=True, right_index=True)
df=df.drop(columns=['attributes'])
df=df.drop_duplicates(subset='leadId', keep="first")
df
df.to_excel("dataToCorrect.xlsx")
ids=df[df.columns.to_list()[2]].to_list()
camposval=df['Old_Value'].to_list()
for i in range(len(camposval)):
if camposval[i] == None:
camposval[i] = 'NULL'
STEP=300
a=math.ceil(len(ids)/STEP)
i=0
while i<a:
tempids=ids[i*STEP:(i+1)*STEP]
tempcamposval=camposval[i*STEP:(i+1)*STEP]
params={'action': 'updateOnly',
'lookupField': 'id',
'input':[]}
j=0
while j<len(tempids):
lead={'id':tempids[j],
fieldRest:tempcamposval[j]}
params['input'].append(lead)
j=j+1
token=get_access_token()
url="https://"+MUNCHKIN+".mktorest.com/rest/v1/leads.json"
headers={'content-type': 'application/json', 'Authorization': 'Bearer ' + token }
i=i+1
response=requests.post(url=url,data=json.dumps(params), headers=headers)
print(response.json()['result'])
Translate insights into sales actions
importrequests
import pandas as pd
import json
fromdatetimeimportdatetime, timedelta
MUNCHKIN = "YOUR-MUNCHKIN-ID"
client_id = "YOUR-CLIENT-ID"
client_secret= "YOUR-CLIENT-SECRET"
defget_access_token():
globalclient_id
globalclient_secret
globalMUNCHKIN
params={'grant_type': 'client_credentials',
'client_id': client_id,
'client_secret': client_secret}
headers={'Accept-Encoding': 'gzip'}
url="https://"+MUNCHKIN+".mktorest.com/identity/oauth/token"
response=requests.get(url=url,params=params,headers=headers)
data=response.json()
return data['access_token']
leadid="1007244"
ndays=60
gptAPIKey="Bearer␣
↪sk-proj-ne6OZggjgQhQU6XcG0ocHNPNzBvOOULTkk8a-75Y75rHKS-vyztxPYq0OLaFsnhtGivx9bVUNoT3BlbkFJH
fieldName="MktoPersonNotes"
today = datetime.today()
sinceDate = today - timedelta(days=ndays)
sinceDate = sinceDate.strftime("%Y-%m-%dT00:00:00")
url="https://"+MUNCHKIN+".mktorest.com/rest/v1/activities/pagingtoken.json"
token=get_access_token()
params={'sinceDatetime': sinceDate}
headers={'Authorization': 'Bearer ' + token}
response=requests.get(url=url,params=params,headers=headers)
data=response.json()
nextPageToken=data['nextPageToken']
data
access_token=get_access_token()
def get_lead_activities(token, lead_id, firstToken):
url = f"https://"+MUNCHKIN+".mktorest.com/rest/v1/activities.json"
params={
"leadId": lead_id,
"activityTypeIds": "1,2,3,10,11,34,104",
"nextPageToken": firstToken
}
headers={'Authorization': 'Bearer ' + token}
activities = []
more_results = True
while more_results:
response = requests.get(url, params=params, headers=headers)
data = response.json()
if 'result' in data:
activities.extend(data['result'])
more_results = data.get('moreResult', False)
if more_results:
params["nextPageToken"] = data['nextPageToken']
return activities
all_activities = get_lead_activities(access_token, leadid,nextPageToken)
all_activities = str(all_activities).replace('"', "'")
activities=all_activities
activities
def send_to_chatgpt(activities):
url = "https://api.openai.com/v1/chat/completions"
headers = {
"Authorization": gptAPIKey,
"Content-Type": "application/json"
}
prompt = """Analyze the following lead activities and explain the␣
↪activities that contributed to this lead being marked as MQL so a␣
↪salesperson knows how they should approach the client, including which␣
↪product or service this lead is most interested in and any other relevant␣
↪insights. Include relevant URLs on form fills:""" +activities+""" – Remember␣
↪this will only be read by a salesperson, so don't use technical␣
↪explanations, just your best summary. Keep your response limited to 100␣
↪words."""
data = {
"model": "gpt-4o-mini",
"messages": [{"role": "user", "content": prompt}],
"max_tokens": 250
}
response = requests.post(url, headers=headers, json=data)
return response.json()
gpt_response = send_to_chatgpt(activities)['choices'][0]['message']['content']
gpt_response
def update_marketo_field(lead_id, field_name, gpt_response):
access_token=get_access_token()
url = "https://"+MUNCHKIN+".mktorest.com/rest/v1/leads.json"
headers = {
"Content-Type": "application/json",
'Authorization': 'Bearer ' + token
}
payload = {
"action": "updateOnly",
"lookupField": "id",
"input":[
{
"id": int(lead_id),
field_name: gpt_response
}
]
}
response = requests.post(url, headers=headers, json=payload)
return response.json()
update_response = update_marketo_field(leadid, fieldName, gpt_response)
update_response