Thumbnail
Chat Messaging Dashboard | Integration for shopify + zendesk

This document explains the process of integrating shopify + zendesk with tyntec’s Chat Messaging Dashboard. Enabling the Chat Messaging Dashboard to show customer data from shopify and zendesk, right where your conversations happen. 

logo_shopify_zendesk_ct2x

Results

After finishing this tutorial you will be able to view customer related data in your Chat Messaging Dashboard under Contact Notes.

Shopify 

  • Display shopify related information such as order number, order amount, etc.

Zendesk

  • Display zendesk information such as ticket id, status, linked order id, etc.

Instructions

Create a node application

 

 

First create a node project and install necessary dependencies by following the below commands.

  • Create a project folder
  • Open the terminal and inside the project folder run the following.
    npm init
    npm install express cors body-parser mongoose request
  • Create file with name app.js inside the project directory and paste the below code.

 

'use strict';
const Express = require("express");
const Port = process.env.PORT || 3000;
const BodyParser = require("body-parser");
const Mongoose = require("mongoose");
const App = Express();
const cors = require('cors');
 
// Connect to Mongoose database 
Mongoose.connect('YOUR MONGODB CONNECTION URL', {useNewUrlParser : true, useFindAndModify: false, useUnifiedTopology: true})
.then((success)=>{
   console.log('Db connected successfully')
   //Starts the server
   App.listen(process.env.PORT || 3000, (req, res) => {
       console.log(`server running on port ${Port}`);
   });
})
.catch(e=>{
   console.log('Problem while connecting to DB')
})
 
 
// Middlewares
App.use(cors());
App.use(BodyParser.urlencoded ({
   extended: false
}));
App.use(BodyParser.json());
 
// Use Api routes in the App
require('./routes')(App)
 
module.exports = {
   App
}

Now run the project by using the command node app.js in the terminal.

Setting up database models

Let's create the database schemas for our project for both shopify and zendesk.

Create a folder with name models in your project directory and inside it create three files named shopifyOrders.js, shopifyCustomers.js and zendesk.js and paste the code shown below.

Prerequisites

  • Zendesk support plugin should be installed on your shopify website.
  • Under shopify customer details, there should be a WhatsApp phone number for the integration to work properly. 
  • Basic knowledge of Node.js project with MongoDB.

shopifyOrders.js

const mongoose = require('mongoose')
const Orders = new mongoose.Schema({
   customer_id: {
       type: String
   },
   order_id: {
       type: String,
       required: true,
       required:true
   },
   order_number: {
       type: Number
   },
   phone: {
       type: String
   },
   email: {
       type: String
   },
   total_price: {
       type: String
   },
   billing_address: {
       type: Object
   },
   status: {
       type: String
   }
 
})
 
module.exports = mongoose.model('orders', Orders)

shopifyCustomers.js

const mongoose = require('mongoose')
const ShopifyCustomers = new mongoose.Schema({
   customer_id: {
       type: String,
       required: true,
       unique: true
   },
   email: {
       type: String,
   },
   first_name: {
       type: String
   },
   last_name: {
       type: String
   },
   phone: {
       type: String
   },
   tags: {
       type:String
   },
   address: {
       type: Array
   }
 
})
 
module.exports = mongoose.model('customers', ShopifyCustomers)

zendesk.js

const Mongoose = require('mongoose')
const TicketSchema = Mongoose.Schema({
   ticket_id: {
       type: Number,
       unique: true
   },
   ticket_url: {
       type: String
   },
   order_number: {
       type: String
   },
   status: {
       type: String
   },
   phone: {
       type:String
   },
   email: {
       type:String
   },
   tags: {
       type: Array
   }
 
})
 
module.exports = Mongoose.model('tickets', TicketSchema)

Webhook endpoint

Creating routes for webhooks

Create a folder called routes in your project directory and create three files as shown below.

shopify.js

const Router = require("express").Router();
const ShopifyCtrl = require('../controllers/shopify')
 
//ORDER ROUTES
Router.route('/createOrder')
   .post(async function (req,res) {
       try{
               console.log('---------create order')
 
               let obj = {
                   "customer_id": req.body.customer.id,
                   "order_id": req.body.id,
                   "order_number": req.body.order_number,
                   "phone": req.body.phone,
                   "email": req.body.email,
                   "total_price": req.body.total_price,
                   "billing_address": req.body.billing_address,
                   "status": req.body.status
               }
               let data =     await ShopifyCtrl.createOrder(obj)
               customerData = await ShopifyCtrl.getCustomerByID(req.body.customer.id)
               // console.log(customerData)
               if(data.phone && customerData && !customerData.phone){
                   console.log('inside condition')
                   let UpdateStatus = await ShopifyCtrl.updateCustomer(data.customer_id, {'phone': data.phone})
                   if(UpdateStatus){
                       console.log('phone updated')
                   }
               }
               if(data.email && customerData && !customerData.email){
                   let UpdateStatus = await ShopifyCtrl.updateCustomer(data.customer_id, {'email': data.email})
                   if(UpdateStatus){
                       console.log('email updated')
                   }
               }
               res.status(200).send(data)
       }
       catch(e){
           console.log(e)
       }
   })
 
