Receiving SMS and MMS messages

Last updated: 2025-08-28Contributors
Edit this page

Inbound SMS and MMS messages can be received instantly using the RingCentral push notification frameworks.

A user can subscribe to SMS event notifications to receive inbound messages sent to:

  • Any of their direct phone numbers, or
  • A company phone number or call queue number that the user is authorized to manage for SMS communication.

Phone Number Ownership and Feature Assignment

Refer to the Understanding Phone Number Ownership and Feature Assignment in RingCentral section for details on SMS feature assignment.

When subscribing to instant SMS events, your application must:

  1. Authenticate the user extension that will receive inbound text messages on its assigned phone number(s).
  2. Subscribe to the instant SMS event notification using the following event filter:
    [
    "/restapi/v1.0/account/~/extension/~/message-store/instant?type=SMS"
    ]
  3. Implement a Webhook server or a WebSocket connection to handle and process inbound messages in real time.

Receiving text messages on behalf of other users?

  • A super admin user can subscribe to instant SMS events to receive inbound text messages on behalf of one or more user extensions. In this scenario, the application must be authenticated as the super admin user. The eventFilters list can include multiple entries, each corresponding to a specific user identified by their extension ID.
    [
    "/restapi/v1.0/account/~/extension/[extension01Id]/message-store/instant?type=SMS",
    "/restapi/v1.0/account/~/extension/[extension02Id]/message-store/instant?type=SMS",
    "/restapi/v1.0/account/~/extension/[extensionNId]/message-store/instant?type=SMS"
    ]

Sample of a typical event payload of an inbound text message

The following is a sample SMS event notification payload. The essential data fields from.phoneNumber, to.phoneNumber, and subject are highlighted, where subject contains the actual text message content.

{
  "uuid": "6242343638330007102",
  "event": "/restapi/v1.0/account/80964XXXX/extension/629893XXXX/message-store/instant?type=SMS",
  "timestamp": "2025-07-30T18:12:45.034Z",
  "subscriptionId": "7e4a7486-8df9-4195-8aef-b8d81d3345f6",
  "ownerId": "629893XXXX",
  "body": {
    "id": "3062991514017",
    "to": [
      {
        "phoneNumber": "+1657390XXXX",
        "name": "VP Dan",
        "location": "Orange, CA",
        "target": true
      }
    ],
    "from": {
      "phoneNumber": "+1650224XXXX",
      "location": "Mountain View, CA",
      "phoneNumberInfo": {
        "countryCode": "1",
        "nationalDestinationCode": "650",
        "subscriberNumber": "224XXXX"
      }
    },
    "type": "SMS",
    "creationTime": "2025-07-30T18:12:45.028Z",
    "lastModifiedTime": "2025-07-30T18:12:45.028Z",
    "readStatus": "Unread",
    "priority": "Normal",
    "attachments": [
      {
        "id": "3062991514017",
        "type": "Text",
        "contentType": "text/plain"
      }
    ],
    "direction": "Inbound",
    "availability": "Alive",
    "subject": "Hi advisor, I'd like to ...",
    "messageStatus": "Received",
    "conversation": {
      "id": "1638233798595111162"
    },
    "eventType": "Create",
    "owner": {
      "extensionId": "629893XXXX",
      "extensionType": "User",
      "name": "VP Dan"
    }
  }
}

Use Case Example: Auto-Reply for Vacation Messages

A financial advisor wants to maintain personalized communication with clients through SMS using their assigned direct number (+1-555-987-XXXX). While on vacation, the advisor wants to automatically respond to any incoming text messages with an out-of-office notice indicating their unavailability and return date.

To accomplish this, the application will leverage the RingCentral REST API and Push Notification framework to:

  1. Authenticate as the advisor’s user extension.
  2. Subscribe to instant SMS event notifications for the advisor’s phone number.
  3. Implement logic to send an automatic reply when a new message is received.

Sample code

Install RingCentral JavaScript SDK

$ npm install @ringcentral/sdk @ringcentral/subscriptions --save

Create and edit a receive-reply-sms.js file

Create a file named receive-reply-sms.js, then copy and paste the following code into the file.

const RC = require('@ringcentral/sdk').SDK
const Subscriptions = require('@ringcentral/subscriptions').Subscriptions;

// Instantiate the SDK and get the platform and the subscription instances
const rcsdk = new RC({
    server: "https://platform.ringcentral.com",
    clientId: "RC_APP_CLIENT_ID",
    clientSecret: "RC_APP_CLIENT_SECRET"
});
const subscriptions = new Subscriptions({
   sdk: rcsdk
});

