CRM and CX Blogs by SAP
Stay up-to-date on the latest developments and product news about intelligent customer experience and CRM technologies through blog posts from SAP experts.
cancel
Showing results for 
Search instead for 
Did you mean: 
Former Member
399

Blog 3: Alexa – let Alexa talk to Hybris Marketing Cloud


3.1 Webhook Basics


A webhook (also called a web callback or HTTP push API) is a way for an app to provide other applications with real-time information. A webhook delivers data to other applications as it happens, meaning you get data immediately. Unlike typical APIs where you would need to poll for data very frequently to get it real-time. This makes webhooks much more efficient for both provider and consumer. (Sendgrid)

While developing an Alexa skill on Amazon, the developer must provide an API which answers to incoming requests, this Api can be deployed with Amazon Lambda (which is the recommended way for Alexa skills) or can be hosted on another place. The connection to the non-lambda server must succeed via an Https connection.

For tis Blog I’m going to use Heroku for the simple reason that I already used it. Heroku is a cloud platform that lets companies build, deliver, monitor and scale apps — we're the fastest way to go from idea to URL, bypassing all those infrastructure headaches.

For more information about how to deploy an application on Heroku visit the Heroku website:  www.heroku.com

In this blog I’m going to use NodeJS to demonstrate my examples

3.2 Connect & Authenticate -> Web hooks can connect to Hybris Marketing system


HTTP Basic authentication implementation is the simplest technique for enforcing access controls to web resources because it doesn't require cookies, session identifiers, or login pages; rather, HTTP Basic authentication uses standard fields in the HTTP header, obviating the need for handshakes.

This authentication method is not the most recommended, but since we are looking for a rapid solution, our Hybris Marketing Cloud instance allow us to use this method directly. But on a system running in production, it is recommended to use more secured method like SSO (Single Sign On, OAuth)

What we need is a framework which support Routing and a webserver to answer to requests. ExpressJS is Fast, unopinionated, minimalist web framework for Node.js, Express is a minimal and flexible Node.js web application framework that provides a robust set of features for web and mobile applications, with a myriad of HTTP utility methods and middleware at your disposal, creating a robust API is quick and easy. Express provides a thin layer of fundamental web application features, without obscuring Node.js features that you know and love. To make requests, we also need a simple HTTP Client to send requests to the Hybris Marketing Backend. For this purpose, there is a node.js module named “request” very suitable for such use cases.

To setup an ExpressJS project is very simple. First create a directory named webhook, change to it and run npm init. Then install express, request and body-parser (useful to parse request body) as dependencies, as per the installation guide.

Your package.json file should look like this:

 
{

"name": "webhook-nodejs",

"main": "app.js",

"prive": true,

"scripts": {

"start": "node ./app.js"

},

"dependencies": {

"body-parser": "~1.12.0",

"express": "~4.14.0",

"request": "^2.79.0"

}

}

Run npm install, and create an app.js file in the project directory which should contains:

 
var express = require('express')

var app = express()



app.get('/', function (req, res) {

res.send('Hello World!')

})



app.listen(3000, function () {

console.log('Example app listening on port 3000!')

})


This is the minimal setup we need to develop an application with nodejs.

The request module is the Http Client that we will use to contact the backend.
const AUTH = {

'user': USERNAME, // please enter your password here

'pass': PASSWORD,

'sendImmediately': false

};



const BASE_URL = "https://coeportal218.saphosting.de/sap/opu/odata/sap/CUAN_COMMON_SRV";



var urls = {

"IN_PREPARATION": "/TargetGroups?$skip=0&$top=102&$orderby=ChangedOn%20desc&$filter=(Search/TileFilterCategory%20eq%20%272%27)&$select=CreatedByUserId%2cName%2cTargetGroupId%2cCustomerMemberCount%2cCreatedByPersonName%2cLifecycleStatus%2cStaticDynamic%2cVersion%2cCreatedOn%2cMemberType&search=&$inlinecount=allpages"

};



function getData(){

promise = new Promise(function (resolve, reject) {

httpClient({

method: 'GET',

uri: BASE_URL + urls.IN_PREPARATION,

auth: AUTH,

json: true

}, function (error, response, body) {

if (error) {

reject(error);

} else {

resolve(body);

}

});

});



}


 