Router.route('/updateOrder')
   .post(async function (req,res) {
      try{
           console.log('route called once')
           let obj = {
               "order_number": req.body.order_number,
               "phone": req.body.phone,
               "email": req.body.email,
               "total_price": req.body.total_price,
               "billing_address": req.body.billing_address,
               "status": req.body.status
           }
           let data =     await ShopifyCtrl.updateOrder(req.body.id, obj)
           res.status(200).send(data)
      }
      catch(e){
          console.log(e)
      }
   })
 
 
 
//CUSTOMER ROUTES
Router.route('/createCustomer')
   .post(async function (req,res) {
      try{
           console.log('create customer', req.body)
           let obj = {
               "customer_id": req.body.id,
               "email": req.body.email,
               "first_name": req.body.first_name,
               "last_name":req.body.last_name,
               "phone":req.body.phone,
               "tags":req.body.tags,
               "address":req.body.addresses,
           }
           let data =     await ShopifyCtrl.createCustomer(obj)
           res.status(200).send(data)
      }
      catch(e){
          console.log(e)
      }
   })
 
Router.route('/updateCustomer')
   .post(async function (req,res) {
       console.log('route called once', req.body)
      try{
           let obj = {
               "email": req.body.email,
               "first_name": req.body.first_name,
               "last_name":req.body.last_name,
               "phone":req.body.phone,
               "tags":req.body.tags,
               "address":req.body.addresses,
           }
           let data = await ShopifyCtrl.updateCustomer(req.body.id, obj)
           res.status(200).send(data)
      }
      catch(e){
          console.log(e)
      }
   })
module.exports = Router

zendesk.js

const Router = require("express").Router();
const Axios = require('axios')
const ZendeskCtrl= require('../controllers/zendesk')
 
//TICKET ROUTES
Router.route('/createTicket')
   .post(async function (req, res) {
       let obj = {
           'ticket_id': req.body.id,
           'ticket_url': req.body.url,
           'status': req.body.status,
           'order_number': req.body.order_number,
           'phone': req.body.phone,
           'email': req.body.email
       }
       let result = await ZendeskCtrl.createTicket(obj)
       console.log(req.body)
       res.status(200).send(result)
   });
 
Router.route('/updateStatus')
   .post(async function (req,res){
       let result = await ZendeskCtrl.updateTicketStatus(req.body.id, req.body.status)
   })
 
   module.exports = Router

Index.js

'use strict';
 
const Shopify = require('./shopify')
const Zeendesk = require('./zendesk')
module.exports = (app) => { 
   app.use('/shopify', Shopify)
   app.use('/zendesk', Zeendesk)
};

Create the controllers for the API’s

Create a folder called controllers and create the following files.

controllers/shopify.js

'use strict';
 
const ShopifyOrders = require('../models/shopifyOrders')
const ShopifyCustomers = require('../models/shopifyCustomers')
const Api = require('../api/api')
const axios = require('axios')
 
//configuration from your shopify store 
const apiKey = PRIVATE APP API KEY
const password = PRIVATE APP PASSWORD
const storeAddress = "yourstore.myshopify.com"
 
async function createCustomer(data){
   try{
       let newCustomer = new ShopifyCustomers(data)
       let res = await newCustomer.save()
       return res;
   }
   catch(e){
       console.log(e)
   }
}
 
async function getCustomerByID(id){
   try{
      let res = await ShopifyCustomers.findOne({'customer_id': id})
      console.log(res)
       return res;
   }
   catch(e){
       console.log(e)
   }
}
 
//order related api's
async function createOrder(data){
   try{
       let newOrder = new ShopifyOrders(data)
       let res = await newOrder.save()
       if(!res.phone){
          let result = await ShopifyCustomers.findOne({'customer_id':res.customer_id})
          res.phone = result.phone
       }
       res?Api.whatsAppNoteApiShopify(res):""
       return res;
   }
   catch(e){
       console.log(e)
   }
}
 
async function updateOrder(id, newData){
   try{
       let res = await ShopifyCustomers.findOneAndUpdate({'order_id': id}, { '$set': newData}, {new: true})
       console.log(res)
       return res;
   }
   catch(e){
       console.log(e)
   }
}
 
module.exports = {
   createCustomer,
   createOrder,
   updateOrder,
   getCustomerByID
}

controller/Zendesk.js

'use strict';
const Zendesk = require('../models/zendesk')
const axios = require('axios')
const Api = require('../api/api')
 
