Learn how webhooks operate with RingCentral
Start TutorialA Webhook is an HTTP-based callback that contains event notification data.
RingCentral Webhooks are a transport type available for developers to use when creating Push Notifications.
This Webhook Basics tutorial will show you the basics about how to create and consume Push Notifications using the WebHook transport type in Node.js.
Developers working with this tutorial can deploy this app to Heroku or operate it locally behind ngrok, but you must have a valid SSL certificate chain that supports TLSv1.2, but you must have a valid SSL certificate chain that supports TLSv1.2+.
Please make sure you have access to the following required resources on-hand prior to running this source code locally or via deployment to Heroku
See Also:
The first file we'll look at is env.tmpl
. This contains environment variable configuration data for this tutorial to operate locally (and provides guidelines for what you might need if you are deploying an application similar to this on your favorite PaaS.
If running locally or not on Heroku, rename the env.tmpl
file mv env.tmpl .env
. Then, open the file for editing, and fill in these tutorial runtime configuration values:
The env.tmpl
file acts as a template for you and shows you all the environment variables we will use in this tutorial. We use the dotenv module to handle this for us.
We begin by defining the local web server PORT
and we provide an indicator if this application is set to operate with the RingCentral Production API or RingCentral Sandbox API using the RC_ENV
environment variable.
PORT
: number - defaults to 3000RC_ENV
: string - [sandbox, production] - tells the application which API endpoint to use - defaults to sandboxThis application uses dotenv to simplify loading environment variables on your local system. If you want to bypass this, such as if you deploy to Heroku, then set RC_ENV to production
.
Since this application has been configured to be of type Server Only (NO-UI), it indicates this is a background process (aka: service worker or service). Typically we store administrator-level user credentials in these (unless we choose to use a different OAuth2 flow).
RC_APP_NAME
: string - <your_ringcentral_developer_portal_application_name> - reference for developers, not used internally (required on Heroku)RC_APP_KEY
: string - <your_ringcentral_application_key> - Available from within the RingCentral Developer Portal, also known as client_id in OAuth2 nomenclatureRC_APP_SECRET
: string - <your_ringcentral_application_secret> - Available from within the RingCentral Developer Portal, also known as client_secret in OAuth2 nomenclatureRC_USERNAME
: string - <your_ringcentral_username> - Either phone number or email (depending upon your account settings) and must be an administrative user-level account for either sandbox or production respectivelyRC_PASSWORD
: string - <your_ringcentral_password> - The associated password for the RC_USERNAME
provided above. Must be an administrative user-level account for either sandbox or production respectivelyRC_EXTENSION
: string - <your_ringcentral_extension> - The extension number as a string, optionalRC_CACHE_PREFIX
: string - Randomized string for the RingCentral JavaScript SDK, only required if you modify the source otherwise leave emptyEXTENSIONS_PER_PAGE
: number - Quantity of extensions to fetch per page - defaults to 500Now that we have all preparation work completed, let's take a look at the first file that contains the actual content of the tutorial, /index.js
.
This demo application uses Official RingCentral JavaScript SDK, Node's http module, and Node's url module as dependencies. If running locally, make sure you execute npm install
after cloning to install these dependencies.
We will use Node.js HTTP module to create a new web server. We will need to this later to setup our WebHook event handler, more on that later...
First we will instantiate the RingCentral JavaScript SDK, and then we cache the RingCentral Platform object for later reference, and create a placeholder for our subscription.
Next we use the RingCentral Platform object's login()
method to authentiate using OAuth2 Password Flow to obtain a valid access_token
. In multi-tenant, or SaaS applications you would want to use Authorization Flow (aka: 3-Legged OAuth).
If we are successful in authenticating, the application code's init method is called to start the app.
Instead of calling the init method directly in the Promise as shown in the previous step, we also could have leveraged the RingCentral Platform Events and inserted the init method call inside the handleLoginSuccess
method.
As you can see there are several different Platform Events which are available for your application to ensure a smooth user experience.
During the initialization of this demo app, all extensions within your RingCentral Sandbox account are retrieved recursively.
Since the RingCentral Platform Object returns a Promise, it makes authoring this recursive request pretty simple.
RingCentral JS SDK Server-Side Subscriptions require the subscription
application variable placeholder we created earlier to be provided with an array of EventFilters.
The createEventFilter
function requires a parameter be provided which is the full list of our account extensions.
First we setup a private variable _eventFilters
which type array (the data type required by the JS SDK for this property's value when we will later register the subscription
).
Then we iterate over each extension in the list, cache the extension for reference while building the eventFilters
array elements.
Lastly we leverage our environment variables to generate the string for each Event Type respectively and append it to the _eventFilters
variable.
Finally, once all the eventFilters have been added, we return the _eventFilters
back to the Promise chain, which passes the array of eventFilters as an argument to the startSubscription
function.
It is a best practice to provide Multiple event filters in a single Subscription. You can see in this code that we leverage our environment variables to include
It is recommended that developers using the JS SDK read the full Subscriptions lifecycle.
See Also
The startSubscription function expects the eventFilters
as it's only parameter. When we call this function, what happens...?
We use the RingCentral SDK to POST our eventFilters
and to define the delivery mode.
deliveryMode
contains the two important properties which differentiate a WebHook from Subscription. We simplify any changes by referencing the enviroonment variables for deliveryMode
and address
respectively. The two acceptable values currently for deliveryMode
are: WebHook and PubNub.
address
property is the URI where we expect the registration events, notification events, and authentication events for this webhook to be sent on our web server. A valid SSL certificate chain which supports TLSv1.2+ is required on any address
value which is not localhost
or the loopback IP address 127.0.0.1
. One of the reasons I use Heroku is because it simplifies managing the certificates for service workers and PoC work.
Once we have the POST body populated per the Push Notification API documentation to Create a Subscription (using the WebHook deliveryMode), the SDK sends this data and when the promise is resolved we log the Create Subscription response and then we set the subscription
placeholder variable we created earlier to this newly created subscription.
Once we know the WebHook is up-and-running, we use the Node.js HTTP module's createServer() method to create our new web server and tell it to listen on the PORT
value defined in the environment variables.
Then we register event listeners on the http.server and register handlers for: listening
, close
, error
. These three events just log event data to the console, but in production you would have a much more robust set of these event handlers.
The last event handler we register is request
, and we map the request listener to the inboundRequest
function (Node's web server expects requests to provide at least two parameters: request and response. Let's look at the logic we will use to handle incoming requests for WebHooks.
When inbound requests are received by our web server, the inboundRequest
request handler first caches some variables:
Validation-Token
header which must be in the headers of the server response that must be delivered back to RingCentral within 1000ms.When a new request comes in, the first thing we do is make sure the request's action is POST, and that the reqUrl
matches path we set for deliveryMode.address
on the WebHook. In this case, it is '/webhooks'.
Why do we do this? Because if requests do not match our expected parameters we should not trust that it is from RingCentral. If we enter this conditional, we want to reject the response with an HTTP 403 and we end the server response.
When we first create a new Push Notification (PubNub
|WebHook), RingCentral will send an HTTP POST request to our Push Notification's
deliveryMode.address`.
The request must have a Validation-Token
header with a specific value. To be a valid WebHook event consumer (and for RingCentral to begin sending WebHooks) your web server must:
Validation-Token
header and set it equal to the validation-token
we received in the inbound request.Note: If this fails, you will not be able to start your Webhook.
Lastly, we add an event listener for the data
event on the request, and register a callback handler to chunk the request data in the request's body.
Once we have no more data, we convert the chunked body into a string, set the server response HTTP status code to 200 and end the request and include the data (we also log the data in the console to simplify testing).
You can look inside the scripts
section of the package.json
for this repository to see you can use NPM to start the app. In your terminal, use:
npm start
If you see a log message that reads, "SUBSCRIPTION CREATED SUCCESSFULLY" then you have an operating WebHook.
Open your SoftPhone (making sure it is in the correct mode, either: production or sandbox), and then change your Availability once you've authenticated in the desktop softphone. You should receive a new WebHook when this happens.
For each action the Notification Event Types (that map to the eventFilters
of the Subscription), we take using our RingCentral account, we should begin receiving WebHooks that contain valuable near, real-time, actionable data!