With this piece of code, we have made a request to a Demo System, and ask for the Target Groups in Preparation.

3.3 Access Hybris Marketing entities -> Alexa can read entities (e.g. campaigns)


Full Example:

Alexa communicates with our service via a request-response mechanism using HTTP over SSL/TLS. When a user interacts with an Alexa skill, your service receives a POST request containing a JSON body. The request body contains the parameters necessary for the service to perform its logic and generate a JSON-formatted response.
{
"version": "string",
"session": {
"new": true,
"sessionId": "string",
"application": {
"applicationId": "string"
},
"attributes": {
"string": {}
},
"user": {
"userId": "string",
"permissions": {
"consentToken": "string"
},
"accessToken": "string"
}
},
"context": {
"System": {
"application": {
"applicationId": "string"
},
"user": {
"userId": "string",
"permissions": {
"consentToken": "string"
},
"accessToken": "string"
},
"device": {
"deviceId": "string",
"supportedInterfaces": {
"AudioPlayer": {}
}
},
"apiEndpoint": "string"
},
"AudioPlayer": {
"token": "string",
"offsetInMilliseconds": 0,
"playerActivity": "string"
}
},
"request": {}
}

 

The request object is an Intent Request and we must use it in our webhook in order to know which intent has been called.
// Intent Request, the intentName has been defined by ourself in the amazon developer web page
{
"type": "IntentRequest",
"requestId": "string",
"timestamp": "string",
"dialogState": "string",
"locale": "string",
"intent": {
"name": "string",
"confirmationStatus": "string"
"slots": {
"string": {
"name": "string",
"value": "string",
"confirmationStatus": "string"
}
}
}
}

This is my full Controller code
var requestHelper = require('./requestHelper');
/**
* List of constants used for requesting our Backend
*/
const IN_PREPARATION = 1,
RELEASED = 2,
COMPLETED = 3,
GREETING = 4,
TO_BE_RELEASED = 5,
MEMBERS = 6;

/**
* JSON result format when the request is comming from API.ai
*/
var JSON_STRING_RESULT = {
"speech": "",
"displayText": "",
"data": {},
"source": "fofie.work.marketting",
"contextOut": []
};

