Generate Leads with Calendly, Firebase and Zoho: A Story of Webhooks

clock icon Apr 24, 2019


I came across webhooks for the first time about a year ago, even though I haven’t had to use them until about a week ago. I’m mostly writing this because I had an awful experience getting these three technologies to work (Calendly, Firebase, and Zoho), especially with Zoho. If you work at Zoho and you are reading this, no offence but you guys need to work on your documentation. It’s a pain to go through. Before I get into the technologies, what is a webhook?


What is a Webhook?

The initial misconception I had with Webhooks was mixing them up with API. I thought they were the same thing, just different terms, but as it turns out they are not. There’s an article on Hackernoon that goes into the difference between the two terms so I won’t go into it. Basically, you can think of a webhook as “an automated that is made to a server when an event takes place on a website.” What does this mean in practice? Let’s say your company wants visitors to be able to book meetings through the website. Once a visitor sets up a meeting, the details should be forwarded to the sales/marketing department so they can follow up the leads.


There are two ways to go about this: you can hire developers to build and manage a system that does this, which would be costly, or you can take advantage of Calendly’s Meeting API and Zoho’s CRM (Customer Relationship Management). In case you are interested in doing the latter, here’s one way you can go about it.


Prerequisites

You have to sign up on Calendly, Firebase, and Zoho. You also need to have Node.js installed, which would be used to install the Firebase Command Line Interface. Firebase uses your Google account so if you already have a Google account, then you don’t have to create an account. Once you signed up, you can continue with the rest of the article. The source code is on Github so you can have a look and follow along.


Embedding Calendly on your Website

Once you sign up on Calendly, you get a prompt to create a meeting. You can just follow the steps to set up a meeting. To embed it on your website, click the top right dropdown and select Share Your Link. You will get your embed code which you can place anywhere on your website.


Firebase

When you subscribe to Calendly’s webhooks, data from the form is sent to all the endpoints that are subscribed to the webhook. You can create your own endpoint but I’m using Firebase cloud functions here. Create a project on firebase with the steps below:

  1. Open the Firebase console
  2. Click Create New Project

  1. Create a project window opens. Enter the required information and click Create Project
  2. That’s it


Next, open up a terminal. Run the following to install Firebase Command Line Interface and set it up:

npm i -g firebase-tools
firebase login
firebase init

Follow the onscreen prompts and select the project you just created above. We only need cloud functions so select that on the command line and ignore the other services. It would prompt you to install dependencies for cloud functions. Go ahead and install them.


Zoho CRM

One of Zoho’s services is an online Customer Relationship Management (CRM) system for managing your sales, marketing & support in one platform. You can add potential leads to the CRM and follow up later.


Go to Zoho account developer console and get a client id and client secret. Follow this guide to see the process. Copy the client id and client secret and store somewhere. You’ll need it later. Next, click the overflow menu that appears beside your client details and generate a self client. Enter Aaaserver.profile.Read,ZohoCRM.modules.ALL in the scope. I’m selecting all the modules available in the CRM but you can select the individual modules you need. Select an expiry time and click View code. The code that is generated is the grant token. Copy and paste it somewhere.


Generate Access token and Refresh token with Postman

Once you have the grant token, you can use it to generate access and refresh token with Postman. From my understanding, the access token gives apps authorization to interact (post or get leads) with the CRM. The access token expires after a certain period of time hence the refresh token.


To generate the access and refresh tokens, send a POST request to https://accounts.zoho.com/oauth/v2/token like so:



If everything was successful, you should have your access and refresh tokens in the response. Copy and paste them somewhere, we’ll be using them in a bit.


Firebase Cloud Functions

So far we have focused on the setup. Let’s write some code to put everything together. The first thing we need to do is set up some environmental variables in firebase. Open the firebase project create earlier and run the following:

firebase functions:config:set zoho.client_id=YOUR_CLIENT_ID zoho.client_secret=YOUR_CLIENT_SECRET zoho.refresh_token=YOUR_REFRESH_TOKEN

Install axios. Make sure you are inside the functions directory (cd functions) before you run the install command.

npm install --save axios

