Tutorials>Push Notification Subscription Basics

Learn to use RingCentral event data with subscriptions instead of long-polling.

Start Tutorial

What does this thing do?

This is a demo application showing how to use RingCentral Push Notifications using the official RingCentral JavaScript SDK. This application will GET all the Extensions (Enabled + User) in your RingCentral account (based on the environment, but defaults to Sandbox) and will add eventFilters in a single Subscription that will then receive Presence Events for these Extensions. The data from these presence events is then logged in the console of the application for you to review, and if you choose, filter and then execute external REST requests using the embedded HTTP server.

The tutorial's navigation controls are located above this text. Use to move to the next step of the tutorial. Use to move to the previous step of the tutorial (if there is one). Use to see an overview of all the steps in the tutorial.

Developers are able to configure this application to operate with either your RingCentral Sandbox or Production applications in the .env file by setting the RC_ENV value to either sandbox or production.

Developers can also set this application to use any of the RingCentral Subscription Notification Types (defaulby ts to all enabled) in your environment variables. Read the API Reference for Notification Event Types to understand more about these options.

Let's begin by addressing some prerequisites!

Usage Prerequisites

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:

Environment Configuration

The first file we'll look at is .env.tmpl. This contains configuration data for this tutorial to operate either locally, on Heroku, or on your favorite PaaS. This file acts as a template for you and provides developers with all settings.

If running locally or not on Heroku, Developers need to rename this file mv .env.tmpl .env. Open the file for editing, and fill in these tutorial runtime configuration values:

  • PORT: number - defaults to 3000
  • RC_ENV: string - [sandbox, production] - tells the application which API endpoint to use - defaults to sandbox
  • RC_APP_KEY: string - <your_ringcentral_application_key> - Available from within the RingCentral Developer Portal, also known as client_id in OAuth2 nomenclature
  • RC_APP_SECRET: string - <your_ringcentral_application_secret> - Available from within the RingCentral Developer Portal, also known as client_secret in OAuth2 nomenclature
  • RC_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 respectively
  • RC_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 respectively
  • RC_EXTENSION: string - <your_ringcentral_extension> - The extension number as a string, optional
  • RC_CACHE_PREFIX: string - Randomized string for the RingCentral JavaScript SDK, only required if you modify the source otherwise leave empty
  • EXTENSIONS_PER_PAGE: number - Quantity of extensions to fetch per page - defaults to 500
  • SUBSCRIBE_TO_EXTENSION_EVENTS: boolean - Flag to indicate if you want to subscribe to extension events - defaults to true
  • SUBSCRIBE_TO_PRESENCE_EVENTS: boolean - Flag to indicate if you want to subscribe to extension's presence events - defaults to true
  • SUBSCRIBE_TO_MESSAGE_STORE_EVENTS: boolean - Flag to indicate if you want to subscribe to extension's message store events - defaults to true
  • SUBSCRIBE_TO_PRESENCE_LINE_EVENTS: boolean - Flag to indicate if you want to subscribe to extension's presence line events - defaults to true
  • SUBSCRIBE_TO_INSTANT_MESSAGE_EVENTS: boolean - Flag to indicate if you want to subscribe to extension's instant message events - defaults to true

Now, let's take a look at the first file that contains the actual content of the tutorial, tutorial/index.js.

Dependencies and Mode

First we enable JavaScript string mode so the interpreter starts in the appropriate mode respectively.

Next we setup this application's dependencies:

  • RC: The RingCentral JavaScript SDK
  • http: Node.js http module, used to create a web server
  • util: Node.js Util module, used for unfolding JSON event data in the console logs

Once our dependencies are in place, we create the variable rcServer which leverages the environment variables to define our API Base URI.

Then, we create an instance of the RingCentral JavaScript SDK which also leverages our environment variables to set user credentials.

Application Variables

  • server: The web server for this application
  • platform: Cache the RingCentral Platform method to streamline our code later
  • subscription: Creates a subscription, which is just a placeholder for the time being and will be populated later

Get a Token

Now that our application has all the necessary base parts to operate, let's define the login method which is used as a wrapper to the Promise-based RingCentral JS SDK.platform.login method which is used to obtain an access_token we will use in subsequent API requests. This code is built to operate with a private, back-end application which uses Password Flow.