/**
* JSON result format when the request is comming from Amazon Alexa Service
*/
var AMAZON_RESPONSE = {
"version": "2.0",
"response": {
"outputSpeech": {
"type": "SSML",
"text": "",
"ssml": ""
},
"shouldEndSession": false
}
};
var maxNumber = 4;
/**
* Entry Point to our webhook
* Since the webhook is relativly small,
* the code has been pressed into this unique function.
* Instead of been dispatched in many files
*
*/
exports.webhook = function(req, res) {
// check if the request come from amazon or from another source like api.ai
var intentName;
var amazon = false;
/**
* If the request if comming from amazon
* The intend name has to been retrieved
*/
if (typeof req.body.request != "undefined" && typeof req.body.request.type != "undefined" && req.body.request.type == "IntentRequest" && typeof req.body.request.intent != "undefined") {
intentName = ("" + req.body.request.intent.name).toLocaleLowerCase();
// setting amazon to true will be usefull
// to decide which response format to use
amazon = true;
}
/**
* If the intent name has no been set.
* This means that the request is not comming from amazon
* So the intentName has to been retrieved from the api.ai request
*/
if (intentName == null) {
intentName = req.body.result.metadata.intentName;
}

console.log(intentName);
/**
* Static questions
* Simple conversation example.
* Used for the Video Mode 2
* Goal is to respond to simple amazon alexa questions
*
*/
var jsonContent = JSON_STRING_RESULT;
if (intentName == 'when_iphone') {
var speech = "UPS will deliver your new Iphone 7 today between 1 and 2pm. Do you know that there is a special offer for an amazing Iphone cover for your new Iphone 7?";
if (amazon == true) {
jsonContent = AMAZON_RESPONSE;
jsonContent.response.outputSpeech.ssml = "<speak>" + speech + "</speak>";
jsonContent.response.outputSpeech.text = speech;
jsonContent.shouldEndSession = false;
res.jsonp(jsonContent);
}
} else if (intentName == 'what_offer') {
var speech = "You get 10% for the Iphone cover in white in ,and if you use 10 loyalty points, you get additional 10%";
if (amazon == true) {
jsonContent = AMAZON_RESPONSE;
jsonContent.response.outputSpeech.ssml = "<speak>" + speech + "</speak>";
jsonContent.response.outputSpeech.text = speech;
jsonContent.shouldEndSession = false;
res.jsonp(jsonContent);
}
} else if (intentName == 'order_it') {
var speech = "Ok. Done!"
if (amazon == true) {
jsonContent = AMAZON_RESPONSE;
jsonContent.response.outputSpeech.ssml = "<speak>" + speech + "</speak>";
jsonContent.response.outputSpeech.text = speech;
jsonContent.response.shouldEndSession = true;
res.jsonp(jsonContent);
}
/**
* The first intent of ou webhook.
* When the user is asking for general informations,
* Note that the intentNames in APi.ai and Amazon Alexa Intents are the same
*/

} else if (intentName == 'greeting') {
var inPreparation, released, toBeReleased, completed;
/**
* Retreive all primary informations from each category (In inpreparation, to be released. released ...)
* Javascript CallBack Hell
*/
requestHelper.getData(IN_PREPARATION, 20, "", false).then(function(data, error) {
if (error) {
res.jsonp({
"error": error
});
}
inPreparation = data;
requestHelper.getData(RELEASED, 20, "", false).then(function(data, error) {
if (error) {
res.jsonp({
"error": error
});
}
released = data;
requestHelper.getData(TO_BE_RELEASED, 20, "", false).then(function(data, error) {
if (error) {
res.jsonp({
"error": error
});
}
toBeReleased = data;
requestHelper.getData(COMPLETED, 20, "", false).then(function(data, error) {
if (error) {
res.jsonp({
"error": error
});
}
completed = data;
/**
* The text message that will be returned is going to be built here.
*/
var count = Number(inPreparation.d.__count) + Number(released.d.__count) + Number(toBeReleased.d.__count) + Number(completed.d.__count);
var speech = "Hello Fofie There are " + count + " targetgroups on your account , In Prepration :" + Number(inPreparation.d.__count) + "; To be released: " + Number(toBeReleased.d.__count) + "; Released: " + Number(released.d.__count) + " ,Completed: " + (completed.d.__count);
/**
* If the request is comming from Amazon alexa.
*/
if (amazon == true) {
jsonContent = AMAZON_RESPONSE;
/**
* The speech text have to be encapsulated in a seech Tag.
* Otherwise alexa will not read it
*/
jsonContent.response.outputSpeech.ssml = "<speak>" + speech + "</speak>";
jsonContent.response["card"] = {
"type": "Standard",
"title": "Targetgroup Summary",
"text": speech,
"image": {
"smallImageUrl": "https://s3-eu-west-1.amazonaws.com/ymktux/chart.png",
"largeImageUrl": "https://s3-eu-west-1.amazonaws.com/ymktux/chart.png"
} //*/
};
jsonContent.response.outputSpeech.text = speech;
res.jsonp(jsonContent);
} else {
jsonContent = JSON_STRING_RESULT;
jsonContent["speech"] = speech;
jsonContent["displayText"] = jsonContent["speech"];
res.jsonp(jsonContent);
}

});


});
});
});
/**
* The same operations are made in the next steps for the others Use case/
*/
} else if (intentName == "inpreparation") {
requestHelper.getData(IN_PREPARATION, 20, "", false).then(function(data, error) {
if (error) {
res.jsonp({
"error": error
});
}
inPreparation = data;
var count = inPreparation.d.__count;
var speech = "The " + count + " Targetgroups in Preparations are:";

for (var i = 0; i < maxNumber; i++) {
var element = inPreparation.d.results[i];
speech += " -- " + element.Name + " (" + element.CustomerMemberCount + " members)";
}
if (count > maxNumber) {
var rest = Number(count) - maxNumber;
speech += " ..... (" + rest + " others)";
}
if (amazon == true) {
jsonContent = AMAZON_RESPONSE;
jsonContent.response.outputSpeech.ssml = "<speak>" + speech + "</speak>";
jsonContent.response.outputSpeech.text = speech;
res.jsonp(jsonContent);
} else {
jsonContent = JSON_STRING_RESULT;
jsonContent["speech"] = speech;
jsonContent["displayText"] = speech;
res.jsonp(jsonContent);
}


});

} else if (intentName == "released") {
requestHelper.getData(RELEASED, 20, "", false).then(function(data, error) {
if (error) {
res.jsonp({
"error": error
});
}
released = data;
var count = released.d.__count;
var speech = "The " + count + " released Targetgroups are:";

for (var i = 0; i < maxNumber; i++) {
var element = released.d.results[i];
speech += " -- " + element.Name + " (" + element.CustomerMemberCount + " members)";
}
if (count > maxNumber) {
var rest = Number(count) - maxNumber;
speech += " ..... (" + rest + " others)";
}
if (amazon == true) {
jsonContent = AMAZON_RESPONSE;
jsonContent.response.outputSpeech.ssml = "<speak>" + speech + "</speak>";
jsonContent.response.outputSpeech.text = speech;
res.jsonp(jsonContent);
} else {
jsonContent = JSON_STRING_RESULT;
jsonContent["speech"] = speech;
jsonContent["displayText"] = speech;
res.jsonp(jsonContent);
}
});
} else if (intentName == "to_be_released") {
requestHelper.getData(TO_BE_RELEASED, 20, "", false).then(function(data, error) {
if (error) {
res.jsonp({
"error": error
});
}
toBeReleased = data;
var count = toBeReleased.d.__count;
var speech = "The " + count + " Targetgroups to be released are:";
var max = count > maxNumber ? maxNumber : count;
for (var i = 0; i < max; i++) {
var element = toBeReleased.d.results[i];
speech += " -- " + element.Name + " (" + element.CustomerMemberCount + " members)";
}
if (count > maxNumber) {
var rest = Number(count) - maxNumber;
speech += " ..... (" + rest + " others)";
}
if (amazon == true) {
jsonContent = AMAZON_RESPONSE;
jsonContent.response.outputSpeech.ssml = "<speak>" + speech + "</speak>";
jsonContent.response.outputSpeech.text = speech;
res.jsonp(jsonContent);
} else {
jsonContent = JSON_STRING_RESULT;
jsonContent["speech"] = speech;
jsonContent["displayText"] = speech;
res.jsonp(jsonContent);
}
});
} else if (intentName == "completed") {
requestHelper.getData(COMPLETED, 20, "", false).then(function(data, error) {
if (error) {
res.jsonp({
"error": error
});
}
var count = data.d.__count;
var speech = "The " + count + " completed Targetgroups are:";
var max = count > maxNumber ? maxNumber : count;
for (var i = 0; i < max; i++) {
var element = data.d.results[i];
speech += " -- " + element.Name + " (" + element.CustomerMemberCount + " members)";
}
if (count > maxNumber) {
var rest = Number(count) - maxNumber;
speech += " ..... (" + rest + " others)";
}
if (amazon == true) {
jsonContent = AMAZON_RESPONSE;
jsonContent.response.outputSpeech.ssml = "<speak>" + speech + "</speak>";
jsonContent.response.outputSpeech.text = speech;
res.jsonp(jsonContent);
} else {
jsonContent = JSON_STRING_RESULT;
jsonContent["speech"] = speech;
jsonContent["displayText"] = speech;
res.jsonp(jsonContent);
}
});
} else if (intentName == "targetgroup_creator") {
var type = req.body.result.parameters.type;
var number = (req.body.result.parameters.number) - 1;
var mappedType = type == "released" ? RELEASED : (type == "inpreparation") ? IN_PREPARATION : (type == "tobereleased") ? TO_BE_RELEASED : (type == "completed") ? COMPLETED : 0;
requestHelper.getData(mappedType, 20, "", false).then(function(data, error) {
var count = data.d.__count;
var speech;
if (number > count - 1) {
speech = "This target group is unknown";
} else {
var targetGroup = data.d.results[number];
speech = "The targetgroup " + targetGroup.Name + " (" + targetGroup.CustomerMemberCount + " members)" + " has been created by " + targetGroup.CreatedByPersonName;
}
if (amazon == true) {
jsonContent = AMAZON_RESPONSE;
jsonContent.response.outputSpeech.ssml = "<speak>" + speech + "</speak>";
jsonContent.response.outputSpeech.text = speech;
res.jsonp(jsonContent);
} else {
jsonContent = JSON_STRING_RESULT;
jsonContent["speech"] = speech;
jsonContent["displayText"] = speech;
res.jsonp(jsonContent);
}
});

} else if (intentName == "members") {
if (amazon == true) {
var type = req.body.request.intent.slots.targetgroup.value;
var number = Number(req.body.request.intent.slots.numberslot.value) - 1;
} else {
var type = req.body.result.parameters.type;
var number = (req.body.result.parameters.number) - 1;
}

var mappedType = type == "released" ? RELEASED : (type == "inpreparation") ? IN_PREPARATION : (type == "tobereleased") ? TO_BE_RELEASED : (type == "completed") ? COMPLETED : 0;
if (mappedType == 0) {
var speech = "Unknown Type of target Group (released, completed, in prepration, to be released ?)";
if (amazon) {
jsonContent = AMAZON_RESPONSE;
jsonContent.response.outputSpeech.ssml = "<speak>" + speech + "</speak>";
jsonContent.response.outputSpeech.text = speech;
res.jsonp(jsonContent);
} else {
jsonContent = JSON_STRING_RESULT;
jsonContent["speech"] = speech;
jsonContent["displayText"] = speech;
res.jsonp(jsonContent);
}

}
requestHelper.getData(mappedType, 20, "", false).then(function(data, error) {
if (error) {
res.jsonp({
"error": error
});
}
var count = data.d.__count;
var speech;
if (number > count - 1) {
speech = "This target group is unknown";
} else {
var targetGroup = data.d.results[number];
var id = targetGroup.__metadata.id;
requestHelper.getMembers(id).then(function(data, error) {
if (error) {
res.jsonp({
"error": error
});
}
var count = (data.d.__count);
var max = count > maxNumber ? maxNumber : count;
if (count > 0) {
speech = "The members of the Target Group: " + targetGroup.Name + " are:";
for (var i = 0; i < max; i++) {
var element = data.d.results[i];
var city = element.City == undefined ? "" : " from " + element.City;
speech += " - " + element.FullName + city;
}
if (count > maxNumber) {
var rest = Number(count) - maxNumber;
speech += " ..... (" + rest + " others)";
}
} else {
speech = "There are no Members assigned for this TargetGroup";
}
if (amazon == true) {
jsonContent = AMAZON_RESPONSE;
jsonContent.response.outputSpeech.ssml = "<speak>" + speech + "</speak>";
jsonContent.response.outputSpeech.text = speech;
res.jsonp(jsonContent);
} else {
jsonContent = JSON_STRING_RESULT;
jsonContent["speech"] = speech;
jsonContent["displayText"] = speech;
res.jsonp(jsonContent);
}

});
}
});
} else if (intentName == "campaigns") {
var type = req.body.result.parameters.type;
var number = (req.body.result.parameters.number) - 1;
var mappedType = type == "released" ? RELEASED : (type == "inpreparation") ? IN_PREPARATION : (type == "tobereleased") ? TO_BE_RELEASED : (type == "completed") ? COMPLETED : 0;
if (mappedType == 0) {
var speech = "Unknown Type of target Group (released, completed, in prepration, to be released ?)"
jsonContent = JSON_STRING_RESULT;
jsonContent["speech"] = speech;
jsonContent["displayText"] = speech;
res.jsonp(jsonContent);
}
requestHelper.getData(mappedType, 20, "", false).then(function(data, error) {
if (error) {
res.jsonp({
"error": error
});
}
var count = data.d.__count;
var speech;
if (number > count - 1) {
speech = "This target group is unknown";
} else {
var targetGroup = data.d.results[number];
var id = targetGroup.__metadata.id;
requestHelper.getCampaigns(id).then(function(data, error) {
if (error) {
res.jsonp({
"error": error
});
}
var count = (data.d.__count);
if (count > 0) {
for (var i = 0; i < count; i++) {
var element = data.d.results[i];
speech += " - " + element.Campaign;
}
} else {
speech = "There is no Campaign created for this targetGroup"
}

if (amazon == true) {
jsonContent = AMAZON_RESPONSE;
jsonContent.response.outputSpeech.ssml = "<speak>" + speech + "</speak>";
jsonContent.response.outputSpeech.text = speech;
res.jsonp(jsonContent);
} else {
jsonContent = JSON_STRING_RESULT;
jsonContent["speech"] = speech;
jsonContent["displayText"] = speech;
res.jsonp(jsonContent);
}

});
}

});
} else {
var speech = "We cannot understand what you are asking for";
if (amazon == true) {
jsonContent = AMAZON_RESPONSE;
jsonContent.response.outputSpeech.ssml = "<speak>" + speech + "</speak>";
jsonContent.response.outputSpeech.text = speech;
res.jsonp(jsonContent);
} else {
jsonContent = JSON_STRING_RESULT;
jsonContent["speech"] = speech;
jsonContent["displayText"] = speech;
res.jsonp(jsonContent);
}
}
};

