Example REST Activity

config.json 

1{
2  "workflowApiVersion": "1.1",
3  "metaData": {
4    "icon": "images/sms.png",
5    "category": "message"
6  },
7  "type": "REST",
8  "lang": {
9    "en-US": {
10      "name": "REST Activity (Workflow API v1.1)",
11      "description": "An example REST activity using workflow API v1.1 format."
12    }
13  },
14  "arguments": {
15    "execute": {
16      "inArguments": [
17        {
18          "emailAddress": "{{InteractionDefaults.Email}}"
19        },
20        {
21          "phoneNumber": "{{Contact.Default.PhoneNumber}}"
22        }
23      ],
24      "outArguments": [
25        {
26          "foundSignupDate": ""
27        }
28      ],
29      "url": "https://some-endpoint.com/execute"
30    }
31  },
32  "configurationArguments": {
33    "save": {
34      "url": "URI/for/your/activity/save"
35    },
36    "publish": {
37      "url": "URI/for/your/activity/publish"
38    },
39    "validate": {
40      "url": "URI/for/your/activity/validate"
41    },
42    "stop": {
43      "url": "URI/for/your/activity/stop"
44    }
45  },
46  "wizardSteps": [
47    { "label": "Step 1", "key": "step1" },
48    { "label": "Step 2", "key": "step2" },
49    { "label": "Step 3", "key": "step3" },
50    { "label": "Step 4", "key": "step4", "active": false }
51  ],
52  "userInterfaces": {
53    "configModal": {
54      "height": 200,
55      "width": 300,
56      "fullscreen": true
57    }
58  },
59  "schema": {
60    "arguments": {
61      "execute": {
62        "inArguments": [
63          {
64            "phoneNumber": {
65              "dataType": "Phone",
66              "isNullable": false,
67              "direction": "in"
68            }
69          },
70          {
71            "emailAddress": {
72              "dataType": "Email",
73              "isNullable": false,
74              "direction": "in"
75            }
76          }
77        ],
78        "outArguments": [
79          {
80            "foundSignupDate": {
81              "dataType": "Date",
82              "direction": "out",
83              "access": "visible"
84            }
85          }
86        ]
87      }
88    }
89  }
90}

index.html 

Every custom activity must have an index.html in the root of its endpoint.

1<!DOCTYPE html>
2
3<html lang="en">
4  <head>
5    <meta charset="utf-8" />
6    <title>Custom Journey Builder Activity</title>
7
8    <script type="text/javascript" src="js/jquery.min.js"></script>
9    <script type="text/javascript" src="js/require.js"></script>
10    <script type="text/javascript">
11      (function () {
12        var config = {
13          baseUrl: "",
14        };
15
16        var dependencies = ["customActivity"];
17
18        require(config, dependencies);
19      })();
20    </script>
21
22    <!--Styles-->
23    <style type="text/css">
24      body {
25        padding: 20px;
26        margin: 0;
27      }
28      .step {
29        display: none;
30      }
31      #step1 {
32        display: block;
33      }
34    </style>
35  </head>
36  <body>
37    <div id="step1" class="step">
38      Select your SMS message:
39      <select id="select1">
40        <option value="">Select an option</option>
41        <option value="someMessage">Some SMS</option>
42        <option value="anotherMessage">Another SMS</option>
43        <option value="thirdMessage">Third SMS</option>
44        <option value="unknownMessage">Unknown SMS</option>
45      </select>
46
47      <button id="toggleLastStep">Toggle Last Step</button>
48    </div>
49    <div id="step2" class="step">
50      Here's a second page with some info on it.
51    </div>
52    <div id="step3" class="step">
53      You chose the message:
54      <div id="message"></div>
55    </div>
56    <div id="step4" class="step">
57      Hey, here's a fourth step, just for you. Toggle this on or off from step
58      1.
59    </div>
60  </body>
61</html>

customActivity.js 

Postmonger is required for communication between Journey Builder and the activity.