Then we call the login() method to execute that code. If the SDK resolves that request, we initialize the application (more on this a little later in the tutorial).

The SDK caches the token for developers and manages refreshing the token if it is expired during a later request. This sounds great, but what happens if the Promise is rejected due to some error such as a bad request?

Platform Events

The RingCentral Platform provides developers with the following events related to getting, refreshing, and revoking tokens:

  • loginSuccess
  • loginError
  • logoutSuccess
  • logoutError
  • refreshSuccess
  • refreshError

The eventListeners and associated handlers we have defined really do not do much other than log the response or error, in a production environment you will need to address security concerns appropriately.

See Also

Get All User Enabled Extensions

When RingCentral has responded with a valid access_token, the core of the application starts when we call the init() method.

The first thing we do is define a closure for use with recursion to GET Extension List for every extension in your RingCentral account where type === 'User' and status === 'Enabled'. Since the RingCentral JS SDK returns Promises we have thenables.

Handling Async with Thenables

Since the JS SDK returns Promises, we have thenables we can use to wait for the async code to resolve/reject accordingly.

The init() must also return a Promise or throw an error, so we begin our async chain by calling getExtensionsPage() (described in the previous step Get All User Enabled Extensions ).

Then we pass the response data to the createEventFilter.

Create EventFilters

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

Registering the Subscription

Now that all the heavy lifting is completed, we call the startSubscription function and pass it the eventFilters we created in the previous step. The value this function returns first calls the subscription method setEventFilters, and passes eventFilters through as an argument, and finally chains the JS SDK subscription.register() method which sends the eventFilters set on the subscription to the RingCentral API. The eventFilters are evaluated. If the request is in good form, the response we receive will contain your Subscription Info Object.

Please note: If an event filter is duplicated then only one instance of it will be kept for that subscription. Therefore, the client will always get only a single notification per subscription per event if the subscription conforms to the event. Developers do not have to build their server-side subscription code as has been proposed here, you can also use the Shorthand version of creating and registering subscriptions.

The last thing this tutorial needs to do is be able to handle the inbound subscription events.

See Also

Subscription Events

As a convenience to developers using the JS SDK it exposes Subscription Events. These Subscription Events are imilar Platform Events which can be used in eventListeners (discussed earlier in the tutorial):

  • notification: Fires only after subscribeSuccess and before either renewError or removeSuccess. This is your actual Notification data as dictated by the eventFilters set on the subscription
  • removeSuccess: Fires only after a subscription has been removed
  • removeError: Fires if there is an error trying to remove a subscription
  • renewSuccess: Fires when a subscription has successfully been renewed - NOTE: Subscriptions in the RingCentral SDKs renew automatically
  • renewError: Fires if there is an error attempting to renew a subscriptionq NOTE: This is important to listen for in your applications, as this can result in lost data and creating a poor user experience with your application or integration
  • subscribeSuccess: Fires if the subscription.register() method executes successfully. In production, your event consumers should be on the ready when you hear this event from RingCentral
  • subscribeError: Fires if there is an error attempting to execute subscription.register() method and provides additional information

Consuming Subscription Notifications

This is where the rubber meets the road for this tutorial, once you start the application and no errors have occurred, developers should see a console.log message 'SUBSCRIPTION CREATED SUCCESSFULLY'. This message is only displayed when our subscription.register() method has successfully accepted our eventFilters and started the subscription.

The code shown here is the event consuming portion of the tutorial. To test that this is operating, you will need to take action using your RingCentral account with respect to the eventFilters you defined in the environment variables for the instance of this application. Let's try one that is pretty easy to test, we will test: SUBSCRIBE_TO_EXTENSION_EVENTS

  1. Open your soft phone (making sure it is set to operate with the Sandbox API) desktop application
  2. Login as one of the extensions you know is a type === User and status === Enabled
  3. You should see a console.log prefixed with SUBSCRIPTION_NOTIFICATION..... (that means the subscription.on(subscription.events.notification) eventListener was triggered and has called handleSubscriptionNotification() and supplied the notification message as the argument (which is what we should see in the logs).
  4. Try toggling the various states of your user in the soft phone and watch the different types of events being generated and sent to your new app!