var platform = rcsdk.platform();
var subscription = subscriptions.createSubscription();

/* Authenticate a user using a personal JWT token */
platform.login({ jwt: "RC_USER_JWT" })

platform.on(platform.events.loginSuccess, function(e){
    subscribe_for_instant_messages_notification()
});

platform.on(platform.events.loginError, function(e){
    console.log("Unable to authenticate to platform. Check credentials.", e.message)
    process.exit(1)
});

/*
  Subscribe for the user instant message event notification
*/
async function subscribe_for_instant_messages_notification(){
  var eventFilters = [ '/restapi/v1.0/account/~/extension/~/message-store/instant?type=SMS' ]
  subscription.setEventFilters(eventFilters)
  .register()
  .then(function(subscriptionResponse) {
      console.log("Ready to receive SMS message via WebSocket.")
  })
  .catch(function(e) {
    console.error(e.message);
  })
}

/*
*  Receive inbound messages from WebSocket subscription event notification
*/
subscription.on(subscription.events.notification, function(msg) {
    send_reply(msg.body)
});

/*
 Send a reply message to a client number
*/
async function send_reply(body){
  var text = 'Hi'
  if (body.from.name)
    text += ` ${body.from.name}.`

  text += "\nThank you for your message. I’m currently on vacation and will be available after August 15th."
  let bodyParams = {
           from: {phoneNumber: body.to[0].phoneNumber},
           to: [ {phoneNumber: body.from.phoneNumber}],
           text: text
         }

  try{
    let endpoint = "/restapi/v1.0/account/~/extension/~/sms"
    await refresh_token()
    var resp = await platform.post(endpoint, bodyParams)
  }catch(e){
    console.log(`Unable to send a reply message to ${bodyParams.to[0].phoneNumber}. Error message:`, e.message)
  }
}

async function refresh_token(){
  if (await platform.loggedIn() == false){
    console.log("Both tokens expired => Relogin using the user JWT.")
    await platform.login( { jwt: "RC_USER_JWT" })
  }else{
    console.log("Token valid")
  }
}

Install RingCentral PHP SDK

$ curl -sS https://getcomposer.org/installer | php
$ php composer.phar require ringcentral/ringcentral-php

Create and edit a receive-reply-sms.php file

Create a file named receive-reply-sms.php, then copy and paste the following code into the file.

<?php
require('vendor/autoload.php');

use RingCentral\SDK\WebSocket\WebSocket;
use RingCentral\SDK\WebSocket\Subscription;
use RingCentral\SDK\WebSocket\Events\NotificationEvent;

// Instantiate the SDK and get the platform instance
$rcsdk = new RingCentral\SDK\SDK( "RC_APP_CLIENT_ID", "RC_APP_CLIENT_SECRET", "https://platform.ringcentral.com" );
$platform = $rcsdk->platform();

/* Authenticate a user using a personal JWT token */
try {
  $platform->login(["jwt" => "RC_USER_JWT"]);
}catch (\RingCentral\SDK\Http\ApiException $e) {
  exit("Unable to authenticate to platform. Check credentials. " . $e->message . PHP_EOL);
}
subscribe_for_instant_messages_notification();

/*
  Subscribe for the user instant message event notification
*/
function subscribe_for_instant_messages_notification(){
  global $rcsdk;
  $websocket = $rcsdk->initWebSocket();
  $websocket->connect();
  $subscription = $rcsdk->createSubscription();
  $subscription->addEvents(array('/restapi/v1.0/account/~/extension/~/message-store/instant?type=SMS'));

  /*
    Receive inbound messages from WebSocket subscription event notification
  */
  $subscription->addListener(Subscription::EVENT_NOTIFICATION, function (NotificationEvent $event) {
      send_reply($event->payload()['body']);
  });

  $subscription->register();
}

/*
*  Send a reply message to a client number
*/
function send_reply($body){
  global $platform;
  try {
    $textMessage = "Hi";
    if (isset($body['from']['name']))
        $textMessage .= " " . $body['from']['name'];
    $textMessage .= "\nThank you for your message. I’m currently on vacation and will be available after August 15th.";
    $bodyParams = array(
      'from' => array( 'phoneNumber' => $body['to'][0]['phoneNumber'] ),
      'to'   => array( array('phoneNumber' => $body['from']['phoneNumber'])),
      'text' => $textMessage
    );

    $endpoint = "/restapi/v1.0/account/~/extension/~/mms";
    refresh_token();
    $resp = $platform->post($endpoint, $bodyParams);
  }catch (\RingCentral\SDK\Http\ApiException $e) {
    // Getting error messages using PHP native interface
    print 'Expected HTTP Error: ' . $e->message . PHP_EOL;
  }
}

