Sanford Whiteman
a.k.a. “that guy” from the Marketo Community
who also blogs at https://blog.teknkl.com
and has created some Marketo apps
such as FlowBoost.
APPLICATION
PROGRAMMING
INTERFACE
= What your software talks to instead of talking directly to the Marketo platform
APIs ARE NOT
- DIRECT CONNECTIONS to the technical heart of a system
APIs ARE
- ABSTRACTIONS of an internal system for public consumption
- ALWAYS ABSTRACTS
- ALMOST NEVER OFFERS a superset of what you can do via a platform's native UI
- USUALLY OFFERS a marked subset
- SOMETIMES ALLOWS specific things you can't do in the UI (yay!)
- COMMONLY USES industry-standard formats, like JSON, XML, MIME, or Form-URL encoding
AN API...
APIs are ALL about
THEIR limits
- PROTECT back-end databases with a granular security and usage model
- FRACTION of performance of internal resources
- ONLY SUPPORT their documented functions
- PUT CAPS ON total and point-in-time use
APIs can guard AGAINST FALSE ADVERTISING
How can you tell when an integration salesperson is lying?
They just said, "We have a native connector"
APIS ARE not the only way (THE NEWISH WAY, THO)
AN INTERFACE IS JUST A PORT
NOT A DIRECT CONNECTION
P.T.T.I.*
Doesn't quite work with Marketo (and similar APIs).
* “Program to the Interface, not the Implementation”
The CLIENT APIs
Munchkin API
Forms JS API
The IN-FLOW APIs
Webhook API
Velocity API
The BULK (AND BULK-ISH) APIs
Bulk Lead/Activity Extract
Bulk Lead/Activity Export
Bulk Lead Import
The MARKETING APIs
Campaign Request/Schedule
Program/List Membership
The OBJECT APIs
Lead CRUD and Push
Marketo Custom Object/Activity
Marketo Oppty/Company/Sales
What we've got
The ASSET APIs
Static Files API
Email/LP Template APIs
Email/LP/Form APIs
A USER INTERFACE API
Customize menus, buttons, et al.
Branded flow options: FlowBoost It! instead of Call Webhook
What WE AIN'T GOT
A FORMS PREPROCESSOR API
Manage data between browser and database
YOUR HOPES AND DREAMS
Anything else you thought already worked
A CAMPAIGN UPDATE API
Reorder, create, delete SC steps
A REPORTING API
Execute and download UI-defined reports
MARKETO SAYS WE AIN'T GOT IT
BUT I SUSPECT SOMEONE DOES!
A PARTNER-ONLY API
- Unmetered (or partner-paid) API calls
- Specialized program-level attributes
What's {{Member.Webinar URL}}???
DON'T FLIP IT, NOR REVERSE (ENGINEER) IT
IN-FLow APIS
Run at campaign execution and/or email assembly; moderate scale
CLIENT APIS
Run in web browsers, designed for massive scale
OLD APIS
BULK AND BULK-ISH APIS
Awesome if actually used in bulk; terrible if used singly
OBJECT APIS
Use conservatively given business needs, bulkify madly
ASSET APIS
If flushed too often, don't scale, otherwise OK
APIs vs. ENDPOINTS
- API: collection of functions related to same object or feature, usually accessed with the same protocol
- Endpoint: a specific function within an API, usually with a unique URL
Upsert Lead (/lead.json) and Push Lead (/push.json) are endpoints within the REST Lead API.
Common cONUNDRUM: FEATURES EXIST, BUT not in a SINGLE API
- Webhooks: can read and update data in a flow, but can't access Custom Objects, only Leads and Companies
- Velocity: can read Custom Object data, but can't update Leads* or COs, only generate email content
- REST CO: can read and update Custom Object data, but can't scale and doesn't work in real-time
*or can it...?
STACK apis for ONE SOLUTION
- Forms JS + Webhook = reCAPTCHA
- Munchkin + Webhook = friendlify campaign IDs
- Webhook + REST = Custom Object from form fillout
- Velocity + Webhook + REST = Aggregate CO data
THE CLIENT APIS
THE CLIENT APIs
Vastly more scalable than server APIs
Designed to respond to individual public and/or anonymous activities
THE CLIENT APIs
- Munchkin API: create supplementary/synthetic Visit Web Page and Click Link activities and associate web sessions without a form
- Forms API: extend form validation and visibility rules, build new inter-field behaviors, onSubmit and onSuccess event capture
<button type="button">Button</button>
<button type="submit">Button</button>
<a href="#">Button</a>
<a href="https://example.com/getMy.pdf">Button</a>
The Munchkin API lets you fix missing hits
<button class="mchReDecorate" type="button">Button</button>
<script>
Array.from(document.querySelectorAll(".mchReDecorate"))
.forEach(function(decoratable){
decoratable.addEventListener("click", function(e){
Munchkin.munchkinFunction("clickLink", {
href : this.form.action ||
this.getAttribute("data-href") ||
this.href
});
});
});
);
</script>
The Munchkin API lets you fix missing hits
LIKE THE SCREENSHOT SAYS →
(1) FIDDLE (2) PROFIT
The FORMS JS API lets you DO... SO MUCH STUFF
The FORMS JS API lets you DO... NON-VISUAL STUFF, TOO
- Fix missing/quirky Hidden field features
- Create Referral forms and other cookie-related features
- Enable embedded Pre-Fill (using “the Whiteman technique”)
FORMS 2.0 JS API
RULES & REGS
- NEVER USE DOM document or window events !
- ONLY USE DOM input events if proven necessary
- LEARN Marketo's native behavior first
- LEARN HTML5 form standards first
HOW TO mESS UP A MARKETO FORMS INTEGRATION
- Use DOMContentLoaded/jQuery ready instead of Forms API whenReady or whenRendered
- Use document.getElementById("myId") instead of form.querySelector("#myId")
- Use input.value instead of form.getValues()
- Use <input id> instead of <input name>
- whenReady instead of whenRendered
- async tracking pixel in onSuccess
HOW TO mESS UP A FORMS INTEGRATION
Even when you use the API
form.onSuccess(function(vals, tyURL){
tracker.send("my ROI pixel");
document.location.href = tyURL;
});
- mismanage event stack order
The (MILDLY) SECRET FORMS ENDPOINT
THE FORMS ENDPOINT
Replaces broken integrations
THE FORMS ENDPOINT
- The “legacy” Marketo forms acceptor for <script>-less posts
- Returns HTTP 302, not JSON
- Integrates with flexible 3rd-party form builders like Unbounce
THE FORMS ENDPOINT
THe IN-FLOW APIS
Webhooks and Velocity
WEBHOOK CONCEPT ART
WEBHOOK BEST BETS
- Calculate and normalize permanent field values
- Count registrations across different leads
- Enrich via lookups in remote databases
- Relay lead data to other services
- Take the heat off REST (’hooks aren't metered)
WEBHOOK CAUTIONS
- ’Hooks can't create new leads
- Do have a practical limit though no hard daily max
- No direct access to Custom Object data
- Are partially async (trigger on change)
Which part is “THE WEBHOOK”?
-
the thing that gets called (remote service)?
-
the thing that calls (http client w/payload)?
-
the ACT of calling?
BRING IN THE POWER OF REMOTE SERVICES
BUILD OR BUY?
- Single-purpose 'hooks a code management headache
- Easiest language (PHP?) not as suitable for scale
- No matter how easy we make it sound, there's still code somewhere!
VELOCITY =
ALL of JAVA* —
not "Just" JavaScript —
plus some great open-source Apache libraries
* OK, all of Java 6
SURE, Velocity
is an API!
- Layer/s on top of Marketo db (datatype stringifying)
- New fields revealed like segment names
- Kind of an API on an API on an API (VTL language, Java, and Marketo objects)
Don't freak out!
VELOCITY POWER PLAYS
- LOCALIZE OUTPUT for language + country
- QUERY LOOKUP TABLES for product IDs, rep maps, etc.
- SORT, FILTER, OUTPUT CUSTOM OBJECTS in emails
- DATE/TIME MATH for upcoming events, appointments, special offers
- HYPER-SEGMENT output on combo of segmentations
- PROTECT COMPLEX CONTENT from rewriting, like Emojis
VELOCITY CAN REPLACE
- CLASSIC DYNAMIC CONTENT™ — with hyper-dynamic content decisions
- MANUALLY UPDATING {{MY.TOKENS}} — with lookups in a top-level token
- Lots of WEBHOOKS and API-DRIVEN “stamping” processes —with on-the-fly output
VELOCITEASE #1
#set( $inTimeZone = $date.getTimeZone().getTimeZone('America/New_York') )
#set( $outTimeZone = $date.getTimeZone().getTimeZone('America/New_York') )
#set( $locale = $date.getLocale() )
#set( $String = $context.getClass().forName("java.lang.String") )
#set( $LocaleFrom2Part = $locale.getClass().getConstructor($String,$String))
#set( $locales = {
"en_US" : $LocaleFrom2Part.newInstance("en","US"),
"fr_FR" : $LocaleFrom2Part.newInstance("fr","FR"),
"es_ES" : $LocaleFrom2Part.newInstance("es","ES"),
"pt_PT" : $LocaleFrom2Part.newInstance("pt","PT")
})
#set( $myDate = $convert.parseDate($lead.Member_Expire_Date,'yyyy-MM-dd',$locale,$inTimeZone) )
${date.format("d MMMM, yyyy",$myDate,$locales.en_US,$outTimeZone)}
${date.format("d MMMM yyyy",$myDate,$locales.fr_FR,$outTimeZone)}
${date.format("d 'de' MMMM 'de' yyyy",$myDate,$locales.es_ES,$outTimeZone)}
${date.format("d 'de' MMMM 'de' yyyy",$myDate,$locales.pt_PT,$outTimeZone)}
English output: March 31, 2018
French output: 31 mars 2018
Spanish output: 31 de marzo de 2018
Portuguese output: 31 de março de 2018
VELOCITEASE #2
#set( $secretKeySpec = $EncryptionTool.getKeySpec.newInstance(
$PreferenceCenterAESSecret.toString().trim().getBytes("ascii"),
"AES")
)
#set( $cipher = $javax.crypto.Cipher.getInstance("AES/ECB/PKCS5Padding") )
#set( $tmp = $cipher.init( $field.in($javax.crypto.Cipher).ENCRYPT_MODE, $secretKeySpec ) )
#set( $encrypted = $cipher.doFinal($PreferenceCenterPayload.toString().getBytes("utf8")) )
#set( $Base64Encoded = $EncodingTool.Base64.encoder.encodeBuffer( $encrypted ) )
#set( $Base64EncodedURLSafe = $Base64Encoded.replace(
$EncodingTool.Base64.ENCODED_CHAR_62.STANDARD,
$EncodingTool.Base64.ENCODED_CHAR_62.URLSAFE
).replace(
$EncodingTool.Base64.ENCODED_CHAR_63.STANDARD,
$EncodingTool.Base64.ENCODED_CHAR_63.URLSAFE
)
)
<a href="${PreferenceCenterBaseURL.toString().trim()}?lead=${Base64EncodedURLSafe}">${PreferenceCenterLinkText.toString().trim()}</a>
<a href="https://xerox.my.preferencecenter.co.uk?lead=uk_H5W_tuqQymuK7Rig-s16sxLYyqdIlOA_4zW-P9q0-8GoiuHK1R-oxaQAcwNnkfM7E_2uNl...">Manage Your Preferences Ultra-Securely</a>
VELOCITEASE #3
(just for Perkutians)
- Velocity can make outbound HTTP connections (shh!)
- Velocity has access to the Campaign Run ID
- Velocity can cache data in memory across leads
- Velocity can parse XML
... what does all that make you think of?
I KINDA DID WRITE THE BOOK ON THIS
VELOCITY VACANCIES
- Doesn't save data permanently, only outputs
- Recomputing same value across leads inefficient
- Only works in emails (just as JS only works on LPs)
- OK, I admit, it's hard as ▓▓▓▓ to master
SET UP A
REST API GATEWAY.
YESTERDAY.
API GATEWAYS CURE THE AUDIT TRAIL BLUES
API GATEWAYS ENFORCE
PER-KEY LIMITS
API GATEWAYS TELL YOU WHAT PARTNERS WON'T
API GATEWAYS LET YOU BALANCE YOUR API CALLS
THE OBJECT APIS
THE LEAD (PERSON) API
- Push Lead: program membership, upsert reason (even when no-op!)... but still incomplete
- Upsert Lead: most common, but no advantages over Push in 2018
- Associate Lead: still necessary with either of the above
Meter all the things!
get (stored REST API access_token)
then
check (seconds until token expires)
if (token expired)
send (REST API client_id, REST API client_secret)
to (Marketo REST Identity endpoint)
and get (new REST API access_token)
then
send (new REST API access_token, request parameters)
to (Marketo REST Get Leads endpoint)
and get (lead info)
else
send (stored REST API access_token, request parameters)
to (Marketo REST Get Leads endpoint)
and get (lead info)
What's wrong with this (pseudo)code?
get (stored REST API access_token)
then
check (seconds until token expires)
if (token expired)
send (REST API client_id, REST API client_secret)
to (Marketo REST Identity endpoint)
and get (new REST API access_token)
then
send (new REST API access_token, request parameters)
to (Marketo REST Get Leads endpoint)
and get (lead info)
else
send (stored REST API access_token, request parameters)
to (Marketo REST Get Leads endpoint)
and get (lead info)
then
if (error) with error code (601:access_token expired)
then
send (REST API client_id, REST API client_secret)
to (Marketo REST Identity endpoint)
and get (new REST API access_token)
then
send (new REST API access_token, request parameters)
to (Marketo REST Get Leads endpoint)
and get (lead info)
THE MARKETO CUSTOM OBJECT API
- 1st-level (directly attached to lead) or 2nd-level (many-to-many) dimensions
- unlike SFDC/NetSuite synced objects, are readable in the Marketo UI...
- ... but also don't sync to CRM!
THE MARKETO CUSTOM OBJECT API: USE CASES
THE MARKETO CUSTOM OBJECT API
- CO records and CO relationships to leads are managed separately
(even for seemingly 1st-level objects - think Oppties & Oppty Roles) - 2nd-level COs don't work in Velocity (contra Marketo docs) so plan schema accordingly
THE MARKETO CUSTOM ACTIVITIES API
Theory:
- programmatically add activities beyond built-in Visit Web Page and Click Link
- show custom activity names and metadata in the Activity Log, like Added to Shopping Cart
- trigger and filter on domain-specific actions (like app actions)
THE MARKETO CUSTOM ACTIVITIES API
Practice:
- completely unworkable if called one-by-one (reliability, DoS vuln)
- only work in queued batches, meaning implementation complexity
- have scale issues even batched
- not really better than synthetic Visit Web Page
THE MARKETO OPPTY/ COMPANY/SALES REP APIS
- For non-CRM environments
- They, um, work?
- Sync with external systems is no small feat, even when seemingly 1-directional
THE BULK(ISH) APIS
This and more in Part II,
coming in 2019!
Marketo MUG 2018-10 (Public)
By Sanford Whiteman, TEKNKL