The request Helper file
var httpClient = require('request');


const BASE_URL = "https://coeportal218.saphosting.de/sap/opu/odata/sap/CUAN_COMMON_SRV";
const IN_PREPARATION = 1,
RELEASED = 2,
COMPLETED = 3,
GREETING = 4,
TO_BE_RELEASED = 5,
MEMBERS = 6;
HEADER_OPTIONS = {
'auth': {
'user': "", //your username
'pass': "", // Your password
'sendImmediately': false
},
'json': true
};
var JSON_STRING_RESULT = {
"speech": "",
"displayText": "",
"data": {},
"source": "fofie.work.marketting",
"contextOut": []
};
const AUTH = {
'user': USERNAME,
'pass': PASSWORD,
'sendImmediately': false
};

/**
* This array contains the differents URLs
*/
var urls = {
"IN_PREPARATION": "/TargetGroups?$skip=0&$top=102&$orderby=ChangedOn%20desc&$filter=(Search/TileFilterCategory%20eq%20%272%27)&$select=CreatedByUserId%2cName%2cTargetGroupId%2cCustomerMemberCount%2cCreatedByPersonName%2cLifecycleStatus%2cStaticDynamic%2cVersion%2cCreatedOn%2cMemberType&search=&$inlinecount=allpages",
"RELEASED": "/TargetGroups?$skip=0&$top=102&$orderby=ChangedOn%20desc&$filter=(Search/TileFilterCategory%20eq%20%273%27)&$select=CreatedByUserId%2cName%2cTargetGroupId%2cCustomerMemberCount%2cCreatedByPersonName%2cLifecycleStatus%2cStaticDynamic%2cVersion%2cCreatedOn%2cMemberType&search=&$inlinecount=allpages",
"COMPLETED": "/TargetGroups?$skip=0&$top=102&$orderby=ChangedOn%20desc&$filter=(Search/TileFilterCategory%20eq%20%274%27)&$select=CreatedByUserId%2cName%2cTargetGroupId%2cCustomerMemberCount%2cCreatedByPersonName%2cLifecycleStatus%2cStaticDynamic%2cVersion%2cCreatedOn%2cMemberType&search=&$inlinecount=allpages",
"TO_BE_RELEASED": "/TargetGroups?$skip=0&$top=102&$orderby=ChangedOn%20desc&$filter=(Search/TileFilterCategory%20eq%20%275%27)&$select=CreatedByUserId%2cName%2cTargetGroupId%2cCustomerMemberCount%2cCreatedByPersonName%2cLifecycleStatus%2cStaticDynamic%2cVersion%2cCreatedOn%2cMemberType&search=&$inlinecount=allpages",
"MEMBERS": "/TargetGroupMembers?$skip=0&$top=108&$orderby=FullName%20asc&$select=FullName%2cFunction%2cDepartment%2cEMailAddress%2cPhoneNumber%2cMobilePhoneNumber%2cStreet%2cHouseNumber%2cCity%2cCountryDescription%2cRegionDescription%2cFirstLineName%2cMemberKey%2cObjectType%2cCustomerId&$inlinecount=allpages&sap-client=100",
CAMPAIGNS: "/Initiatives?$skip=0&$top=110&$orderby=Name%20asc&$select=Name%2cInitiativeIdExt%2cInitiativeId%2cLifecycleStatus%2cPriority%2cMainResponsiblePersonName%2cStartDate%2cEndDate%2cProcessType%2cOrchJsonTimestamp&$inlinecount=allpages&sap-client=100"

};
exports.getData = function (type, number, client, returnArray) {
var jsonContent = null;
var promise;
switch (Number(type)) {
case IN_PREPARATION:
promise = new Promise(function (resolve, reject) {
httpClient({
method: 'GET',
uri: BASE_URL + urls.IN_PREPARATION,
auth: AUTH,
json: true
}, function (error, response, body) {
if (error) {
reject(error);
} else {
resolve(body);
}
});
});
break;
case RELEASED:
promise = new Promise(function (resolve, reject) {
httpClient({
method: 'GET',
uri: BASE_URL + urls.RELEASED,
auth: AUTH,
json: true
}, function (error, response, body) {
if (error) {
reject(error);
} else {
resolve(body);
}
});
});
break;
case COMPLETED:
promise = new Promise(function (resolve, reject) {
httpClient({
method: 'GET',
uri: BASE_URL + urls.COMPLETED,
auth: AUTH,
json: true
}, function (error, response, body) {
if (error) {
reject(error);
} else {
resolve(body);
}
});
});
break;
case TO_BE_RELEASED:
promise = new Promise(function (resolve, reject) {
httpClient({
method: 'GET',
uri: BASE_URL + urls.TO_BE_RELEASED,
auth: AUTH,
json: true
}, function (error, response, body) {
if (error) {
reject(error);
} else {
resolve(body);
}
});
});
break;
case GREETING:
break;
case MEMBERS:
promise = new Promise(function (resolve, reject) {
httpClient({
method: 'GET',
uri: BASE_URL + urls.MEMBERS,
auth: AUTH,
json: true
}, function (error, response, body) {
if (error) {
reject(error);
} else {
resolve(body);
}
});
});
break;
break;
default:
}
return promise;
};