function refresh_token(){
  global $platform;
  if (!$platform->loggedIn()){
    print "Both tokens expired => Relogin using the user JWT" . PHP_EOL;
    $platform->login( [ "jwt" => "RC_USER_JWT" ] );
  }else{
    print "Token valid" . PHP_EOL;
  }
}
?>

Install RingCentral Python SDK

$ pip install ringcentral

Create and edit a receive-reply-sms.py file

Create a file named receive-reply-sms.py, then copy and paste the following code into the file.

from ringcentral import SDK
import asyncio
import os
from ringcentral.websocket.events import WebSocketEvents

# Send a reply message to a client number
def send_reply(body):
    try:
        textMessage = "Hi"
        if 'name' in body['from']:
            textMessage += " " + body['from']['name']
        textMessage += "\nThank you for your message. I’m currently on vacation and will be available after August 15th."
        bodyParams = {
             'from' : { 'phoneNumber': body['to'][0]['phoneNumber'] },
             'to'   : [ {'phoneNumber': body['from']['phoneNumber']} ],
             'text' : textMessage
        }
        endpoint = "/restapi/v1.0/account/~/extension/~/sms"
        refresh_token()
        resp = platform.post(endpoint, bodyParams)
        print("Replied.")
    except Exception as e:
        print (e)

def refresh_token():
    if platform.logged_in() == False:
        print("Both tokens expired => Relogin.")
        platform.login(jwt= "RC_USER_JWT")
    else:
        print("Token valid.")

#
# Receive inbound messages from WebSocket subscription event notification
#
def on_notification(message):
    send_reply(message[1]['body'])

def on_sub_created(sub):
    print("\n Subscription created:\n")
    print(sub.get_subscription_info())
    print("\n Please go and change your user status \n")

def on_ws_created(web_socket_client):
    print("\nNew WebSocket connection created:")

# Subscribe for the user instant message event notification
async def subscribe_for_instant_messages_notification():
    try:
        web_socket_client = rcsdk.create_web_socket_client()
        web_socket_client.on(WebSocketEvents.connectionCreated, on_ws_created)
        web_socket_client.on(WebSocketEvents.subscriptionCreated, on_sub_created)
        web_socket_client.on(WebSocketEvents.receiveSubscriptionNotification, on_notification)
        await asyncio.gather(
            web_socket_client.create_new_connection(),
            web_socket_client.create_subscription(["/restapi/v1.0/account/~/extension/~/message-store/instant?type=SMS"])
        )
    except KeyboardInterrupt:
        print("Stopped by User")

# Authenticate a user using a personal JWT token
def login():
    print ("running in a loop")
    platform.login(jwt= "RC_USER_JWT")
    asyncio.run(subscribe_for_instant_messages_notification())

# Instantiate the SDK and get the platform instance
rcsdk = SDK("RC_APP_CLIENT_ID", "RC_APP_CLIENT_SECRET", "https://platform.ringcentral.com")
platform = rcsdk.platform()

login()

Install RingCentral Ruby SDK

$ gem install ringcentral-sdk dotenv

Create and edit a receive-reply-sms.rb file

Create a file named receive-reply-sms.rb, then copy and paste the following code into the file.

require 'ringcentral'
require 'subscription'

#
#  Subscribe for the user instant message event notification
#
def subscribe_for_instant_messages_notification()
  events = [
    '/restapi/v1.0/account/~/extension/~/message-store/instant?type=SMS'
  ]
  subscription = WS.new($platform, events, lambda { |message|
    send_reply(message['body'])
  })
  subscription.subscribe()
  puts "Waiting for incoming SMS message ..."
  while 1
      sleep(5)
  end
end

#
# Send a reply message to a client number
#
def send_reply(body)
  begin
    textMessage = "Hi"
    if body['from'].key?('name')
      text_message += " " + body['from']['name']
    end
    textMessage += "\nThank you for your message. I’m currently on vacation and will be available after August 15th."
    bodyParams = {
            from: {phoneNumber: body['to'][0]['phoneNumber'] },
            to: [ {phoneNumber: body['from']['phoneNumber']} ],
            text: textMessage
    }

    endpoint =  "/restapi/v1.0/account/~/extension/~/sms"
    refresh_token()
    resp = $platform.post(endpoint, payload: bodyParams)
  rescue StandardError => e
    puts (e)
  end