1define(["postmonger"], function (Postmonger) {
2  "use strict";
3
4  var connection = new Postmonger.Session();
5  var payload = {};
6  var lastStepEnabled = false;
7  var steps = [
8    // initialize to the same value as what's set in config.json for consistency
9    { label: "Step 1", key: "step1" },
10    { label: "Step 2", key: "step2" },
11    { label: "Step 3", key: "step3" },
12    { label: "Step 4", key: "step4", active: false },
13  ];
14  var currentStep = steps[0].key;
15
16  $(window).ready(onRender);
17
18  connection.on("initActivity", initialize);
19  connection.on("requestedTokens", onGetTokens);
20  connection.on("requestedEndpoints", onGetEndpoints);
21
22  connection.on("clickedNext", onClickedNext);
23  connection.on("clickedBack", onClickedBack);
24  connection.on("gotoStep", onGotoStep);
25
26  function onRender() {
27    // JB will respond the first time 'ready' is called with 'initActivity'
28    connection.trigger("ready");
29
30    connection.trigger("requestTokens");
31    connection.trigger("requestEndpoints");
32
33    // Disable the next button if a value isn't selected
34    $("#select1").change(function () {
35      var message = getMessage();
36      connection.trigger("updateButton", {
37        button: "next",
38        enabled: Boolean(message),
39      });
40
41      $("#message").html(message);
42    });
43
44    // Toggle step 4 active/inactive
45    // If inactive, wizard hides it and skips over it during navigation
46    $("#toggleLastStep").click(function () {
47      lastStepEnabled = !lastStepEnabled; // toggle status
48      steps[3].active = !steps[3].active; // toggle active
49
50      connection.trigger("updateSteps", steps);
51    });
52  }
53
54  function initialize(data) {
55    if (data) {
56      payload = data;
57    }
58
59    var message;
60    var hasInArguments = Boolean(
61      payload["arguments"] &&
62        payload["arguments"].execute &&
63        payload["arguments"].execute.inArguments &&
64        payload["arguments"].execute.inArguments.length > 0
65    );
66
67    var inArguments = hasInArguments
68      ? payload["arguments"].execute.inArguments
69      : {};
70
71    $.each(inArguments, function (index, inArgument) {
72      $.each(inArgument, function (key, val) {
73        if (key === "message") {
74          message = val;
75        }
76      });
77    });
78
79    // If there is no message selected, disable the next button
80    if (!message) {
81      showStep(null, 1);
82      connection.trigger("updateButton", { button: "next", enabled: false });
83      // If there is a message, skip to the summary step
84    } else {
85      $("#select1")
86        .find("option[value=" + message + "]")
87        .attr("selected", "selected");
88      $("#message").html(message);
89      showStep(null, 3);
90    }
91  }
92
93  function onGetTokens(tokens) {
94    // Response: tokens = { token: <legacy token>, fuel2token: <fuel api token> }
95    // console.log(tokens);
96  }
97
98  function onGetEndpoints(endpoints) {
99    // Response: endpoints = { restHost: <url> } i.e. "rest.s1.qa1.exacttarget.com"
100    // console.log(endpoints);
101  }
102
103  function onClickedNext() {
104    if (
105      (currentStep.key === "step3" && steps[3].active === false) ||
106      currentStep.key === "step4"
107    ) {
108      save();
109    } else {
110      connection.trigger("nextStep");
111    }
112  }
113
114  function onClickedBack() {
115    connection.trigger("prevStep");
116  }
117
118  function onGotoStep(step) {
119    showStep(step);
120    connection.trigger("ready");
121  }
122
123  function showStep(step, stepIndex) {
124    if (stepIndex && !step) {
125      step = steps[stepIndex - 1];
126    }
127
128    currentStep = step;
129
130    $(".step").hide();
131
132    switch (currentStep.key) {
133      case "step1":
134        $("#step1").show();
135        connection.trigger("updateButton", {
136          button: "next",
137          enabled: Boolean(getMessage()),
138        });
139        connection.trigger("updateButton", {
140          button: "back",
141          visible: false,
142        });
143        break;
144      case "step2":
145        $("#step2").show();
146        connection.trigger("updateButton", {
147          button: "back",
148          visible: true,
149        });
150        connection.trigger("updateButton", {
151          button: "next",
152          text: "next",
153          visible: true,
154        });
155        break;
156      case "step3":
157        $("#step3").show();
158        connection.trigger("updateButton", {
159          button: "back",
160          visible: true,
161        });
162        if (lastStepEnabled) {
163          connection.trigger("updateButton", {
164            button: "next",
165            text: "next",
166            visible: true,
167          });
168        } else {
169          connection.trigger("updateButton", {
170            button: "next",
171            text: "done",
172            visible: true,
173          });
174        }
175        break;
176      case "step4":
177        $("#step4").show();
178        break;
179    }
180  }
181
182  function save() {
183    var name = $("#select1").find("option:selected").html();
184    var value = getMessage();
185
186    // 'payload' is initialized on 'initActivity' above.
187    // Journey Builder sends an initial payload with defaults
188    // set by this activity's config.json file.  Any property
189    // may be overridden as desired.
190    payload.name = name;
191
192    payload["arguments"].execute.inArguments = [{ message: value }];
193
194    payload["metaData"].isConfigured = true;
195
196    connection.trigger("updateActivity", payload);
197  }
198
199  function getMessage() {
200    return $("#select1").find("option:selected").attr("value").trim();
201  }
202});

Sample Request 

Sample POST data sent to https://some-endpoint.com/execute.

1{
2        "inArguments": [
3                {
4                    "emailAddress": "{{InteractionDefaults.Email}}"
5                },
6                {
7                    "phoneNumber": "{{Contact.Default.PhoneNumber}}"
8                }
9            ],
10        "outArguments": [],
11        "activityObjectID": "1234abcd-56ef-78gh-90ij-9876klmn5432",
12        "journeyId": "1234abcd-56ef-78gh-90ij-9876klmn5432",
13        "activityId": "1234abcd-56ef-78gh-90ij-9876klmn5432",
14        "definitionInstanceId": "1234abcd-56ef-78gh-90ij-9876klmn5432",
15        "activityInstanceId": "1234abcd-56ef-78gh-90ij-9876klmn5432",
16        "keyValue": "someContactKeyHere",
17        "mode": 0
18}

Sample Response 

Sample 200 OK response expected from the server.

1{
2        "foundSignupDate": "2016-03-10"
3}

Related Items