Delete everything in the functions/index.js file and add the following

// index.js
const functions = require('firebase-functions');
const axios = require('axios');
const clientId = functions.config().zoho.client_id;
const clientSecret = functions.config().zoho.client_secret;
const refreshToken = functions.config().zoho.refresh_token;
const baseURL = 'https://accounts.zoho.com';

There’s nothing mainstream going on here, just importing a few modules and reading the environmental variables we set earlier.

exports.zohoCrmHook = functions.https.onRequest(async (req, res) => {

  const newLead = {
    'data': [
      {
        'Email': payload.invitee.email,
        'Last_Name': payload.invitee.last_name,
        'First_Name': payload.invitee.first_name
      }
    ],
    'trigger': [
      'approval',
      'workflow',
      'blueprint'
    ]
  };
 
  const { data } = await getAccessToken();
  const accessToken = data.access_token;

  const leads = await getLeads(accessToken);
  const result = checkLeads(leads.data.data, newLead.data[0].Email);

  if (result.length < 1) {
    try {
      return res.json(await createLead(accessToken, newLead));
    }
    catch (e) {
      console.log(e);
    }
  }
  else res.json({ message: 'Lead already in CRM' })
}

Calendly passes the details that are filled in the meeting to the cloud function as a payload object. We create a new lead object with the format specified in the zoho docs. Next, we call a helper method getAccessToken, which as the name suggests, gets the access token to be used for any subsequent request. Then we fetch the leads (getLeads) that are already in the CRM. We pass the data to checkLeads which compares the email address of our new lead to the leads in the CRM. Since email addresses are unique, we only send a new lead to the CRM if we don’t find a match. The last thing is an if-else statement that determines if to send the new lead based on the result.

function getAccessToken () {
  const url = `https://accounts.zoho.com/oauth/v2/token?refresh_token=${refreshToken}&client_id=${clientId}&client_secret=${clientSecret}&grant_type=refresh_token`;

  return new Promise((resolve, reject) => {
    axios.post(url)
      .then((response) => {
        return resolve(response);
      })
      .catch(e => console.log(e))
  });
}

The getAccessToken sends a request to the https://accounts.zoho.com/oauth/v2/token with the refresh token, client id, and client secret as parameters. It returns a promise that is resolved with the response of the request. The other helper functions have a similar signature, the noticeable difference being that the access token is added to the headers.

function getLeads(token) {
  const url = 'https://www.zohoapis.com/crm/v2/Leads';

  return new Promise((resolve, reject) => {
    axios.get(url, {
      headers: {
        'Authorization': `Zoho-oauthtoken ${token}`
      }
    })
      .then((response) => {
        return resolve(response);
      })
      .catch(e => console.log(e))
  })
}

function createLead(token, lead) {
  const url = 'https://www.zohoapis.com/crm/v2/Leads';

  return new Promise((resolve, reject) => {
    const data = JSON.stringify(lead);
    axios.post(url, data, {
      headers: {
        'Authorization': `Zoho-oauthtoken ${token}`
      }
    })
      .then((response) => {
        console.log(response.data)
        return resolve(response);
      })
      .catch(e => reject(e))
  })
}

function checkLeads(leads, currentLead) {
  return leads.filter(lead => lead.Email === currentLead)
}

Once you are done, deploy the cloud function to Firebase.

firebase deploy --only functions

If it deploys successfully, you would get a URL for the cloud function. Take note of it because it’s the final piece to the puzzle.


Register Cloud Function on Calendly

I mentioned that webhooks make a call to a server when an event takes place on a website. Calendly webhooks notify your server, or in this case, the cloud function when an event takes place. You need to create a webhook subscription with Calendly to receive events. You can follow this guide to register the webhook subscription and replace the URL param with your cloud function URL.


Now any time someone sets an appointment with Calendly on your website, that data is fed to your cloud function which in turn sends the data to your CRM. This way anyone on your team can easily log in to Zoho CRM, see the potential leads and follow up accordingly.


If you’ve enjoyed this, as always share in your circles. The full source code is on Github. Leave a star if you found it useful. It’s the only way I know it’s helpful :)