end

def refresh_token()
    if $platform.refresh() == nil
        puts "Both tokens expired => Relogin."
        $platform.authorize(jwt: "RC_USER_JWT")
    else
        puts "Token valid."
    end
end

# Authenticate a user using a personal JWT token
def login()
  begin
    $platform.authorize(jwt: "RC_USER_JWT")
    subscribe_for_instant_messages_notification()
  rescue StandardError => e
    puts ("Unable to authenticate to platform. Check credentials." + e.to_s)
  end
end

# Instantiate the SDK and get the platform instance
$platform = RingCentral.new( "RC_APP_CLIENT_ID", "RC_APP_CLIENT_SECRET", "https://platform.ringcentral.com" )

login()


Running the code

If you have tried the Send SMS quick start, you can just copy all the functions above and add them to the quick start project then call the subscribe_for_instant_messages_notification() function. Otherwise, edit the following variables in the code with your app's credentials and the user's JWT before running the code.

"RC_USER_JWT"
"RC_APP_CLIENT_ID"
"RC_APP_CLIENT_SECRET"

Important

The additional refresh_token() function is crucial for long-running processes that need to operate continuously for weeks or months. This is because the access_token is valid for only 1 hour, and the refresh_token expires after 7 days. If no API calls are made for more than a week, both tokens will expire. In such cases, the application must be reauthorized using the user’s JWT token.

Alternatively, you can use a timer to periodically call the platform.refresh() method (for example, daily or every 6 days) to prevent the refresh_token from expiring.

Other Key Considerations:

  • Prevent Loops: Do not auto-reply to messages from unknown senders. Only respond to messages from the advisor’s verified contacts.
  • Smart Responses: Use AI or NLP to analyze inbound message content and provide context-appropriate replies.
  • One-Time Reply: Optionally, store the client’s number in memory or a database to avoid sending multiple vacation replies to the same contact.
  • Webhook for Reliability: Consider using Webhook notifications instead of WebSocket notifications for long-running processes for better stability.

Parsing MMS Messages and Downloading Attachments

MMS message event notifications work the same way as SMS message notifications. The key difference lies in the event payload: MMS notifications include one or more MmsAttachment type attachments. To download an MMS attachment, use the uri value from the attachment object along with the user’s valid access_token.

Sample payload for a typical inbound MMS message event

Here is an example of a typical inbound MMS message event payload. The essential data fields from.phoneNumber, to.phoneNumber, and the MMS attachment object are highlighted. The uri field within any attachment object of type "MmsAttachment" provides the link to the actual binary content.

{
  "id": "3064938607016",
  "to": [
    {
      "phoneNumber": "+1657390XXXX",
      "name": "VP Don",
      "location": "Orange, CA",
      "target": true
    }
  ],
  "from": {
    "phoneNumber": "+1650224XXXX",
    "location": "Mountain View, CA",
    "phoneNumberInfo": {
      "countryCode": "1",
      "nationalDestinationCode": "650",
      "subscriberNumber": "224XXXX"
    }
  },
  "type": "SMS",
  "creationTime": "2025-07-31T20:13:18.861Z",
  "lastModifiedTime": "2025-07-31T20:13:18.861Z",
  "readStatus": "Unread",
  "priority": "Normal",
  "attachments": [
    { "id": "3064938607016", "type": "Text", "contentType": "text/plain" },
    {
      "id": "675981076016",
      "type": "MmsAttachment",
      "uri": "https://media.ringcentral.com/restapi/v1.0/account/80964XXXX/extension/629893XXXX/message-store/3064938607016/content/675981076016",
      "contentType": "image/jpeg",
      "size": 461020
    }
  ],
  "direction": "Inbound",
  "availability": "Alive",
  "subject": "Hi there",
  "messageStatus": "Received",
  "conversation": { "id": "1638233798595111162" },
  "eventType": "Create",
  "owner": { "extensionId": "629893XXXX", "extensionType": "User", "name": "VP Don" }
}

Sample code to download an MMS attachment

Let's edit the example code above to add a function to download an MMS message's attachments.

Edit the receive-reply-sms.js file

