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

Why does thisButton

not log a Clicked Link

on Web Page activity?

 

Nor does this Button

nor this other Button

yet this Button does!

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

Private

Marketo MUG 2018-10 (Public)