async function createTicket(data){
   try{
       let newTicket = new Zendesk(data)
       let res = await newTicket.save()
       res?Api.whatsAppNoteApiZendesk(res):""
       return res;
   }
   catch(e){
       console.log(e)
   }
}
 
async function updateTicket(id, newData){
   try{
       let res = await Zendesk.findOneAndUpdate({'ticket_id': id}, { '$set': newData}, {new: true})
       console.log(res)
       return res;
   }
   catch(e){
       console.log(e, "")
   }
}
 
async function updateTicketStatus(id, status){
 try{
   let res = await Zendesk.findByIdAndUpdate({'ticket_id': id}, {'$set': {'status': status}})
   return res;
 }
 catch(e){
     console.log(e, "on controllers/zendesk.js on line 73")
 }
}
 
module.exports = {
   createTicket,
   updateTicket,
   updateTicketStatus
}

Now we have created all the APIs and routes in our application. Now let’s configure the APIs that we created on shopify and zendesk platforms.

Configuring webhooks

Configure Shopify webhooks

Navigate in your shopify store to 'Apps' and open 'Private Apps' to create a new private app.

Fill all the details like app name, developer email and check the storefront api checkbox and click save.

Now if you go back to the private apps section you can see your app. 

Click on your app name and to view the app details.

Note the API key and your Password, which should be configured in the shopify controllers.

Create a new webhook on Shopify

Navigate to 'Settings' and open the 'Notifications' section. And you will see the webhooks as shown below.

Click on 'Create webhook' to enter the details. Select an event from the 'Event' dropdown and enter your webhook URL. Then save your new webhook.

You can test your new webhook via the 'Send test notification' link. If everything works, then your new webhook is ready. 

Configure Zendesk webhooks

Open your zendesk dashboard and navigate to the business rules section go to triggers and click on add trigger and fill out the form as shown below.

In the 'Conditions' section, click on 'Add condition' and select ticket from the dropdown, as shown below.

Now we have to add an 'Action' which will be triggered when the condition mentioned above is met.

Click on 'Add action' and configure the action as shown in the screenshot and save it.
Here we are describing the fields that need to be sent to the webhook.

Now navigate to the 'Settings' section, select 'Extensions' and 'Add extension'. Select from the dropdown 'http target'. It should look like shown below. Fill in the rest of your details and save it.

Trigger tyntec's API

After your setup, you are now able to trigger tyntec's API for the creation on order and ticket. Create one folder named 'api' in your project folder and create a file named api.js. Paste there code as shown below.

api.js

const Request = require('request')
const fs = require('fs');
const path = require('path')
 
exports.whatsAppNoteApiZendesk = (data) => {
   console.log(data, "inside whatsapp status")
   return new Promise((resolve, reject) => {
       console.log("sendThreadMessage")
       var url = "https://api.eazy.im/2.0/contact/note"
       var options = {
           url: url,
           headers: {
               'content-type': 'application/json',
               'Authorization': 'Bearer YOUR TOKEN'
           },
           json: true,
           body: {
               "jid": data.phone.replace("+","")+"@whatsapp.eazy.im",
               "notes": [
                   {
                       "body": "<strong>ZENDESK</strong><br>Ticket_id: <a href='"+data.ticket_url+"'>"+data.ticket_id+"</a>&nbsp;&nbsp; Status: "+data.status+""
                   }
               ]
           }
 
       };
 
       function callback(error, response, body) {
           if (!error && response.statusCode == 200) {
               if (response) {
                   console.log(response.statusCode)
                   resolve(body)
               } else {
                   reject(error)
               }
           } else {
               reject(error)
           }
 
       }
       Request.post(options, callback);
   })
}
 
exports.whatsAppNoteApiShopify= (data) => {
   console.log(data, "inside whatsapp status shopify")
   return new Promise((resolve, reject) => {
       console.log("sendThreadMessage")
       var url = "https://api.eazy.im/2.0/contact/note"
       var options = {
           url: url,
           headers: {
               'content-type': 'application/json',
               'Authorization': 'Bearer QjmOrO6ZdNEDDcpd1fpFczrNPbYT8574qZPwrPdZ'
           },
           json: true,
           body: {
               "jid": data.phone.replace("+","")+"@whatsapp.eazy.im",
               "notes": [
                   {
                       "body": "<strong>SHOPIFY</strong><br>Order_id: <a href='https://botstay.myshopify.com/admin/orders/"+data.order_id+"'>"+data.order_number+"</a>&nbsp;&nbsp; Status: Order Placed"
                   }
               ]
           }
 
       };
 
       function callback(error, response, body) {
           if (!error && response.statusCode == 200) {
               if (response) {
                   console.log(response.statusCode)
                   resolve(body)
               } else {
                   reject(error)
               }
           } else {
               reject(error)
           }
 
       }
       Request.post(options, callback);
   })
}

Congratulations. You're all set. You can now create an order ticket or support ticket. It will show up directly in your Chat Messaging Dashboard like shown below.