Edit the receive-reply-sms.js file by replacing the subscription.on(subscription.events.notification, function(msg) function and adding the download_mms_attachments(attachments) function below to the existing code.

/*
*  Receive inbound messages from WebSocket subscription event notification
*/
subscription.on(subscription.events.notification, async function(msg) {
  // send_reply(msg.body)
  download_mms_attachments(msg.body.attachments)
});

/*
  Download an MMS message attachments
*/
const fs = require('fs')
async function download_mms_attachments(attachments){
  await refresh_token()
  for (var attachment of attachments){
    if (attachment.type == "MmsAttachment"){
      let contentType = attachment.contentType.split("/")
      let fileName = `${attachment.id}.${contentType[1]}`
      let res = await platform.get(attachment.uri)
      await res.body.pipe(fs.createWriteStream(fileName))
    }
  }
}

Edit the receive-reply-sms.php file

Edit the receive-reply-sms.py file by replacing the subscribe_for_instant_messages_notification() function and adding the download_mms_attachment($attachments) function below to the existing code.

<?php
/*
  Subscribe for the user instant message event notification
*/
function subscribe_for_instant_messages_notification(){
  global $rcsdk;
  $websocket = $rcsdk->initWebSocket();
  $websocket->connect();
  $subscription = $rcsdk->createSubscription();
  $subscription->addEvents(array('/restapi/v1.0/account/~/extension/~/message-store/instant?type=SMS'));

  /*
    Receive inbound messages from WebSocket subscription event notification
  */
  $subscription->addListener(Subscription::EVENT_NOTIFICATION, function (NotificationEvent $event) {
      // send_reply($event->payload()['body']);
      $attachments = $event->payload()['body']['attachments'];
      download_mms_attachments($attachments);

  });
  $subscription->register();
}

/*
  Download an MMS message attachments
*/
function download_mms_attachments($attachments){
  global $platform;
  refresh_token();
  foreach($attachments as $attachment){
    $fileName = $attachment['id'];
    if ($attachment['type'] == "MmsAttachment"){
      $fileNameExt = preg_split("/[\/]/", $attachment['contentType'], -1);
      $fileName .= "." . $fileNameExt[1];
      try {
        $res = $platform->get($attachment['uri']);
        file_put_contents($fileName, $res->raw());
      }catch (ApiException $e) {
        $message = $e->getMessage();
        print 'Expected HTTP Error: ' . $message . PHP_EOL;
      }
    }
  }
}
?>

Edit the receive-reply-sms.py file

Edit the receive-reply-sms.py file by replacing the on_notification(message) function and adding the download_mms_attachments(attachments) function below to the existing code.

#
# Receive inbound messages from WebSocket subscription event notification
#
def on_notification(message):
    # send_reply(message[1]['body'])
    download_mms_attachments(message[1]['body']['attachments'])

#
# Download an MMS message attachments
#
def download_mms_attachments(attachments):
    refresh_token()
    for attachment in attachments:
        fileName = str(attachment['id'])
        if attachment['type'] == "MmsAttachment":
            fileNameExt = attachment['contentType'].split("/")
            fileName = ("%s.%s" % (fileName, fileNameExt[1]))
            try:
                res = platform.get(attachment['uri'])
                with open(fileName, 'wb') as file:
                    file.write(res.body())
                    file.close()
            except ApiException as e:
                print (e.getMessage())

Edit the receive-reply-sms.rb file

Edit the receive-reply-sms.rb file by replacing the subscribe_for_instant_messages_notification() function and adding the download_mms_attachments(attachments) function below to the existing code.

#
#  Subscribe for the user instant message event notification
#
def subscribe_for_instant_messages_notification()
  events = [
    '/restapi/v1.0/account/~/extension/~/message-store/instant?type=SMS'
  ]
  #
  # Receive inbound messages from WebSocket subscription event notification
  #
  subscription = WS.new($platform, events, lambda { |message|
    # send_reply(message['body'])
    download_mms_attachments(message['body']['attachments'])
  })
  subscription.subscribe()
  puts "Waiting for incoming SMS/MMS messages ..."
  while 1
      sleep(5)
  end
end

#
# Download an MMS message attachments
#
def download_mms_attachments(attachments)
  refresh_token()
  for attachment in attachments
    if attachment["type"] == "MmsAttachment"
      file_name_ext = attachment["contentType"].split("/")
      file_name = "%s.%s" % [attachment["id"], file_name_ext[1]]
      begin
        res = $platform.get(attachment["uri"])
        File.open(file_name, "wb") { |file| file.write(res.body) }
      rescue IOError => e
        puts e.message
      end
    end
  end
end