exports.getCampaigns = function(targetGroupId){
var promise;
promise = new Promise(function (resolve, reject) {
httpClient({
method: 'GET',
uri: targetGroupId + urls.CAMPAIGNS,
auth: AUTH,
json: true
}, function (error, response, body) {
if (error) {
reject(error);
} else {
resolve(body);
}
});
});
return promise;
};

exports.getMembers = function(id) {
return new Promise(function (resolve, reject) {
httpClient({
method: 'GET',
uri: id + urls.MEMBERS,
auth: AUTH,
json: true
}, function (error, response, body) {
if (error) {
reject(error);
} else {
resolve(body);
}
});
});
};

function prepareJsonObject(jsonContent) {
var arrayOfElement = {};
arrayOfElement["count"] = jsonContent.d.results.length;
arrayOfElement["data"] = [];
for (var i = 0; i < jsonContent.d.results.length; i++) {
var element = jsonContent.d.results[i];
var currentElement = [];
currentElement["id"] = element["__metadata"]["id"];
currentElement["changedBy"] = element["ChangedByPersonName"];
currentElement["createdBy"] = element["CreatedByPersonName"];
currentElement["name"] = element["Name"];
currentElement["status"] = element["LifecycleStatus"]["StatusDescription"];
currentElement["createdOn"] = element["CreatedOn"];
currentElement["CreatedByPersonName"] = element["CreatedByPersonName"];
arrayOfElement.data.push(currentElement);
}
return arrayOfElement;
}

/**
* Greeting function, first time when the users write his first message in telegram
*/
exports.greeting = function (res) {

};

function releaseOne() {

}

My webhook.js flie (for routing)
var express = require('express');
var router = express.Router();

var webhookController = require('./webhookController');

router.post('/', webhookController.webhook );

module.exports = router;

And the app.js file
var express = require('express');
var app = express();
var bodyParser = require('body-parser');
var webhook = require('./webhook');

app.use(bodyParser.urlencoded({
extended: true
}));
app.use(bodyParser.json());

var port = process.env.PORT || 3001;

var router = express.Router();

router.get('/', function (req, res) {
res.json({
message: 'hooray! welcome to our api!'
});
});

app.use('/webhook', webhook);
app.use('/feed', feed)

app.listen(port);
console.log('Magic happens on port ' + port);

This was basically the code of our webhook, the code had been deployed on heroku.