<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Benjamin Aronov</title>
    <description>The latest articles on DEV Community by Benjamin Aronov (@benjamin-aronov).</description>
    <link>https://dev.to/benjamin-aronov</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F176178%2Fb401d087-81d6-492d-aee5-e6c204d0e539.jpg</url>
      <title>DEV Community: Benjamin Aronov</title>
      <link>https://dev.to/benjamin-aronov</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/benjamin-aronov"/>
    <language>en</language>
    <item>
      <title>How to Send RCS Rich Card Carousels With Node.js</title>
      <dc:creator>Benjamin Aronov</dc:creator>
      <pubDate>Fri, 12 Sep 2025 15:23:13 +0000</pubDate>
      <link>https://dev.to/vonagedev/how-to-send-rcs-rich-card-carousels-with-nodejs-15n6</link>
      <guid>https://dev.to/vonagedev/how-to-send-rcs-rich-card-carousels-with-nodejs-15n6</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://developer.vonage.com/en/blog/rcs-business-messaging-is-now-in-the-vonage-messages-api" rel="noopener noreferrer"&gt;Rich Communication Services (RCS)&lt;/a&gt; gives you the tools to build modern, interactive brand experiences right inside a user’s default messaging app. Among its most powerful features is the rich card carousel: a horizontally scrollable set of cards that can include videos, images, text, and tappable actions.&lt;/p&gt;

&lt;p&gt;In this tutorial, you’ll learn how to send an RCS carousel using Node.js and the &lt;a href="https://developer.vonage.com/en/messages/overview" rel="noopener noreferrer"&gt;Vonage Messages API&lt;/a&gt;. You’ll combine video and image cards with actions to boost engagement.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;&amp;gt;&amp;gt; TL;DR: View the full working &lt;a href="https://github.com/Vonage-Community/tutorial-messages-node-rcs_carousel-rich-card/tree/main" rel="noopener noreferrer"&gt;code on GitHub&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://youtu.be/ORSlt1nAHbA" rel="noopener noreferrer"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Use Case: Fashion Popup Announcement
&lt;/h2&gt;

&lt;p&gt;Let’s say your brand is launching a limited-time fashion pop-up shop. You want to generate buzz and showcase key items. With an RCS carousel, you can package this all in one clean, interactive message.&lt;/p&gt;

&lt;p&gt;Your RCS carousel will include media and suggested actions:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Card 1: Event Launch Video

&lt;ul&gt;
&lt;li&gt;Video trailer for the popup&lt;/li&gt;
&lt;li&gt;2 actions: “Save the Date” and “See Location”&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Card 2: T-Shirts image:

&lt;ul&gt;
&lt;li&gt;An image of the featured tee&lt;/li&gt;
&lt;li&gt;action: “See All Shirts”&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Card 3: Hats image:

&lt;ul&gt;
&lt;li&gt;An image of your hat collection&lt;/li&gt;
&lt;li&gt;action: “See All Hats”&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  What Is an RCS Carousel?
&lt;/h2&gt;

&lt;p&gt;An RCS carousel is a set of swipeable rich cards, each with its own:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A title (max 200 characters)&lt;/li&gt;
&lt;li&gt;A description (max 2000 characters)&lt;/li&gt;
&lt;li&gt;Media: image or video&lt;/li&gt;
&lt;li&gt;Up to four suggested replies or actions&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The cards appear horizontally, allowing users to swipe through them.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1jc3qgo2yhhzbb2dwku6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1jc3qgo2yhhzbb2dwku6.png" alt="Illustration of an RCS carousel message in the Android Messages app, annotated to show benefits like trusted branding, verified sender ID, richer media cards, time-saving action buttons, and quick-reply suggestions." width="687" height="577"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Important notes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;All cards in a carousel must use the same type of suggestion.&lt;/li&gt;
&lt;li&gt;Media files must be publicly accessible and under 100MB.&lt;/li&gt;
&lt;li&gt;You can include between 2 and 10 cards.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Prerequisites
&lt;/h2&gt;

&lt;p&gt;Before you start, you’ll need:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://nodejs.org/en/download" rel="noopener noreferrer"&gt;Node.js installed&lt;/a&gt; on your machine.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://ngrok.com/downloads/mac-os" rel="noopener noreferrer"&gt;ngrok installed&lt;/a&gt; for exposing your local server to the internet.&lt;/li&gt;
&lt;li&gt;A Vonage API account.&lt;/li&gt;
&lt;li&gt;A registered RCS Business Messaging (RBM) Agent, see managed accounts below.&lt;/li&gt;
&lt;li&gt;A phone with RCS capabilities for testing.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Vonage API Account
&lt;/h3&gt;

&lt;p&gt;To complete this tutorial, you will need a &lt;a href="https://developer.vonage.com/sign-up" rel="noopener noreferrer"&gt;Vonage API account&lt;/a&gt;. If you don’t have one already, you can sign up today and start building with free credit. Once you have an account, you can find your API Key and API Secret at the top of the &lt;a href="https://dashboard.nexmo.com/" rel="noopener noreferrer"&gt;Vonage API Dashboard&lt;/a&gt;.&lt;/p&gt;

&lt;h4&gt;
  
  
  Ready to start building?
&lt;/h4&gt;

&lt;p&gt;Experience seamless connectivity, real-time messaging, and crystal-clear voice and video calls—all at your fingertips.&lt;/p&gt;

&lt;h2&gt;
  
  
  How to Contact Your Vonage Account Manager
&lt;/h2&gt;

&lt;p&gt;In order to send and receive RCS capabilities in your Vonage application, you will need to have a registered Rich Business Messaging (RBM) agent and a &lt;a href="https://api.support.vonage.com/hc/en-us/articles/16711304811932-How-can-I-check-if-RCS-Rich-Communication-Services-is-active-on-my-device" rel="noopener noreferrer"&gt;phone with RCS capabilities&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Currently, RCS Messaging through Vonage is only available for managed accounts. You will need to contact your account manager to request Developer Mode activation for your RBM agent. Developer Mode allows you to test RCS messaging to allow-listed numbers before completing the Agent Verification process and launching in production.&lt;/p&gt;

&lt;p&gt;Please &lt;a href="https://www.vonage.com/contact-us/" rel="noopener noreferrer"&gt;contact our sales team&lt;/a&gt; if you do not have a managed account. &lt;/p&gt;

&lt;blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;Understand the &lt;a href="https://api.support.vonage.com/hc/en-us/articles/15546468078108-Understanding-RCS-and-RBM" rel="noopener noreferrer"&gt;difference between RCS and RBM&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;


&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  How to Set Up Your Node.js Project
&lt;/h2&gt;

&lt;p&gt;This guide assumes you're familiar with JavaScript and Node.js basics. &lt;/p&gt;

&lt;h3&gt;
  
  
  Initialize the Project
&lt;/h3&gt;

&lt;p&gt;Create a new directory and initialize a Node.js project:&lt;/p&gt;

&lt;h3&gt;
  
  
  Install Required NPM Packages
&lt;/h3&gt;

&lt;p&gt;Install the necessary node packages with &lt;a href="https://www.npmjs.com/" rel="noopener noreferrer"&gt;Node Package Manager&lt;/a&gt; (NPM):&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://www.npmjs.com/package/express" rel="noopener noreferrer"&gt;express&lt;/a&gt;: Creates the web server&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.npmjs.com/package/dotenv" rel="noopener noreferrer"&gt;dotenv&lt;/a&gt;: Loads your environment variables&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.npmjs.com/package/@vonage/server-sdk" rel="noopener noreferrer"&gt;@vonage/server-sdk&lt;/a&gt;: Sends messages through the Vonage Messages API&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Create Your Project Files
&lt;/h3&gt;

&lt;p&gt;Create the main application file and environment configuration file:&lt;/p&gt;

&lt;h2&gt;
  
  
  How to Configure Your Environment
&lt;/h2&gt;

&lt;p&gt;In the .env file, add your Vonage credentials and configuration:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt; VONAGE_APPLICATION_ID: Your Vonage application ID.&lt;/li&gt;
&lt;li&gt;VONAGE_API_SIGNATURE_SECRET= Your Vonage API Secret&lt;/li&gt;
&lt;li&gt;VONAGE_PRIVATE_KEY: Your Vonage application’s private key file.&lt;/li&gt;
&lt;li&gt;RCS_SENDER_ID: Your RBM SenderID (the Name of the Brand). The SenderID requires special formatting, such as not having any spaces. Check with your account manager if you’re unsure.&lt;/li&gt;
&lt;li&gt;PORT: Port number for the Express server.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You will obtain your Vonage Application ID and private.key file below, in the &lt;em&gt;“How to Create and Configure Vonage Application”&lt;/em&gt; section. Find your API Secret in the &lt;a href="https://dashboard.vonage.com/" rel="noopener noreferrer"&gt;developer dashboard homepage&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  How to Send an RCS Carousel
&lt;/h2&gt;

&lt;p&gt;Now that your environment is set up, let’s write the code that actually sends your RCS rich card carousel.&lt;/p&gt;

&lt;p&gt;In this step, you’ll create an Express server that sends a custom RCS message using the Vonage Messages API. The carousel will contain three swipeable product cards, each with media (video or image), a title and description, and actionable buttons your users can tap.&lt;/p&gt;

&lt;h3&gt;
  
  
  Load Dependencies and Initialize the Vonage Client
&lt;/h3&gt;

&lt;p&gt;We’ll start by importing the necessary packages, loading your environment variables, and initializing the Vonage client. Add the following code to your index.js file to get things going:&lt;/p&gt;

&lt;h3&gt;
  
  
  Define an Express Endpoint to Send a RCS Carousel
&lt;/h3&gt;

&lt;p&gt;A few small but important details are worth knowing before we send the carousel. All media files must be publicly accessible over HTTPS, ideally hosted on a CDN or cloud storage. We’re using GitHub-hosted assets for simplicity in this example, but in production, you’ll want faster, more reliable media hosting. &lt;/p&gt;

&lt;p&gt;&lt;em&gt;&amp;gt;&amp;gt; Keep individual media files under 100MB to meet RCS constraints.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Each card includes one or more action buttons using postbackData, openUrlAction, or createCalendarEventAction. The postbackData value is a short string (50 characters max) that your server can use to track what users tap. You can also link directly to maps or pre-filled calendar events for added interactivity, making the carousel feel more like a mini-app than just a message.&lt;/p&gt;

&lt;h2&gt;
  
  
  How to Receive RCS Suggested Actions via Webhooks
&lt;/h2&gt;

&lt;p&gt;Sending off a carousel is great! But wouldn’t it be nice to know if your user interacted with your carousel?  With Vonage webhooks, you can do just that.&lt;/p&gt;

&lt;p&gt;Create the following endpoint, which will handle inbound RCS requests from our Vonage application. This code:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Validates that the request is coming from Vonage using a JWT signature&lt;/li&gt;
&lt;li&gt;Looks for the button property since you’re expecting an action instead of a reply property, and stores the payload in userAction&lt;/li&gt;
&lt;li&gt;Logs the userAction to our Node server to see what the user selected&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  How to Define Your Express Server
&lt;/h2&gt;

&lt;p&gt;At the bottom of your index.js, add this code to build your Express server.&lt;/p&gt;

&lt;p&gt;And finally run your server from the command line:&lt;/p&gt;

&lt;p&gt;&lt;em&gt;&amp;gt;&amp;gt; &lt;a href="https://github.com/Vonage-Community/tutorial-messages-node-rcs_carousel-rich-card/tree/main" rel="noopener noreferrer"&gt;See the full index.js file.&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  How to Expose Your Server with ngrok
&lt;/h2&gt;

&lt;p&gt;To receive webhooks from Vonage, your local server must be accessible over the internet. Use ngrok to expose your server by running the following command in a separate tab from your Express sever:&lt;/p&gt;

&lt;p&gt;Note the HTTPS URL provided by ngrok (e.g., &lt;a href="https://your-ngrok-subdomain.ngrok.io" rel="noopener noreferrer"&gt;https://your-ngrok-subdomain.ngrok.io&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;You can read more about &lt;a href="https://developer.vonage.com/getting-started/tools/ngrok" rel="noopener noreferrer"&gt;testing with ngrok&lt;/a&gt; in our developer portal tools.&lt;/p&gt;

&lt;h2&gt;
  
  
  How to Create and Configure Your Vonage Application
&lt;/h2&gt;

&lt;p&gt;Now that your Node App is ready, you’ll also need to create and set up your Vonage Application. First, create your app in the &lt;a href="https://dashboard.nexmo.com/applications/new" rel="noopener noreferrer"&gt;Vonage Dashboard&lt;/a&gt;. Give the app a name and turn on the Messages capability. &lt;/p&gt;

&lt;p&gt;&lt;em&gt;Vonage dashboard showing the creation of a new application configured for RCS messaging.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;In your Vonage application settings:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Set the Inbound URL to &lt;a href="https://YOUR_NGROK_URL/inbound_rcs" rel="noopener noreferrer"&gt;https://YOUR_NGROK_URL/inbound_rcs&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Set the Status URL to &lt;a href="https://example.com/rcs_status" rel="noopener noreferrer"&gt;https://example.com/rcs_status&lt;/a&gt;. 
** Message statuses will be covered in a future article.&lt;/li&gt;
&lt;li&gt;Generate a public and private key by clicking the button. Ensure to move your private.key file to the project root directory (rcs-carousel-node).&lt;/li&gt;
&lt;li&gt;Save the changes.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Then link your RCS Agent by clicking the “Link external accounts” tab:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fu3artqvfxkvmb5dn1sf3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fu3artqvfxkvmb5dn1sf3.png" alt="Dashboard view showing the Vonage-Node-RCS application linked to the Vonage RoR RCS external account, with voice and message capabilities enabled." width="800" height="397"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Dashboard view showing the Vonage-Node-RCS application linked to the Vonage RoR RCS external account, with voice and message capabilities enabled.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  How to Test Your Node Application
&lt;/h2&gt;

&lt;p&gt;Use this curl command to trigger your endpoint (replace placeholders):&lt;/p&gt;

&lt;p&gt;On the recipient's phone, the Rich Card Carousel will appear and they can select an action!&lt;/p&gt;

&lt;h2&gt;
  
  
  Final Notes
&lt;/h2&gt;

&lt;p&gt;You’ve now built an interactive RCS product carousel with Node.js and the Vonage Messages API. This is a great way to showcase products, promote events, or offer dynamic choices in a single message.&lt;/p&gt;

&lt;p&gt;Want to go further?&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Respond to taps and selections via postbackData&lt;/li&gt;
&lt;li&gt;Load product cards dynamically from an API&lt;/li&gt;
&lt;li&gt;Add location-based filters or categories&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Come show off what you’re building in the&lt;a href="https://developer.vonage.com/community/slack" rel="noopener noreferrer"&gt;Vonage Community Slack&lt;/a&gt; or tag us on &lt;a href="https://twitter.com/VonageDev" rel="noopener noreferrer"&gt;X (formerly Twitter)&lt;/a&gt;. We’d love to see your carousels in the wild!&lt;/p&gt;

</description>
      <category>rcs</category>
      <category>node</category>
    </item>
    <item>
      <title>Send and Receive RCS Suggested Replies with ASP.NET Core and Vonage</title>
      <dc:creator>Benjamin Aronov</dc:creator>
      <pubDate>Fri, 15 Aug 2025 14:37:43 +0000</pubDate>
      <link>https://dev.to/vonagedev/send-and-receive-rcs-suggested-replies-with-aspnet-core-and-vonage-34fj</link>
      <guid>https://dev.to/vonagedev/send-and-receive-rcs-suggested-replies-with-aspnet-core-and-vonage-34fj</guid>
      <description>&lt;p&gt;&lt;a href="https://developer.vonage.com/en/messages/concepts/rcs" rel="noopener noreferrer"&gt;Rich Communication Services (RCS)&lt;/a&gt; represents the evolution of SMS: bringing branded, interactive, and app-like experiences into your native messaging app. With &lt;a href="https://developer.vonage.com/en/messages/overview" rel="noopener noreferrer"&gt;Vonage’s Messages API&lt;/a&gt;, you can deliver RCS messages with &lt;a href="https://developer.vonage.com/en/messages/guides/rcs/rcs-custom-messages#suggested-replies" rel="noopener noreferrer"&gt;Suggested Replies&lt;/a&gt;: clickable options that improve engagement and streamline response handling.&lt;/p&gt;

&lt;p&gt;In this tutorial, you’ll build an ASP.NET Core Web API from scratch that uses &lt;a href="https://github.com/Vonage/vonage-dotnet-sdk" rel="noopener noreferrer"&gt;Vonage’s .NET SDK&lt;/a&gt; to send and receive RCS suggested reply messages. You’ll also learn how to configure the application, set up secure webhooks, and test the end-to-end flow using ngrok and your RCS-enabled phone.&lt;/p&gt;

&lt;blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;TL;DR: View the full working &lt;a href="https://github.com/Vonage-Community/tutorial-messages-asp_dot_net_core-rcs_suggested_replies" rel="noopener noreferrer"&gt;code on GitHub&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;


&lt;/blockquote&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6jiwu5rsdzpp794zr8n7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6jiwu5rsdzpp794zr8n7.png" alt="RCS message sent using the Vonage Messages API, prompting the user to select a preferred appointment time with suggested reply buttons." width="576" height="1280"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;RCS message sent using the Vonage Messages API, prompting the user to select a preferred appointment time with suggested reply buttons.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Prerequisites
&lt;/h2&gt;

&lt;p&gt;Before we get started, make sure you have:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://dotnet.microsoft.com/en-us/download" rel="noopener noreferrer"&gt;.NET 9.0 SDK&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://visualstudio.microsoft.com/" rel="noopener noreferrer"&gt;Visual Studio 2022+&lt;/a&gt; or VS Code&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://ngrok.com/" rel="noopener noreferrer"&gt;ngrok&lt;/a&gt; for local tunneling&lt;/li&gt;
&lt;li&gt;A Vonage API account and a registered RBM agent. (See below)&lt;/li&gt;
&lt;li&gt;An RCS-capable device for testing&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Vonage API Account
&lt;/h3&gt;

&lt;p&gt;To complete this tutorial, you will need a &lt;a href="https://developer.vonage.com/sign-up" rel="noopener noreferrer"&gt;Vonage API account&lt;/a&gt;. If you don’t have one already, you can sign up today and start building with free credit. Once you have an account, you can find your API Key and API Secret at the top of the &lt;a href="https://dashboard.nexmo.com/" rel="noopener noreferrer"&gt;Vonage API Dashboard&lt;/a&gt;.&lt;/p&gt;

&lt;h4&gt;
  
  
  Ready to start building?
&lt;/h4&gt;

&lt;p&gt;Experience seamless connectivity, real-time messaging, and crystal-clear voice and video calls—all at your fingertips.&lt;/p&gt;

&lt;h2&gt;
  
  
  How to Contact Your Vonage Account Manager
&lt;/h2&gt;

&lt;p&gt;In order to send and receive RCS capabilities in your Vonage application, you will need to have a registered Rich Business Messaging (RBM) agent and a &lt;a href="https://api.support.vonage.com/hc/en-us/articles/16711304811932-How-can-I-check-if-RCS-Rich-Communication-Services-is-active-on-my-device" rel="noopener noreferrer"&gt;phone with RCS capabilities&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Currently, RCS Messaging through Vonage is only available for managed accounts. You will need to contact your account manager to request Developer Mode activation for your RBM agent. Developer Mode allows you to test RCS messaging to allow-listed numbers before completing the Agent Verification process and launching in production.&lt;/p&gt;

&lt;p&gt;Please &lt;a href="https://www.vonage.com/contact-us/" rel="noopener noreferrer"&gt;contact our sales team&lt;/a&gt; if you do not have a managed account. &lt;/p&gt;

&lt;blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;Understand the &lt;a href="https://api.support.vonage.com/hc/en-us/articles/15546468078108-Understanding-RCS-and-RBM" rel="noopener noreferrer"&gt;difference between RCS and RBM&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;


&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Create the ASP.NET Core Project
&lt;/h2&gt;

&lt;p&gt;We’ll start by generating a minimal ASP.NET Core Web API using the built-in CLI template.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;dotnet new web -n RcsSuggestedReplies
cd RcsSuggestedReplies
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Add Required NuGet Packages
&lt;/h2&gt;

&lt;p&gt;Install the necessary dependencies:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;dotnet add package Vonage
dotnet add package Microsoft.AspNetCore.Mvc.NewtonsoftJson
dotnet add package Microsoft.AspNetCore.OpenApi
dotnet add package Swashbuckle.AspNetCore
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Vonage: To use the Messages API&lt;/li&gt;
&lt;li&gt;Newtonsoft.Json: JSON handling for API requests and responses&lt;/li&gt;
&lt;li&gt;OpenApi: OpenAPI specification support for your endpoints&lt;/li&gt;
&lt;li&gt;Swashbuckle: Swagger UI for testing your API in the browser&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Create a Configuration Class
&lt;/h2&gt;

&lt;p&gt;Create CustomConfiguration.cs in the root of your project and add:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;namespace RcsSuggestedReplies;

public record CustomConfiguration
{
    public string SenderId { get; init; } = string.Empty;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This class uses C#'s record type to define a simple immutable configuration object. It allows you to bind strongly typed settings from appsettings.json, making your code cleaner and less error-prone than using raw strings everywhere.&lt;/p&gt;

&lt;h2&gt;
  
  
  Configure Application Settings
&lt;/h2&gt;

&lt;p&gt;Create or update your appsettings.json file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft.AspNetCore": "Warning"
    }
  },
  "AllowedHosts": "*",
  "Vonage": {
    "Application.Id": "YOUR_APPLICATION_ID",
    "Application.Key": "-----BEGIN PRIVATE KEY YOUR_PRIVATE_KEY"
  },
  "CustomConfiguration": {
    "SenderId": "YOUR_SENDER_ID"
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Your appsettings.json stores runtime configuration such as credentials, sender ID, and log levels. Keeping sensitive settings like these in a config file allows for the separation of code and environment-specific values.&lt;/p&gt;

&lt;p&gt;Update these variables once you have completed the &lt;em&gt;“Create and Configure Your Vonage Application”&lt;/em&gt; section below.&lt;/p&gt;

&lt;h2&gt;
  
  
  Create the Send Message Endpoint
&lt;/h2&gt;

&lt;p&gt;Create a file named SendRcsMessageEndpoint.cs in the root of your project. This file defines the API logic for sending RCS messages. The SendRcsRequest record models the incoming JSON body, while the SendRcsMessageEndpoint handles the logic for sending the message via the Vonage Messages API. We separate the logic that builds the message payload into its own method, BuildRcsCustomRequest. This improves readability and makes the function easier to test or extend. For example, you could customize the suggestions dynamically in the future.&lt;/p&gt;

&lt;p&gt;For now, this endpoint handles sending RCS messages with 3 hardcoded suggested replies for appointment scheduling.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;using Microsoft.Extensions.Options;
using Vonage.Messages;
using Vonage.Messages.Rcs;

namespace RcsSuggestedReplies;

public record SendRcsRequest(string To);

public class SendRcsMessageEndpoint(IMessagesClient messagesClient, IOptions&amp;lt;CustomConfiguration&amp;gt; customConfiguration)
{
    public async Task&amp;lt;IResult&amp;gt; SendRcsMessage(SendRcsRequest request)
    {
        try
        {
            var response = await messagesClient.SendAsync(BuildRcsCustomRequest(request));
            Console.WriteLine($"Message sent: {response.MessageUuid}");
            return Results.Ok();
        }
        catch (Exception exception)
        {
            Console.WriteLine($"Error sending message: {exception.Message}");
            return Results.Problem(exception.Message);
        }
    }

    private RcsCustomRequest BuildRcsCustomRequest(SendRcsRequest sendRcsRequest)
    {
        return new RcsCustomRequest
        {
            From = customConfiguration.Value.SenderId,
            To = sendRcsRequest.To,
            Custom = new
            {
                ContentMessage = new
                {
                    Text = "What time works best for your appointment?",
                    Suggestions =
                        new[]
                        {
                            new
                            {
                                Reply = new
                                {
                                    Text = "9am",
                                    PostbackData = "time_9am"
                                }
                            },
                            new
                            {
                                Reply = new
                                {
                                    Text = "11am",
                                    PostbackData = "time_11am"
                                }
                            },
                            new
                            {
                                Reply = new
                                {
                                    Text = "2pm",
                                    PostbackData = "time_2pm"
                                }
                            }
                        }
                }
            }
        };
    }
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Create the Receive Message Endpoint
&lt;/h2&gt;

&lt;p&gt;Create another file called ReceiveRcsInboundEndpoint.cs in the root of your project.This class handles inbound webhook messages from Vonage. It verifies the request's authenticity using JWT validation and sends a confirmation reply when the user selects one of the suggested responses. JWT signature verification ensures you're not processing spoofed or malicious messages, and that incoming requests are indeed coming from Vonage.After parsing the user's reply, we send a friendly confirmation message. Keeping this logic in a separate method keeps the ReceiveRcsInbound function focused and easier to read.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;using Microsoft.Extensions.Options;
using Vonage;
using Vonage.Messages;
using Vonage.Messages.Rcs;
using Vonage.Messages.Webhooks;
using Vonage.Request;

namespace RcsSuggestedReplies;

public class ReceiveRcsInboundEndpoint(IMessagesClient messagesClient, IOptions&amp;lt;CustomConfiguration&amp;gt; customConfiguration, Credentials credentials)
{
    public async Task&amp;lt;IResult&amp;gt; ReceiveRcsInbound(HttpContext httpContext, MessageWebhookResponse messageWebhookResponse)
    {
        var token = httpContext.Request.Headers.Authorization.ToString().Split(' ')[1];
        if (!Jwt.VerifySignature(token, credentials.ApplicationKey))
        {
            return Results.Unauthorized();
        }

        if (messageWebhookResponse is {Channel: "rcs", MessageType: "reply"})
        {
            var userSelection = messageWebhookResponse.Reply?.ToString();
            Console.WriteLine($"User {messageWebhookResponse.From} select: {userSelection}");
            try
            {
                var response =
                    await messagesClient.SendAsync(BuildConfirmationMessage(messageWebhookResponse, userSelection));
                Console.WriteLine($"Confirmation sent: {response.MessageUuid}");
            }
            catch (Exception exception)
            {
                Console.WriteLine($"Error sending confirmation: {exception.Message}");
            }
        }

        return Results.Ok();
    }

    RcsTextRequest BuildConfirmationMessage(MessageWebhookResponse messageWebhookResponse1, string? s) =&amp;gt;
        new()
        {
            To = messageWebhookResponse1.From,
            From = customConfiguration.Value.SenderId,
            Text = $"{s} is a great choice!",
        };
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This endpoint handles incoming RCS messages, verifies their authenticity, and sends confirmation responses.&lt;/p&gt;

&lt;h2&gt;
  
  
  Configure the Program.cs File
&lt;/h2&gt;

&lt;p&gt;Update your Program.cs file to the following.&lt;/p&gt;

&lt;p&gt;Here, we configure dependency injection, which is a core part of ASP.NET Core's design. We register the Vonage client and our custom endpoints so they can be injected where needed, making the code more modular.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;using RcsSuggestedReplies;
using Vonage.Extensions;
using Vonage.Messages.Webhooks;

var builder = WebApplication.CreateBuilder(args);

// Add services to the container
builder.Services.AddControllers();
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();

// Register Vonage and application services
builder.Services.AddVonageClientScoped(builder.Configuration);
builder.Services.Configure&amp;lt;CustomConfiguration&amp;gt;(builder.Configuration.GetSection("CustomConfiguration"));
builder.Services.AddScoped&amp;lt;SendRcsMessageEndpoint&amp;gt;();
builder.Services.AddScoped&amp;lt;ReceiveRcsInboundEndpoint&amp;gt;();

var app = builder.Build();

// Configure the HTTP request pipeline
if (app.Environment.IsDevelopment())
{
    app.UseSwagger();
    app.UseSwaggerUI();
}

app.MapControllers();

// Define our API endpoints
app.MapPost("send-rcs",
    async (SendRcsMessageEndpoint endpoint, SendRcsRequest request) =&amp;gt; await endpoint.SendRcsMessage(request));
app.MapPost("inbound-rcs",
    async (ReceiveRcsInboundEndpoint endpoint, HttpContext context, MessageWebhookResponse inbound) =&amp;gt;
        await endpoint.ReceiveRcsInbound(context, inbound));

app.Run();
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  How to Expose Your Server with ngrok
&lt;/h2&gt;

&lt;p&gt;To receive webhooks from Vonage, your local server must be accessible over the internet. Use ngrok to expose your ASP.NET Core server, which will run on port 5000:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ngrok http 5000
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Note the HTTPS URL provided by ngrok (e.g., &lt;a href="https://your-ngrok-subdomain.ngrok.io" rel="noopener noreferrer"&gt;https://your-ngrok-subdomain.ngrok.io&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;You can read more about &lt;a href="https://developer.vonage.com/getting-started/tools/ngrok" rel="noopener noreferrer"&gt;testing with ngrok&lt;/a&gt; in our developer portal tools.&lt;/p&gt;

&lt;blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;Your application might be running on a different port. You can check in launchSettings.json to confirm.&lt;/p&gt;
&lt;/blockquote&gt;


&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Create and Configure Your Vonage Application
&lt;/h2&gt;

&lt;p&gt;Now that your ASP.NET App is ready, you’ll also need to create and set up your Vonage Application. First, create your app in the &lt;a href="https://dashboard.vonage.com/applications/new" rel="noopener noreferrer"&gt;Vonage Dashboard&lt;/a&gt;. Give the app a name and turn on the Messages capability. &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;To create an application, go to the &lt;a href="https://dashboard.vonage.com/applications/new" rel="noopener noreferrer"&gt;Create an Application&lt;/a&gt; page on the Vonage Dashboard, and define a Name for your Application. &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;If needed, click on "generate public and private key". A private key (.key file) will be generated. Download and store it securely. This key is needed for authentication when making API requests. Note: Private keys will not work unless the application is saved.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Choose the capabilities you need (e.g., Voice, Messages, RTC, etc.) and provide the required webhooks (e.g., event URLs, answer URLs, or inbound message URLs). These will be described in the tutorial.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;To save and deploy, click "Generate new application" to finalize the setup. Your application is now ready to use with Vonage APIs.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In your Vonage application settings:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Set the Inbound URL to &lt;a href="https://YOUR_NGROK_URL/inbound-rcs" rel="noopener noreferrer"&gt;https://YOUR_NGROK_URL/inbound-rcs&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Set the Status URL to &lt;a href="https://example.com/rcs-status" rel="noopener noreferrer"&gt;https://example.com/rcs-status&lt;/a&gt;. \
** Message statuses will be covered in a future article.&lt;/li&gt;
&lt;li&gt;Generate a public and private key by clicking the button. Ensure to move your private.key file to the project root directory (RcsSuggestedReplies).&lt;/li&gt;
&lt;li&gt;Save the changes.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Then link your RCS Agent by clicking the “Link external accounts” tab:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Feywu2f0wc9x81cmqrl8m.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Feywu2f0wc9x81cmqrl8m.png" alt="Dashboard view showing the Vonage-ASP-NET-RCS application linked to the Vonage RoR RCS external account, with voice and message capabilities enabled." width="800" height="397"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Dashboard view showing the Vonage-ASP-NET-RCS application linked to the Vonage RoR RCS external account, with voice and message capabilities enabled.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Update Your Vonage Credentials
&lt;/h2&gt;

&lt;p&gt;Replace the placeholder values in appsettings.json with your actual Vonage credentials:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;"Vonage": {
  "Application.Id": "YOUR_ACTUAL_APPLICATION_ID",
  "Application.Key": "YOUR_PRIVATE_KEY"
},
"CustomConfiguration": {
  "SenderId": "YOUR_ACTUAL_SENDER_ID"
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Run Your Application and Test
&lt;/h2&gt;

&lt;p&gt;Start your application:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;dotnet run
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Your RCS messaging application is now running! You can use a tool like Postman or cURL to send a POST request to your /send-rcs endpoint with the recipient's phone number:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;curl -X POST https://**YOUR_NGROK_URL***/send-rcs \
  -H "Content-Type: application/json" \
  -d '{
    "to": "**YOUR_RCS_TEST_NUMBER"
}'

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;On the recipient's RCS-enabled device, the message with suggested replies should appear.&lt;/p&gt;

&lt;p&gt;When the recipient selects a suggested reply, your /inbound-rcs endpoint will handle the response, and a confirmation message will be sent back.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fst9gbyxhho2ur3ewj6xt.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fst9gbyxhho2ur3ewj6xt.png" alt="RCS conversation where a user selects a time from suggested replies and receives a confirmation message, powered by the Vonage Messages API." width="576" height="1280"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;RCS conversation where a user selects a time from suggested replies and receives a confirmation message, powered by the Vonage Messages API.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;You’ve now built a working ASP.NET Core application that can send and receive RCS Suggested Replies using the Vonage Messages API. This simple UI improvement, letting users tap a response instead of typing, can dramatically enhance how users interact with your app.&lt;/p&gt;

&lt;p&gt;With webhook verification, structured response handling, and confirmation messages, this template gives you a solid foundation to expand on. You try adding RCS Cards, storing replies in a database, or dynamically generating suggested replies from user history&lt;/p&gt;

&lt;p&gt;If you run into any questions or have ideas for what you'd like to build next, come join the conversation in our &lt;a href="https://developer.vonage.com/community/slack" rel="noopener noreferrer"&gt;Vonage Community Slack&lt;/a&gt; or reach out on&lt;a href="https://twitter.com/VonageDev" rel="noopener noreferrer"&gt;X (formerly Twitter)&lt;/a&gt;. We’d love to see what you build!&lt;/p&gt;

</description>
      <category>aspnet</category>
      <category>rcs</category>
    </item>
    <item>
      <title>How to Send and Receive RCS Suggested Replies with Node.js</title>
      <dc:creator>Benjamin Aronov</dc:creator>
      <pubDate>Fri, 18 Jul 2025 13:59:35 +0000</pubDate>
      <link>https://dev.to/vonagedev/how-to-send-and-receive-rcs-suggested-replies-with-nodejs-1dhk</link>
      <guid>https://dev.to/vonagedev/how-to-send-and-receive-rcs-suggested-replies-with-nodejs-1dhk</guid>
      <description>&lt;p&gt;&lt;a href="https://developer.vonage.com/en/messages/concepts/rcs" rel="noopener noreferrer"&gt;Rich Communication Services (RCS)&lt;/a&gt; is transforming the way businesses engage with customers. As the next evolution of SMS, RCS offers a richer, more interactive experience with features like images, videos, file sharing, and suggested replies, natively inside a user's default messaging app. Check out all the cool &lt;a href="https://developer.vonage.com/en/messages/guides/rcs/rcs-agent-capabilities?source=messages" rel="noopener noreferrer"&gt;RCS capabilities&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;With RCS support rolling out around the world, for both Android and iOS, now is the perfect time to start exploring this technology. In this tutorial, you'll learn how to send RCS suggested replies using the Vonage Messages API in a &lt;a href="http://node.js/" rel="noopener noreferrer"&gt;Node.js&lt;/a&gt; application, helping you create more dynamic and engaging conversations with your users.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;TL;DR: Find the complete &lt;a href="https://github.com/Vonage-Community/tutorial-messages-node-rcs_suggested_replies/tree/main" rel="noopener noreferrer"&gt;working code on GitHub&lt;/a&gt;.&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;What Are RCS Suggested Replies?&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;RCS Suggested Replies enhance user interactions by providing predefined response options within messages. When a user selects a suggested reply, your application receives a structured response, allowing for streamlined and interactive conversations.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkz0k08yr45ecevkzxak0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkz0k08yr45ecevkzxak0.png" alt="RCS message sent using the Vonage Messages API, prompting the user to select a preferred appointment time with suggested reply buttons." width="576" height="1280"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Prerequisites&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Before you begin, ensure you have the following:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://nodejs.org/en/download" rel="noopener noreferrer"&gt;Node.js installed&lt;/a&gt; on your machine.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://ngrok.com/downloads/mac-os" rel="noopener noreferrer"&gt;ngrok installed&lt;/a&gt; for exposing your local server to the internet.&lt;/li&gt;
&lt;li&gt;&lt;a href="https://vonage.dev/4kKui68" rel="noopener noreferrer"&gt;A Vonage API account&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;A registered RCS Business Messaging (RBM) Agent.&lt;/li&gt;
&lt;li&gt;A phone with RCS capabilities for testing.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;How to Contact Your Vonage Account Manager&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;In order to send and receive RCS capabilities in your Vonage application, you will need to have a registered Rich Business Messaging (RBM) agent and a &lt;a href="https://api.support.vonage.com/hc/en-us/articles/16711304811932-How-can-I-check-if-RCS-Rich-Communication-Services-is-active-on-my-device" rel="noopener noreferrer"&gt;phone with RCS capabilities&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Currently, RCS Messaging through Vonage is only available for managed accounts. You will need to contact your account manager to request Developer Mode activation for your RBM agent. Developer Mode allows you to test RCS messaging to allow-listed numbers before completing the Agent Verification process and launching in production.&lt;/p&gt;

&lt;p&gt;Please &lt;a href="https://www.vonage.com/contact-us/" rel="noopener noreferrer"&gt;contact our sales team&lt;/a&gt; if you do not have a managed account. &lt;/p&gt;

&lt;p&gt;&lt;em&gt;&amp;gt;&amp;gt; Understand the &lt;a href="https://api.support.vonage.com/hc/en-us/articles/15546468078108-Understanding-RCS-and-RBM" rel="noopener noreferrer"&gt;difference between RCS and RBM&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;How to Set Up Your Node.js Project&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;This tutorial will assume you have a working understanding of JavaScript and Node, sticking to the commands required without too much deeper explanation.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Initialize the Project&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Create a new directory and initialize a Node.js project:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;mkdir rcs-suggested-replies-node
cd rcs-suggested-replies-node
npm init -y
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  &lt;strong&gt;Install Project Dependencies&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Install the necessary node packages with&lt;a href="https://www.npmjs.com/" rel="noopener noreferrer"&gt; Node Package Manager&lt;/a&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm install express dotenv @vonage/server-sdk
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;express&lt;/code&gt;: Creates the web server.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;dotenv&lt;/code&gt;: Loads environment variables securely.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;@vonage/server-sdk&lt;/code&gt;: The&lt;a href="https://github.com/Vonage/vonage-node-sdk" rel="noopener noreferrer"&gt; Vonage Node SDK&lt;/a&gt; for interacting with the Messages API&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Create Your Project Files&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Create the main application file and environment configuration file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;touch index.js .env
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  &lt;strong&gt;How to Configure Environment Variables&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;In the .env file, add your Vonage credentials and configuration:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;VONAGE_APPLICATION_ID=your_application_id
VONAGE_PRIVATE_KEY_PATH=./private.key
RCS_SENDER_ID=your_rbm_agent_id
PORT=3000
VONAGE_API_SIGNATURE_SECRET=your_api_secret
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;VONAGE_APPLICATION_ID&lt;/code&gt;: Your Vonage application ID.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;VONAGE_PRIVATE_KEY&lt;/code&gt;: Your private key file.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;RCS_SENDER_ID&lt;/code&gt;: Your RBM SenderID (the Name of the Brand). The SenderID requires special formatting, such as not having any spaces. Check with your account manager if you’re unsure.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;PORT&lt;/code&gt;: Port number for the Express server.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;VONAGE_API_SIGNATURE_SECRET&lt;/code&gt;=your_api_secret \&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You will obtain your Vonage Application ID and private.key file below, in the “How to Create and Configure Your Vonage Application” section.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;How to Send RCS Suggested Replies&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;In &lt;code&gt;index.js&lt;/code&gt;, set up the Express server and implement the functionality to send RCS messages with suggested replies.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Load Dependencies and Initialize the Vonage Client&lt;/strong&gt;
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const express = require('express');
const fs = require('fs');
const dotenv = require('dotenv');
const { Vonage } = require('@vonage/server-sdk');
const { verifySignature } = require('@vonage/jwt');

dotenv.config();

const app = express();
app.use(express.json());

const PORT = process.env.PORT || 3000;

const VONAGE_API_SIGNATURE_SECRET = process.env.VONAGE_API_SIGNATURE_SECRET;

const privateKey = fs.readFileSync(process.env.VONAGE_PRIVATE_KEY);

const vonage = new Vonage({
  applicationId: process.env.VONAGE_APPLICATION_ID,
  privateKey: privateKey
});

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  &lt;strong&gt;Define an Express Endpoint to Send Suggested Replies&lt;/strong&gt;
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;app.post('/send-rcs', async (req, res) =&amp;gt; {
  const toNumber = req.body.to;

  const message = {
    to: toNumber,
    from: process.env.RCS_SENDER_ID,
    channel: 'rcs',
    message_type: 'custom',
    custom: {
      contentMessage: {
        text: "What time works best for your appointment?",
        suggestions: [
          {
            reply: {
              text: "9am",
              postbackData: "time_9am"
            }
          },
          {
            reply: {
              text: "11am",
              postbackData: "time_11am"
            }
          },
          {
            reply: {
              text: "2pm",
              postbackData: "time_2pm"
            }
          }
        ]
      }
    }
  };

  try {
    const response = await vonage.messages.send(message);
    console.log('Message sent: ', response);
    res.status(200).json({ message: 'RCS message sent successfully.' });
  } catch (error) {
    console.error('Error sending message:', error);
    res.status(500).json({ error: 'Failed to send RCS message.' });
  }
});

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  &lt;strong&gt;How to Receive RCS Replies via Webhooks&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Set up an endpoint to handle incoming RCS replies.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;app.post('/inbound_rcs', async (req, res) =&amp;gt; {
  const token = request.headers.authorization.split(' ')[1];

  if (!verifySignature(token, VONAGE_API_SIGNATURE_SECRET)) {
    res.status(401).end();
    return;
  }

  const inboundMessage = req.body;

  if (inboundMessage.channel === 'rcs' &amp;amp;&amp;amp; inboundMessage.message_type === 'reply') {
    const userSelection = inboundMessage.reply.title;
    const userNumber = inboundMessage.from;

    console.log(`User ${userNumber} selected: ${userSelection}`);

    // Optionally, send a confirmation message back to the user
    const confirmationMessage = {
      to: userNumber,
      from: process.env.RCS_SENDER_ID,
      channel: 'rcs',
      message_type: 'text',
      text: `${userSelection} is a great choice!`
    };

    try {
      const response = await vonage.messages.send(confirmationMessage);
      console.log('Confirmation sent:', response);
    } catch (error) {
        console.error('Error sending confirmation:', error);
    };
  }

  res.status(200).end();
});
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Notice that all you do with the inbound message is log it to the console. Here is where you might want to save the message to your database or create some custom logic. For this example, you simply confirm to the user you've received their reply.&lt;/p&gt;

&lt;p&gt;Lastly, add your Express Server:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;app.listen(PORT, () =&amp;gt; {
  console.log(`Server is running on port ${PORT}`);
});

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;&amp;gt;&amp;gt; See the full &lt;a href="https://github.com/Vonage-Community/tutorial-messages-node-rcs_suggested_replies/blob/main/index.js" rel="noopener noreferrer"&gt;index.js file&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fk1qa9ic8qqae6bhqid8o.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fk1qa9ic8qqae6bhqid8o.png" alt="Terminal output showing a Node.js server sending an RCS message with suggested replies and logging the user's selected response." width="511" height="66"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;How to Expose Your Server with ngrok&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;To receive webhooks from Vonage, your local server must be accessible over the internet. Use ngrok to expose your server:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ngrok http 3000
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Note the HTTPS URL provided by ngrok (e.g., &lt;a href="https://your-ngrok-subdomain.ngrok.io" rel="noopener noreferrer"&gt;https://your-ngrok-subdomain.ngrok.io&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;You can read more about&lt;a href="https://developer.vonage.com/getting-started/tools/ngrok" rel="noopener noreferrer"&gt; testing with ngrok&lt;/a&gt; in our developer portal tools.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;How to Create and Configure Your Vonage Application&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Now that your Node App is ready, you’ll also need to create and set up your Vonage Application. First, create your app in the &lt;a href="https://dashboard.vonage.com/applications/new" rel="noopener noreferrer"&gt;Vonage Dashboard&lt;/a&gt;. Give the app a name and turn on the Messages capability. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnkgecvykwf0rwy6p6hov.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnkgecvykwf0rwy6p6hov.png" alt="A screenshot of the Vonage Developer dashboard showing the creation of a new application with authentication, privacy, and messaging capabilities settings." width="800" height="615"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In your Vonage application settings:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Set the &lt;strong&gt;Inbound URL&lt;/strong&gt; to &lt;a href="https://YOUR_NGROK_URL/inbound_rcs" rel="noopener noreferrer"&gt;https://YOUR_NGROK_URL/inbound_rcs&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Set the &lt;strong&gt;Status URL&lt;/strong&gt; to &lt;a href="https://example.com/rcs_status.**" rel="noopener noreferrer"&gt;https://example.com/rcs_status.**&lt;/a&gt; Message statuses will be covered in a future article.&lt;/li&gt;
&lt;li&gt;Generate a public and private key by clicking the button. Ensure to move your private.key file to the project root directory (rcs-suggested-replies-node).&lt;/li&gt;
&lt;li&gt;Save the changes.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Then link your RCS Agent by clicking the &lt;strong&gt;“Link external accounts”&lt;/strong&gt; tab:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpjqya61o8jayw7jkoijm.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpjqya61o8jayw7jkoijm.png" alt="Dashboard view showing the Vonage-Node-RCS application linked to the Vonage RoR RCS external account, with voice and message capabilities enabled." width="800" height="397"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;How to Test Your Node RCS Application&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Start your Express server:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;node index.js
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Use a tool like Postman or cURL to send a POST request to your /send-rcs endpoint with the recipient's phone number:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;curl -X POST https://**YOUR_NGROK_URL***/send-rcs \
  -H "Content-Type: application/json" \
  -d '{
    "to": "**YOUR_RCS_TEST_NUMBER"
}'
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;On the recipient's RCS-enabled device, the message with suggested replies should appear.&lt;/li&gt;
&lt;li&gt;When the recipient selects a suggested reply, your /inbound_rcs endpoint will handle the response, and a confirmation message will be sent back.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzja2g0knf1jwqvmtm3lz.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzja2g0knf1jwqvmtm3lz.png" alt="RCS conversation where a user selects a time from suggested replies and receives a confirmation message, powered by the Vonage Messages API" width="576" height="1280"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Conclusion&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Great job! You've successfully implemented sending and receiving RCS Suggested Replies using Node.js and the Vonage Messages API. But RCS offers so much more! You can try sending high-resolution images and videos, or RCS-specific&lt;a href="https://developer.vonage.com/en/messages/guides/rcs/rcs-custom-messages#rich-cards" rel="noopener noreferrer"&gt; Rich Cards&lt;/a&gt;. The Messages API also provides message statuses, which help us understand what’s happening with our RCS messages. In a future blog post, I’ll show how to track message statuses with webhooks. &lt;/p&gt;

&lt;p&gt;If you have any questions or suggestions for more Node or RCS content, join the conversation with us on the&lt;a href="https://developer.vonage.com/en/community/slack" rel="noopener noreferrer"&gt; Vonage Community Slack&lt;/a&gt; or reach out on &lt;a href="https://x.com/VonageDev" rel="noopener noreferrer"&gt;X, formerly known as Twitter&lt;/a&gt;. We’d love to hear what you build next!&lt;/p&gt;

</description>
      <category>rcs</category>
      <category>node</category>
    </item>
    <item>
      <title>Integrate Slack and SMS via Low-Code AI Studio</title>
      <dc:creator>Benjamin Aronov</dc:creator>
      <pubDate>Thu, 07 Nov 2024 14:58:55 +0000</pubDate>
      <link>https://dev.to/vonagedev/integrate-slack-and-sms-via-low-code-ai-studio-42l0</link>
      <guid>https://dev.to/vonagedev/integrate-slack-and-sms-via-low-code-ai-studio-42l0</guid>
      <description>&lt;h2&gt;
  
  
  &lt;strong&gt;Introduction&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Small and medium businesses often lack resources for full-fledged (and expensive) customer support solutions. However, with Vonage's AI Studio low-code platform, you can build a custom, cost-effective customer experience solution tailored to your needs.&lt;/p&gt;

&lt;p&gt;This tutorial will show you how to integrate SMS and Slack to create a powerful customer support system. By connecting SMS to Slack and Slack to SMS, you can enable your team to respond to customer inquiries directly from Slack.&lt;/p&gt;

&lt;p&gt;Using your existing staff, you can connect with customers over SMS, Voice (phone), or WhatsApp and respond directly from Slack. The best part? You're only charged for what you use! This powerful solution is particularly beneficial for startups already using Slack for team communications.&lt;/p&gt;

&lt;p&gt;Learn how to connect SMS and Slack for a live customer support failover. If your customers don't receive a satisfactory answer from the virtual agent, the conversation will seamlessly transfer to Slack, where any team member can assist!&lt;/p&gt;

&lt;p&gt;TL;DR: Find the refactored &lt;a href="https://github.com/Vonage-Community/tutorial-ai_studio-node-sms_to_slack?adobe_mc=MCMID%3D89448777371780096381139893056321793840%7CMCORGID%3DA8833BC75245AF9E0A490D4D%2540AdobeOrg%7CTS%3D1730990086" rel="noopener noreferrer"&gt;server code on Github&lt;/a&gt; to follow along with the AI Studio and Slack setup without worrying about JavaScript programming.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Integrating SMS with Slack for Customer Support Overview&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Initially, I aimed for a flow similar to the famous &lt;a href="https://slack.com/help/articles/204714258-Giphy-for-Slack?adobe_mc=MCMID%3D89448777371780096381139893056321793840%7CMCORGID%3DA8833BC75245AF9E0A490D4D%2540AdobeOrg%7CTS%3D1730990086" rel="noopener noreferrer"&gt;Giphy slash command&lt;/a&gt; for this SMS to Slack integration. However, custom slash commands are not allowed in threads by Slack (&lt;a href="https://stackoverflow.com/a/65612838/12698548?adobe_mc=MCMID%3D89448777371780096381139893056321793840%7CMCORGID%3DA8833BC75245AF9E0A490D4D%2540AdobeOrg%7CTS%3D1730990086" rel="noopener noreferrer"&gt;Giphy is a special case&lt;/a&gt;). Using a slash command in a regular channel response doesn't associate the response with a specific conversation. With simultaneous conversations, this approach would create a mess! To keep conversations threaded, we implemented the following workaround:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;A new message appears in the customer support channel with the &lt;code&gt;conversation_id&lt;/code&gt; from a new SMS conversation.&lt;/li&gt;
&lt;li&gt;A team member clicks a Slack Shortcut on the message, which tells our application to link that conversation to the current Slack thread.&lt;/li&gt;
&lt;li&gt;The team member uses the &lt;code&gt;/reply&lt;/code&gt; slash command followed by the &lt;code&gt;session_id&lt;/code&gt; and their response.&lt;/li&gt;
&lt;li&gt;Our application handles the reply, sends it to AI Studio, and adds it as a response in the thread.&lt;/li&gt;
&lt;li&gt;Our application also handles customer responses and adds them to the correct thread.&lt;/li&gt;
&lt;li&gt;The conversation continues until the agent uses the &lt;code&gt;/close_ticket&lt;/code&gt; slash command, terminating the session in AI Studio and adding a "conversation resolved" response in the Slack thread.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;By following this approach, you can seamlessly integrate SMS and Slack for customer support, allowing your team to manage conversations directly from Slack while maintaining proper threading and context.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Prerequisites&lt;/strong&gt;
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://dashboard.nexmo.com/your-numbers?adobe_mc=MCMID%3D89448777371780096381139893056321793840%7CMCORGID%3DA8833BC75245AF9E0A490D4D%2540AdobeOrg%7CTS%3D1730990086" rel="noopener noreferrer"&gt;Vonage Virtual Number&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Slack Account and permission to install apps in your workspace&lt;/li&gt;
&lt;li&gt;&lt;a href="https://nodejs.org/en/download?adobe_mc=MCMID%3D89448777371780096381139893056321793840%7CMCORGID%3DA8833BC75245AF9E0A490D4D%2540AdobeOrg%7CTS%3D1730990086" rel="noopener noreferrer"&gt;Node&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Vonage API Account&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;To complete this tutorial, you will need a &lt;a href="https://developer.vonage.com/sign-up?adobe_mc=MCMID%3D89448777371780096381139893056321793840%7CMCORGID%3DA8833BC75245AF9E0A490D4D%2540AdobeOrg%7CTS%3D1730990086" rel="noopener noreferrer"&gt;Vonage API account&lt;/a&gt;. If you don’t have one already, you can sign up today and start building with free credit. Once you have an account, you can find your API Key and API Secret at the top of the &lt;a href="https://dashboard.nexmo.com/?adobe_mc=MCMID%3D89448777371780096381139893056321793840%7CMCORGID%3DA8833BC75245AF9E0A490D4D%2540AdobeOrg%7CTS%3D1730990086" rel="noopener noreferrer"&gt;Vonage API Dashboard&lt;/a&gt;.&lt;/p&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;Ready to start building?&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;Experience seamless connectivity, real-time messaging, and crystal-clear voice and video calls—all at your fingertips.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://developer.vonage.com/sign-up?icid=tryitfree_api-adp-blog_nexmodashbdfreetrialsignup_blogbannerwidget&amp;amp;adobe_mc=MCMID%3D89448777371780096381139893056321793840%7CMCORGID%3DA8833BC75245AF9E0A490D4D%2540AdobeOrg%7CTS%3D1730990086" rel="noopener noreferrer"&gt;Sign up FREE&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Setup&lt;/strong&gt;
&lt;/h2&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;How to Setup a Node Application with Express&lt;/strong&gt;
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Create a new directory for your project and navigate into it using your terminal.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Initialize a new Node.js project and install dependencies&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Create Your Project Files&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;O﻿pen the project in your code editor of choice.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;In the .gitignore, we’ll need to add a single line so git doesn’t accidentally share our .env credentials: &lt;/p&gt;

&lt;p&gt;In our .env file we’ll need to add our secure values from both Slack and AI Studio. We’ll fill those out in the next steps. For now add:&lt;/p&gt;

&lt;p&gt;In the &lt;a href="https://github.com/Vonage-Community/tutorial-ai_studio-node-sms_to_slack/blob/main/server.js?adobe_mc=MCMID%3D89448777371780096381139893056321793840%7CMCORGID%3DA8833BC75245AF9E0A490D4D%2540AdobeOrg%7CTS%3D1730990086" rel="noopener noreferrer"&gt;server.js&lt;/a&gt; file, add the following boilerplate:&lt;/p&gt;

&lt;p&gt;In our boilerplate, we do 4 main things:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Import our dependencies.&lt;/li&gt;
&lt;li&gt;Express runs our server.&lt;/li&gt;
&lt;li&gt;Axios allows us to make HTTP requests. HTTP requests allow us to pass information between Slack &amp;amp; AI Studio.&lt;/li&gt;
&lt;li&gt;&lt;p&gt;bodyParser helps us parse or clean up the data we get back from Slack. &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Configure our app’s server, middleware, and env variables.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Create endpoints for each of our application's functionalities.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Start our server.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;How to Expose Our Application Through localtunnel&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Our application requires passing data several times between AI Studio and Slack. We’ll use &lt;a href="https://github.com/localtunnel/localtunnel?adobe_mc=MCMID%3D89448777371780096381139893056321793840%7CMCORGID%3DA8833BC75245AF9E0A490D4D%2540AdobeOrg%7CTS%3D1730990086" rel="noopener noreferrer"&gt;localtunnel&lt;/a&gt; to expose our localhost and create publicly accessible tunnels. In your terminal run the following command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npx localtunnel --port 3000
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will create a tunnel URL that should look something like this:&lt;/p&gt;

&lt;p&gt;The url that starts with &lt;code&gt;https&lt;/code&gt; and ends in &lt;code&gt;loca.lt&lt;/code&gt; is your tunnel url. In the remainder of the article anytime that &lt;code&gt;TUNNEL_URL&lt;/code&gt; is mentioned, this value should be used.&lt;/p&gt;

&lt;p&gt;Open a second tab in your terminal for later.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;How to Setup a Slack App&lt;/strong&gt;
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Log in to your Slack Workspace and &lt;a href="https://api.slack.com/apps?adobe_mc=MCMID%3D89448777371780096381139893056321793840%7CMCORGID%3DA8833BC75245AF9E0A490D4D%2540AdobeOrg%7CTS%3D1730990086" rel="noopener noreferrer"&gt;open your applications&lt;/a&gt;. &lt;/li&gt;
&lt;li&gt;Click on “Create a New App”. Select the “From Scratch” option.&lt;/li&gt;
&lt;li&gt;Give your app a name and select the Workspace where you want to use it.&lt;/li&gt;
&lt;li&gt;Click “Create App”.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Ta-da! You now have your first Slack App! There’s one last thing you’ll need to do. You’ll need to &lt;a href="https://api.slack.com/messaging/webhooks?adobe_mc=MCMID%3D89448777371780096381139893056321793840%7CMCORGID%3DA8833BC75245AF9E0A490D4D%2540AdobeOrg%7CTS%3D1730990086#enable_webhooks" rel="noopener noreferrer"&gt;enable Incoming Webhooks&lt;/a&gt;. Once you’ve toggled incoming webhooks on, scroll to the bottom of the page and click “Add New Webhook to Workspace”. You’ll be asked to select the desired channel and click “allow”. This will redirect you to the Incoming Webhooks page of your app, except now if you scroll to the bottom you will see a Webhook URL for your desired channel.&lt;/p&gt;

&lt;p&gt;Copy the URL and add it as the value for your SLACK_WEBHOOK_URL in your .env file. It should look something like this:&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;How to Create an Inbound SMS Chatbot&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;To create your agent, follow the instructions found in the AI Studio documentation &lt;a href="https://studio.docs.ai.vonage.com/ai-studio/create-a-new-agent?adobe_mc=MCMID%3D89448777371780096381139893056321793840%7CMCORGID%3DA8833BC75245AF9E0A490D4D%2540AdobeOrg%7CTS%3D1730990086" rel="noopener noreferrer"&gt;here&lt;/a&gt;. There are three important options for our agent, select:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;T﻿ype: SMS&lt;/li&gt;
&lt;li&gt;Template: S﻿tart From Scratch&lt;/li&gt;
&lt;li&gt;E﻿vent: Inbound&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The flow of our agent will be relatively simple.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Upon the user messaging the agent, we’ll use a &lt;a href="https://studio.docs.ai.vonage.com/sms/nodes/conversation/collect-input?adobe_mc=MCMID%3D89448777371780096381139893056321793840%7CMCORGID%3DA8833BC75245AF9E0A490D4D%2540AdobeOrg%7CTS%3D1730990086" rel="noopener noreferrer"&gt;Collect Input node&lt;/a&gt; to ask what they need help with. The answer will be stored in a parameter called inquiry.&lt;/li&gt;
&lt;li&gt;Then we’ll use a &lt;a href="https://studio.docs.ai.vonage.com/sms/nodes/conversation/conditions?adobe_mc=MCMID%3D89448777371780096381139893056321793840%7CMCORGID%3DA8833BC75245AF9E0A490D4D%2540AdobeOrg%7CTS%3D1730990086" rel="noopener noreferrer"&gt;conditional node&lt;/a&gt; to check if &lt;code&gt;inquiry&lt;/code&gt; is equal to “escalate”.&lt;/li&gt;
&lt;li&gt;If it is, we’ll then send the user a message saying “Please hold while we connect you to a live agent”. If the inquiry is something else, we’ll mimic all other possible flows by simply sending a message “Thanks for using our service!” (Send Thank You node).&lt;/li&gt;
&lt;li&gt;The Please Hold node will connect to a &lt;a href="https://studio.docs.ai.vonage.com/sms/nodes/actions/live-agent-routing?adobe_mc=MCMID%3D89448777371780096381139893056321793840%7CMCORGID%3DA8833BC75245AF9E0A490D4D%2540AdobeOrg%7CTS%3D1730990086" rel="noopener noreferrer"&gt;Live Agent Routing Node&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Finally, the &lt;em&gt;Live Agent Routing Node&lt;/em&gt; and &lt;em&gt;Send Thank You Node&lt;/em&gt; will connect to an &lt;a href="https://studio.docs.ai.vonage.com/sms/nodes/actions/end-conversation?adobe_mc=MCMID%3D89448777371780096381139893056321793840%7CMCORGID%3DA8833BC75245AF9E0A490D4D%2540AdobeOrg%7CTS%3D1730990086" rel="noopener noreferrer"&gt;End Conversation node&lt;/a&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fda81oj0ge4jgb6faf4zu.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fda81oj0ge4jgb6faf4zu.png" alt="Overview of AI Studio SMS Agent" width="800" height="160"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;How to Setup a Live Agent Routing Node&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;In the Live Agent Routing Node, we need to do 3 things:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Add your &lt;code&gt;'TUNNEL_URL/start'&lt;/code&gt; in the Start Connection EP field&lt;/li&gt;
&lt;li&gt;Add your &lt;code&gt;'TUNNEL_URL/inbound'&lt;/code&gt;  in the Inbound Transfer EP field&lt;/li&gt;
&lt;li&gt;Select inquiry in the Transfer Parameters &lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;And hit “Save and Exit”.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1co91fmmerpv82n83rmt.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1co91fmmerpv82n83rmt.png" alt="Example of Live Agent Routing Node in AI Studio" width="800" height="961"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Next, add your AI Studio API Key to your .env file. You can find the X-Vgai-Key on the top right of your AI Studio canvas. Click on the "user" icon, and then "Generate API Key". &lt;/p&gt;

&lt;p&gt;Copy the X-Vgai-Key and now add it as the value for your AI_STUDIO_KEY in your .env file. It should look something like this:&lt;/p&gt;

&lt;p&gt;Lastly, you’ll need to assign your Vonage Number to the agent. Follow the &lt;a href="https://studio.docs.ai.vonage.com/ai-studio/editor-mode-and-publish?adobe_mc=MCMID%3D89448777371780096381139893056321793840%7CMCORGID%3DA8833BC75245AF9E0A490D4D%2540AdobeOrg%7CTS%3D1730990086#how-to-publish-your-telephony-and-sms-agents" rel="noopener noreferrer"&gt;publishing instructions&lt;/a&gt; from the documentation.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;How to Initiate a Slack Conversation Using Incoming Webhooks&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;The first action we need to create is connecting AI Studio to Slack. We will use the Live Agent’s Start Connection Endpoint and Slack’s Incoming Webhooks. We’ve already configured these in the setup but now we need to add the logic to actually connect them.&lt;/p&gt;

&lt;p&gt;Our agent’s Start Connection Endpoint is configured to send a request to our &lt;code&gt;/start&lt;/code&gt; endpoint. There we will send 2 pieces of information to Slack: the sessionId and the transcription of our conversation thus far. We’ll package this up in the data object according to what Slack is expecting with a little formatting. We’ll use the axios library to send all our POST requests.&lt;/p&gt;

&lt;p&gt;This is how our &lt;code&gt;/start&lt;/code&gt; endpoint now looks:&lt;/p&gt;

&lt;p&gt;You’ll notice that we call the function &lt;code&gt;handleTranscription&lt;/code&gt;. This function formats our raw transcription into something nice for Slack. You can add this at the bottom of our file.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;How to Test Your SMS to Slack Connection&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;You can now test that your agent is connected to your Slack channel! In the second terminal tab that you opened before, run your application:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;node server.js
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Did your transcription appear in Slack? How cool!&lt;/p&gt;

&lt;p&gt;Because we haven’t implemented a way to end conversations in AI Studio yet, each time you test you’ll need to manually end the conversation. You can do so by sending a POST request to the &lt;a href="https://studio.docs.ai.vonage.com/whatsapp/nodes/actions/live-agent-routing?adobe_mc=MCMID%3D89448777371780096381139893056321793840%7CMCORGID%3DA8833BC75245AF9E0A490D4D%2540AdobeOrg%7CTS%3D1730990086#stop-connection-ep" rel="noopener noreferrer"&gt;Stop Connection EP&lt;/a&gt; with a tool like Postman. You can find your active sessions under the &lt;a href="https://studio.docs.ai.vonage.com/ai-studio/reports?adobe_mc=MCMID%3D89448777371780096381139893056321793840%7CMCORGID%3DA8833BC75245AF9E0A490D4D%2540AdobeOrg%7CTS%3D1730990086" rel="noopener noreferrer"&gt;Reports tab&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Additionally, each time you want to test a new change in your node application you’ll need to restart the server.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;How to Create a Slack Message Shortcut&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Now that we have initiated our conversation in Slack, you might think the next step would be to let our Slack teammates respond right? Well, we need to solve the problem first of somehow linking our Slack thread to our AI Studio conversation so we know how to organize our messages back and forth!&lt;/p&gt;

&lt;p&gt;We’ll do this by creating a &lt;a href="https://api.slack.com/interactivity/shortcuts?adobe_mc=MCMID%3D89448777371780096381139893056321793840%7CMCORGID%3DA8833BC75245AF9E0A490D4D%2540AdobeOrg%7CTS%3D1730990086#message" rel="noopener noreferrer"&gt;Slack Message Shortcut&lt;/a&gt;. This message shortcut will require our agent to “open a ticket” by just clicking a button on the new conversation. This will send a request to our application where we’ll store the conversation thread information in a new object in relation to the &lt;code&gt;conversation_id&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;How to Enable Slack App Interactivity&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;In order to create shortcuts, you’ll need to enable interactivity on your Slack app. You can see how to do so below. For the Request URL you’ll add your &lt;code&gt;TUNNEL_URL&lt;/code&gt; followed by &lt;code&gt;/slack/start&lt;/code&gt;. This will be the endpoint in our application where Slack will send a request whenever the shortcut is triggered.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F393kueizbo3yoi26uj8r.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F393kueizbo3yoi26uj8r.png" alt="Enable interactivity in your Slack App" width="800" height="549"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Next, click on “Create New Shortcut” and fill it in:&lt;/p&gt;

&lt;p&gt;Name: Start a ticket&lt;/p&gt;

&lt;p&gt;Short Description: Creates a conversation for a customer inquiry&lt;/p&gt;

&lt;p&gt;Callback ID: begin_response&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxvfn0l8mc03gyppsv1pj.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxvfn0l8mc03gyppsv1pj.png" alt="Create Slack Shortcut" width="800" height="699"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;How to Link Sessions with Slack Threads&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Now we’ll update our application to use the information we receive back from Slack and link it to our AI Studio sessions. First, we’ll create a global object called &lt;code&gt;SESSIONS&lt;/code&gt;. You can add this just above our endpoints:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const SESSIONS = {};
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Inside of our endpoints we’re going to do 4 things:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Handle the response we receive from Slack and extract &lt;code&gt;thread_ts&lt;/code&gt; (timestamp) and &lt;code&gt;session_id&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Create a new entry in &lt;code&gt;SESSIONS&lt;/code&gt; for the current session/thread&lt;/li&gt;
&lt;li&gt;Prepare the data to be sent to Slack, which includes formatting our initialization message for our Slack thread&lt;/li&gt;
&lt;li&gt;Sending our request to Slack to post the initialization message in the correct thread&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;In our endpoint, we rely on two new functions. You can add these at the bottom of your file with the other functions. The first called &lt;code&gt;extractSessionId&lt;/code&gt; which searches our payload from Slack for the current &lt;code&gt;sessionId&lt;/code&gt;:&lt;/p&gt;

&lt;p&gt;The second function &lt;code&gt;newSession&lt;/code&gt;, creates a new entry in our global &lt;code&gt;SESSIONS&lt;/code&gt; variable.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;How to Create a Slack Slash Command for Message Replies&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Now that our agent has initialized the conversation in our application, we want to let them actually respond to our customers. Let’s do that by creating our first slash command.&lt;/p&gt;

&lt;p&gt;In our Slack application dashboard open the Slash Commands tab. Then click “Create New Command”. &lt;/p&gt;

&lt;p&gt;Create the following command:&lt;/p&gt;

&lt;p&gt;Command: reply Request URL: TUNNEL_URL/slack/message Short Description: Reply to incoming inquiries Usage Hint: [session_id]&lt;/p&gt;

&lt;p&gt;And click “Save”.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F17zhw59s0rrdu0rusrcx.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F17zhw59s0rrdu0rusrcx.png" alt="Create Slack Slash Command" width="800" height="828"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now we need to update our &lt;code&gt;'/slack/message'&lt;/code&gt; endpoint to handle the data being sent from Slack. We need to do two things:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Grab the message and add it as a comment in the correct thread in Slack, along with some formatting&lt;/li&gt;
&lt;li&gt;Grab the message and send it to the correct session in AI Studio&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;We can do that with the following code:&lt;/p&gt;

&lt;p&gt;You’ll notice that we rely on one last function called &lt;code&gt;parseMessage&lt;/code&gt; to clean up our data from Slack. You can add it at the end of our file:&lt;/p&gt;

&lt;p&gt;You can now test sending message replies from Slack! How cool is it to receive it on the SMS side?!&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;How to Send SMS Replies to Slack&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;So we now almost have our full scenario working. But we’re missing one thing! We need to allow our users to send continuous messages into Slack to reply to our human agents. We can do this by updating our &lt;code&gt;/inbound&lt;/code&gt; endpoint.&lt;/p&gt;

&lt;p&gt;Here, we handle the data from AI Studio and pull out the message and &lt;code&gt;session_id&lt;/code&gt;. Using the &lt;code&gt;session_id&lt;/code&gt; we can lookup our &lt;code&gt;thread_ts&lt;/code&gt;. Once we have the &lt;code&gt;thread_ts&lt;/code&gt;, we can send off our message to the correct thread with a POST request to Slack.&lt;/p&gt;

&lt;p&gt;You can update your code to the following:&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;How to Create a Slack Slash Command to End a Conversation&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;You might think, “That’s it! I’m done!”. Well almost! Our Live Agent Node doesn’t know how long a conversation back and forth between AI Studio and some other interface might last. For that we must let AI Studio know when to end the conversation and exit the Live Agent Routing node.&lt;/p&gt;

&lt;p&gt;We’re going to create another slash command, similar to how we created &lt;code&gt;/reply&lt;/code&gt;. This time we will create a command for &lt;code&gt;/close_ticket&lt;/code&gt;. Close ticket will again accept the session_id to know which session to end. &lt;/p&gt;

&lt;p&gt;Create the following command:&lt;/p&gt;

&lt;p&gt;Command: /close_ticket Request URL: TUNNEL_URL/slack/end Short Description: Customer issue has been resolved Usage Hint: [session_id]&lt;/p&gt;

&lt;p&gt;And click “Save”. &lt;/p&gt;

&lt;p&gt;Inside of our &lt;code&gt;/slack/end&lt;/code&gt; endpoint we need to handle the request from Slack. We only need to do three things:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Grab the &lt;code&gt;session_id&lt;/code&gt; by using our &lt;code&gt;parseMessage&lt;/code&gt; function again&lt;/li&gt;
&lt;li&gt;Send a request to the Stop Connection endpoint in AI Studio to tell it to stop the conversation for the correct &lt;code&gt;session_id&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Update the human agent in Slack that the conversation has been ended by posting a message in the correct thread&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;To do so, update your &lt;code&gt;/slack/end&lt;/code&gt; code to look like this:&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Conclusion&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;And that’s a wrap! You've successfully implemented a seamless SMS to Slack and Slack to SMS integration for customer support using Vonage's AI Studio low-code platform. Restart your Node.js server by running node server.js in your terminal, and test the complete flow by sending messages back and forth between your phone's SMS and Slack. Isn't it amazing?&lt;/p&gt;

&lt;p&gt;To further enhance this application, consider leveraging Slack's robust Web API, which enables interactivity based on emoji reactions. Additionally, you could incorporate AI Studio's WhatsApp agents, providing customers with an additional communication channel.&lt;/p&gt;

&lt;p&gt;Are you using other low-code or no-code solutions for customer engagement? Join the &lt;a href="https://developer.vonage.com/en/community/slack" rel="noopener noreferrer"&gt;Vonage Developer Community Slack&lt;/a&gt; or follow us on &lt;a href="https://twitter.com/VonageDev?adobe_mc=MCMID%3D89448777371780096381139893056321793840%7CMCORGID%3DA8833BC75245AF9E0A490D4D%2540AdobeOrg%7CTS%3D1730990086" rel="noopener noreferrer"&gt;X, formerly known as Twitter&lt;/a&gt; to share your exciting projects and insights!&lt;/p&gt;

&lt;p&gt;Integrating SMS and Slack for customer support is just one example of how low-code platforms like AI Studio can streamline business processes and improve customer experiences. Explore more possibilities and stay updated with the latest developments in the low-code and no-code spaces.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Additional Resources&lt;/strong&gt;
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://developer.vonage.com/en/blog/boosting-chatbot-roi-human-agent-request-deflection" rel="noopener noreferrer"&gt;Boosting Chatbot ROI: Human Agent Request Deflection&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://developer.vonage.com/en/blog/building-a-resilient-voice-agent-a-guide-to-failover-systems" rel="noopener noreferrer"&gt;Building a Resilient Voice Agent: A Guide to Failover Systems&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://developer.vonage.com/en/blog/how-to-build-an-intent-classification-hierarchy" rel="noopener noreferrer"&gt;How to Build an Intent Classification Hierarchy&lt;/a&gt; &lt;/li&gt;
&lt;li&gt;&lt;a href="https://developer.vonage.com/en/blog/the-new-frontier-for-freelance-opportunities-conversational-ai-agents" rel="noopener noreferrer"&gt;The New Frontier for Freelance Opportunities: Conversational AI Agents&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
    </item>
    <item>
      <title>How to Build an Intent Classification Hierarchy</title>
      <dc:creator>Benjamin Aronov</dc:creator>
      <pubDate>Thu, 04 Apr 2024 12:43:30 +0000</pubDate>
      <link>https://dev.to/vonagedev/how-to-build-an-intent-classification-hierarchy-d4</link>
      <guid>https://dev.to/vonagedev/how-to-build-an-intent-classification-hierarchy-d4</guid>
      <description>&lt;p&gt;Conversational AI agents are a great way to save your company its most important resource: employee time! Agents are like interactive FAQs except much more flexible. When built correctly, they can drastically help improve your customer experience. But the question is, how do you build them correctly?&lt;/p&gt;

&lt;p&gt;Thankfully, the team at AI Studio has done the hard work for you! We’ve been able to improve performance on large AI agents (50+ Intents) considerably. These techniques have resulted in some agents seeing a 55% increase in successful calls and an 83% reduction in requests for human agents.&lt;/p&gt;

&lt;p&gt;This post will cover how to build a hierarchy in &lt;a href="https://studio.docs.ai.vonage.com/properties-1/intents" rel="noopener noreferrer"&gt;Intent Classification&lt;/a&gt; to improve your agents’ performance in routing users to the correct intent. Topics will include general NLU best practices, examples of building a hierarchical classification, and tips on designing your Conversational AI agent in AI Studio. &lt;/p&gt;

&lt;h2&gt;
  
  
  NLU Best Practices
&lt;/h2&gt;

&lt;p&gt;What is NLU? &lt;a href="https://studio.docs.ai.vonage.com/properties-1/intents/the-meaning-of-nlu" rel="noopener noreferrer"&gt;Natural Language Understanding&lt;/a&gt;, or NLU, is the process that allows a computer to understand the intention of a piece of text. NLU is how a computer understands what a user means when they speak with the computer. The software does this through Intent Classification and Entity Extraction.&lt;/p&gt;

&lt;h3&gt;
  
  
  Intent Overlap &amp;amp; Ambiguity
&lt;/h3&gt;

&lt;p&gt;Intent Classification seems pretty straightforward, right? The Agent just breaks down the user input and maps it to your defined intents. But in practice, it is very easy to confuse the model.&lt;/p&gt;

&lt;p&gt;Consider the scenario of an agent designed for a financial institution such as a bank. Within this context, customers may initiate various interactions related to loans, such as making a Loan Request, checking Loan Status, or seeking general Loan Information.&lt;/p&gt;

&lt;p&gt;The challenge arises when the terms like "loan" or "mortgage" are employed in diverse contexts, such as in phrases like "talk with mortgage representative" or "get mortgage offer." This widespread use of the same keywords within a single classification node can potentially result in misclassification by the model.&lt;/p&gt;

&lt;p&gt;To mitigate this issue, we propose implementing a hierarchical structure with two layers, essentially comprising two classification nodes. The first layer would focus on classifying the core concept, such as "loan" or "mortgage," while the second layer would specialize in discerning the specific action or intent associated with the user's query (request, status, representative, etc). This hierarchical approach aims to enhance the model's precision and reduce the likelihood of misclassifying similar but contextually distinct intents.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Felp6j576nhcsr9yo7j5k.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Felp6j576nhcsr9yo7j5k.jpeg" alt="Intent Overlap &amp;amp; Ambiguity" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Training Set Consistency
&lt;/h3&gt;

&lt;p&gt;Additionally, because the &lt;a href="https://studio.docs.ai.vonage.com/properties-1/intents/generate-training-data" rel="noopener noreferrer"&gt;training sets&lt;/a&gt; that make up each intent will have very similar expressions we need to be extremely consistent. Adding ambiguous words in your training sets can cause unexpected behavior if applied inconsistently.&lt;/p&gt;

&lt;p&gt;For instance imagine your (Loan) Request intent contains the expression, “I want to ask for a loan”. Now a user asks your agent, “I want to ask for a loan status”, which should route them to (Loan) Status. Unless your training set for Status includes an expression with the phrase, “I want to” and “loan”, there is a very high probability that it will route incorrectly to Request. To solve this problem, your training data needs to be extremely consistent with ambiguous filler/supporting words. So either add it everywhere or remove it everywhere. Often it’s easier to omit.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F839kawr6revp6b4a25ml.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F839kawr6revp6b4a25ml.png" alt="Training Set Consistency" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Training Set Case Study: Sales vs. Customer Support
&lt;/h3&gt;

&lt;p&gt;Now imagine that we wanted to add two new intents to our Bank agent: Call Back and Sales. Call Back is for users wanting a customer support representative to call them back and Sales is for someone from the Sales department to call them.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fc3sp3wxuejylknfybmwg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fc3sp3wxuejylknfybmwg.png" alt="Inconsistent Training Example" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We expect all the following to be classified as “sales”:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;I want to speak with a sales representative &lt;/li&gt;
&lt;li&gt;want to speak with a sales representative&lt;/li&gt;
&lt;li&gt;with a sales representative&lt;/li&gt;
&lt;li&gt;sales representative&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;However, as we see in the diagram, the first two user inputs that have “want to speak with” end up being classified as “call back”. That’s because the words “speak with” are more similar to call back than sales. &lt;/p&gt;

&lt;p&gt;The solution is to add training data to our “sales” intent that contains “want to speak with”. It should be in the same proportion as the training data for similar training data in the “call back” training set.&lt;/p&gt;

&lt;p&gt;In a more complicated agent, these two intents may look very similar compared to other intents. We’ll see shortly how hierarchical classification will help our agent get to the point where it can make this more granular distinction.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is Hierarchical Classification?
&lt;/h2&gt;

&lt;p&gt;Sanitizing our Intents to avoid Intent Overlap and ensuring our Training Sets are consistent are a good start to improving Classification but once we start to have agents with lots of intents, it won’t be enough as the world is full of inevitable overlap. And those pesky users never behave as we want them to!&lt;/p&gt;

&lt;p&gt;Hierarchical Classification helps with these large-scale agents as it creates levels of classification to only focus the classification on one variable or topic at a time. By classifying in stages, the agent is most effective by categorizing intents into groups by their biggest differentiators. Grouping by greatest differentiation helps to eliminate overlap and ambiguity.&lt;/p&gt;

&lt;h2&gt;
  
  
  How to Group Intents in Hierarchical Classification
&lt;/h2&gt;

&lt;p&gt;Breaking down our classification into stages may seem straightforward, but quickly we see that there are different ways to group intents. We can either group them by their nouns or their verbs.&lt;/p&gt;

&lt;p&gt;Nouns are the items in your agent that a user may inquire about. Think about these as the direct objects of their request. Most often these are the products or services that your business offers. Examples of nouns would be “late check-out”, “birthday package”, and “1:1 consultation”.&lt;/p&gt;

&lt;p&gt;Verbs on the other hand are the the action someone wants to take on the noun. Consider the differences between the customer requests of 'BOOK a reservation', 'CANCEL a reservation', and 'CHANGE a reservation'.&lt;/p&gt;

&lt;h3&gt;
  
  
  Case Study: Grouping by Noun vs. Verbs
&lt;/h3&gt;

&lt;p&gt;Imagine that we expand our Bank scenario. Instead of just offering Loans, we also want to start offering Insurance. For Insurance, we also give the user the option to Request Insurance, Check on Insurance Status, and General Insurance Information. Our classifier now needs to compare the user input across lots of training data, which inherently will begin to overlap.&lt;/p&gt;

&lt;p&gt;This is exactly the scenario where hierarchy will improve our agent's performance. The first step is to group our topics. In this example, we have a few ways we can group the topics. We could either group them by product or by services.&lt;/p&gt;

&lt;p&gt;This diagram illustrates how we might group by verbs:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjfeodntpqe4km87exf8w.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjfeodntpqe4km87exf8w.jpeg" alt="Hierarchy Grouped By Verbs" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;While the groups make logical sense and we might pass the initial classifier with high results, what will happen in the second stage of classification? As we saw earlier, the classifier will have issues with the second round as high ambiguity is likely when comparing user input-looking things like Loan Instruction and Insurance Instruction. In these instances, there will be high overlap in the Training Sets and we’ll need to be very meticulous to keep the data consistent.&lt;/p&gt;

&lt;p&gt;Now, let’s try to see what happens when we group the Intents by nouns:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fksiyjmdbc5lpdlrxzjhj.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fksiyjmdbc5lpdlrxzjhj.jpeg" alt="Hierarchy Grouped By Nouns" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;What we see here is that not only do we remove a layer of complexity in immediately differentiating between Support and Sales, but more importantly we create groupings in the 2nd round that are much easier to classify. In each group of Loans and Insurance, each Intent can be stripped down to have very little overlap as we did earlier.&lt;/p&gt;

&lt;h2&gt;
  
  
  How to Create Hierarchical Classification
&lt;/h2&gt;

&lt;p&gt;Now that you understand the theory, let’s jump in with a practical guide.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 1: Gather or Create an Idealized Training Set
&lt;/h3&gt;

&lt;p&gt;If you have real-world data, that’s awesome you’re ahead of the game! Jump to number step 2, you can focus on the core training data and leave out any outliers for now.&lt;/p&gt;

&lt;p&gt;Otherwise, imagine that your users speak without using filler words or unnecessary extra words. Now write out all the user expressions you can think of. This is your idealized training set.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Imagine all the possible synonyms for your products/offerings.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Example: room/reservation/booking/stay&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;h3&gt;
  
  
  Step 2: Organize your Idealized Data Into Broad Groups
&lt;/h3&gt;

&lt;p&gt;Just as we organized the Bank topics into broad groups around nouns, you too should group your topics into broad Noun/Noun Phrase categories. At this point, you can start to identify the supporting verbs/verbs.&lt;/p&gt;

&lt;p&gt;In the real world users behave kind of like cavemen. Very often they reply with single words, much more often nouns than verbs. Grouping around nouns will lead to much higher performance.&lt;/p&gt;

&lt;p&gt;Where is the greatest potential for high ambiguity? For the highly ambiguous cases, add training data to standardize and create uniform phrases across the different groups. Just as you saw with the example of Sales vs Call Back Intents above, normalize the training data for groups with high ambiguity.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 3: Handle the Outliers
&lt;/h3&gt;

&lt;p&gt;After you’ve solved most use cases, you may find that you still have some intents that don’t fit in your broad-scope topics. Where should you account for these?&lt;/p&gt;

&lt;p&gt;You should add these intents at the point where they have the greatest ability to be negated by your model. Consider you have an agent for a Nutritionist and one of your intents is to Healthy Foods. However, a user asks, “Can I order a pizza?”. The model will most likely push the user to the “Healthy Foods” intent, even though a pizza shouldn’t go there. See the diagram:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4aod6vcqihd2ilpmdxmq.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4aod6vcqihd2ilpmdxmq.png" alt="Classification Hierarchy: Nutritionist Example" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Our solution is to create a new “negative” intent to capture the default behavior and route it accordingly. So we create an “Unhealthy Foods” intent that will capture these “negative” cases and direct it to the right flow. Our updated classification:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F687e5vfnt7qjuqoubsma.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F687e5vfnt7qjuqoubsma.png" alt="Classification Negative Intent Example" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Design Considerations in AI Studio
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Using Subflows in AI Studio
&lt;/h3&gt;

&lt;p&gt;AI Studio makes it easy to get started quickly and start building out agents with drag-and-drop nodes. However, as your agent starts to scale, it becomes very difficult to keep track of dozens or hundreds of nodes. Not only will agent organization become unmanageable but the Studio will start to become slow in the browser window, loading a large number of nodes.&lt;/p&gt;

&lt;p&gt;It’s best to get ahead of these issues by planning out your agent ahead of time and using the &lt;a href="https://studio.docs.ai.vonage.com/voice/nodes/flow-control/flows" rel="noopener noreferrer"&gt;Subflow feature&lt;/a&gt;. For best practices, each intent should have its own subflow. Each of these subflows will join at a Topic Group Level. Each of these Groups will then flow up to a main level. Creating a Hierarchical Classification before you start working makes organizing your subflows a breeze and helps prevent creating future technical debt.&lt;/p&gt;

&lt;h3&gt;
  
  
  Repeating Intents Across Multiple Flows
&lt;/h3&gt;

&lt;p&gt;After you’ve created the first version of your agent, you might find that your hierarchy has “leakage”. A small number of users may accidentally end up in the wrong flow. Instead of breaking your head to re-engineer the perfect hierarchy model, just “Go with the Flow!”. &lt;/p&gt;

&lt;p&gt;For example, consider this example where a hotel had a premium restaurant package called the “Eagles Nest”. Users will ask for “premium offering for the Hotel” or use other terminology because they don’t know it’s called “Eagles Nest”. There was a top-level classifier for the Hotel and a top-level classifier for “Eagles Nest”. There was so much training data for Hotel, that user inquiries often ended up in Hotel instead of Eagles Nest. So instead of redesigning the whole agent over, we can add a subflow in Hotel, which then leads back to Eagles Nest. In the final agent, this subflow may live in 3 or 4 different places because it all depends on how someone may ask for it.&lt;/p&gt;

&lt;h3&gt;
  
  
  Handling for Broad Queries
&lt;/h3&gt;

&lt;p&gt;In addition to users giving way too simplistic inputs, often they will say the subject they have a question about rather than a detailed question. A great way to handle this and improve user experience is to create a “catch” intent at your highest level of classification.&lt;/p&gt;

&lt;p&gt;For example instead of saying, “I want to make a booking with a Dr. Smith for surgery.”, they will say, “Booking question” or “Surgery question”. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhozawmsjc7ejhs6p7kai.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhozawmsjc7ejhs6p7kai.png" alt="Question Deflection Example" width="800" height="527"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We found that adding this simple catch-all for inputs about questions helped create confidence in the users that the virtual agent would be able to help them. &lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Now that you’ve seen the power of Classification Hierarchy in Conversational AI agents, you can go and make your agents much better at answering your users! Remember these steps and you’ll be the hero at your company:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Review training data&lt;/li&gt;
&lt;li&gt;Organize the data, identify where there’s potential for high ambiguity&lt;/li&gt;
&lt;li&gt;Create a hierarchical classification&lt;/li&gt;
&lt;li&gt;Build out agent&lt;/li&gt;
&lt;li&gt;Test, test, test&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;If you enjoyed this article let us know on Vonage Developer &lt;a href="https://developer.vonage.com/en/community/slack" rel="noopener noreferrer"&gt;Community Slack&lt;/a&gt;. This post was inspired by a question from a community member there! You can also follow us on &lt;a href="https://twitter.com/VonageDev" rel="noopener noreferrer"&gt;X, formerly known as Twitter&lt;/a&gt;, for the latest Vonage API news. &lt;/p&gt;

&lt;h2&gt;
  
  
  Additional Resources
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://developer.vonage.com/en/blog/how-to-create-a-conversational-ai-mockup" rel="noopener noreferrer"&gt;How to Create a Conversational AI Mockup&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://developer.vonage.com/en/blog/build-a-farewell-app-using-vonage-ai-studio-and-notion-as-a-database" rel="noopener noreferrer"&gt;Build a Farewell App Using Vonage AI Studio and Notion as a Database&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>nocode</category>
      <category>lowcode</category>
    </item>
    <item>
      <title>Anything-to-SMS with IFTTT and Vonage</title>
      <dc:creator>Benjamin Aronov</dc:creator>
      <pubDate>Thu, 22 Feb 2024 11:23:01 +0000</pubDate>
      <link>https://dev.to/vonagedev/anything-to-sms-with-ifttt-and-vonage-3bb5</link>
      <guid>https://dev.to/vonagedev/anything-to-sms-with-ifttt-and-vonage-3bb5</guid>
      <description>&lt;p&gt;I live in Tel Aviv, a beach city with 300 sunny days a year. The weather is so stable that I never check the weather. But whenever it does rain, it pours! And I end up drenched and cold. If only I somehow had a reminder to tell me it’s going to rain.&lt;/p&gt;

&lt;p&gt;Have you heard of &lt;a href="https://ifttt.com" rel="noopener noreferrer"&gt;IFTTT&lt;/a&gt;? IFTTT stands for "If This Then That." It's a web-based service that allows you to create simple conditional statements, called applets, to automate various tasks and actions across different web services and devices. And all with no code! The basic idea is to connect different apps and devices to create automated workflows based on triggers and actions.&lt;/p&gt;

&lt;p&gt;No-code/low-code platforms are super-useful for a ton of different things. What's even better is when you combine them to solve problems!&lt;/p&gt;

&lt;p&gt;So in this post, I’ll show you how I built an applet in IFTTT to help me know when it’s going to rain and take an umbrella with me. The applet will send me an SMS warning using Vonage’s no code/low code &lt;a href="https://studio.docs.ai.vonage.com/" rel="noopener noreferrer"&gt;AI Studio&lt;/a&gt; platform. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F29mmdv9csd350gtoq5ba.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F29mmdv9csd350gtoq5ba.png" alt="IFTTT explore page with a wide choice of applets integrating various services" width="800" height="403"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Prerequisites:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;a href="https://ui.idp.vonage.com/ui/auth/registration" rel="noopener noreferrer"&gt;Vonage Developer Account&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;IFTTT Account - &lt;a href="https://ifttt.com/join" rel="noopener noreferrer"&gt;Sign up for a IFTTT free account&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="https://developer.vonage.com/en/numbers/guides/number-management#rent-a-virtual-number" rel="noopener noreferrer"&gt;Vonage Virtual Number&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Creating an IFTTT Applet
&lt;/h2&gt;

&lt;p&gt;Navigate to the Create Applet page. Search for and select Weather Underground. You’ll then see a list of all the available Weather Underground Triggers.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fj4xt1u76yef4evq4kg7x.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fj4xt1u76yef4evq4kg7x.png" alt="Choose a Weather Underground Trigger" width="800" height="522"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You’ll want to select “Tomorrow’s forecast calls for”. The first half of our Applet is done! You should be redirected to a page that looks like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Foogi6hjhwtjkvj35el2s.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Foogi6hjhwtjkvj35el2s.png" alt="Applet If This Than That Page" width="800" height="519"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now we need to somehow tell IFTTT to trigger an SMS. We’re going to do this with Vonage’s AI Studio.&lt;/p&gt;

&lt;h2&gt;
  
  
  Creating an Outbound SMS Agent
&lt;/h2&gt;

&lt;p&gt;Let’s create our AI Studio Agent now. Navigate to the &lt;a href="https://studio.ai.vonage.com/agents" rel="noopener noreferrer"&gt;AI Studio Dashboard&lt;/a&gt;. Follow the instructions found in the AI Studio documentation &lt;a href="https://studio.docs.ai.vonage.com/ai-studio/create-a-new-agent" rel="noopener noreferrer"&gt;here&lt;/a&gt;. There are three important options for our agent, select:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Type:&lt;/strong&gt; SMS&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Template:&lt;/strong&gt; Start From Scratch&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Event:&lt;/strong&gt; Outbound&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Our agent will be extremely basic, sending a single SMS telling us that tomorrow will be rain. It will also send a link to the full weather forecast and provide the expected high and low temperatures.&lt;/p&gt;

&lt;p&gt;For this we need to &lt;a href="https://studio.docs.ai.vonage.com/properties-1/parameters#create-a-parameter" rel="noopener noreferrer"&gt;create 3 parameters&lt;/a&gt; in AI Studio which will hold those values we get from IFTTT. The parameters will be of &lt;code&gt;@sys.any&lt;/code&gt; Entity type and called, &lt;code&gt;ForecastUrl&lt;/code&gt;, &lt;code&gt;HighTempCelsius&lt;/code&gt;, and &lt;code&gt;LowTempCelsius&lt;/code&gt;. See below:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8gro8z7i5ehzxvfnrdey.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8gro8z7i5ehzxvfnrdey.png" alt="AI Studio Dashboard Parameter Creation" width="800" height="372"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now we can add our single Send Message node and our alert message which uses our 3 parameters.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fixlhatcix5uonmdtp1bx.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fixlhatcix5uonmdtp1bx.png" alt="AI Studio Send Message" width="800" height="375"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The last step is to &lt;a href="https://studio.docs.ai.vonage.com/ai-studio/editor-mode-and-publish#how-to-publish-your-telephony-and-sms-agents" rel="noopener noreferrer"&gt;publish our agent&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Connecting IFTTT with Webhooks
&lt;/h2&gt;

&lt;p&gt;Now that our agent is setup all we need to do is finish our Applet in IFTTT and connect it to the agent. We will do this with the Webhook service. So in IFTTT continue and search for “Webhook”.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnpmt93rjg3axgf5ylnrh.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnpmt93rjg3axgf5ylnrh.png" alt="Choose IFTTT Webhook Service" width="800" height="422"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Select “Make a web request” and continue until you see the following page:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsitn6kfy36iauphc7hdc.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsitn6kfy36iauphc7hdc.png" alt="Make a web request" width="530" height="1150"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;For URL, you will need to paste one of the following. The endpoint depends on the region you selected for your agent.&lt;/p&gt;

&lt;p&gt;For EU agents --&amp;gt; &lt;a href="https://studio-api-eu.ai.vonage.com/messaging/conversation" rel="noopener noreferrer"&gt;https://studio-api-eu.ai.vonage.com/messaging/conversation&lt;/a&gt;&lt;br&gt;
For US agents --&amp;gt; &lt;a href="https://studio-api-us.ai.vonage.com/messaging/conversation" rel="noopener noreferrer"&gt;https://studio-api-us.ai.vonage.com/messaging/conversation&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Set &lt;em&gt;Method&lt;/em&gt; to &lt;code&gt;POST&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Set &lt;em&gt;Content Type&lt;/em&gt; to &lt;code&gt;application/json&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;For &lt;em&gt;Additional Headers&lt;/em&gt; you’ll need to add your &lt;code&gt;X-Vgai-Key&lt;/code&gt;. You can find the &lt;code&gt;X-Vgai-Key&lt;/code&gt; on the top right of your AI Studio dashboard. Click on the &lt;em&gt;user&lt;/em&gt; icon, and then &lt;code&gt;Generate API Key&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Example:&lt;br&gt;
X-Vgai-Key: YOUR_X_VGAI_KEY&lt;/p&gt;

&lt;p&gt;For “Body” we will add the following code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
  "to": "YOUR_PHONE_NUMBER",
  "agent_id": "YOUR_VONAGE_AGENT_ID",
  "channel": "sms",
  "session_parameters": [

    {
      "name": ForecastUrl,
      "value": {{ForecastUrl}}
    },

    {
      "name": "HighTempCelsius",
      "value": {{HighTempCelsius}}
    },

    {
      "name": "LowTempCelsius",
      "value": {{LowTempCelsius}}
    }
  ]
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You’ll need to replace YOUR_PHONE_NUMBER with the phone to receive alerts. For example, “15551234567”. Similarly replace YOUR_VONAGE_AGENT_ID with your agent id, which can be found under Agent Details found in the side panel of your Agent in AI Studio.&lt;/p&gt;

&lt;p&gt;Lastly, click “Create Action” and you’re done!&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Did you know about IFTTT before this article? What are you using it for? What other nocode or lowcode tools are you using? I’m really interested to hear any feedback you have for this article.&lt;/p&gt;

&lt;p&gt;Join me on Vonage &lt;a href="https://developer.vonage.com/en/community/slack" rel="noopener noreferrer"&gt;Developer Community Slack&lt;/a&gt; or &lt;a href="https://twitter.com/VonageDev" rel="noopener noreferrer"&gt;X&lt;/a&gt;, formerly known as Twitter and let me know what exciting things you are building!&lt;/p&gt;

&lt;h2&gt;
  
  
  Additional Resources
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://developer.vonage.com/en/blog/low-code-and-no-code-what-option-is-best-for-you" rel="noopener noreferrer"&gt;Low-Code and No-Code: What Option Is Best for You?&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://developer.vonage.com/en/blog/if-you-can-point-and-click-then-you-can-make-a-conversational-ai" rel="noopener noreferrer"&gt;If You Can Point and Click Then You Can Make a Conversational AI&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://developer.vonage.com/en/blog/crash-course-create-virtual-agents-for-whatsapp-with-vonage-ai-studio" rel="noopener noreferrer"&gt;Crash Course: Create Virtual Agents for WhatsApp with Vonage AI Studio&lt;/a&gt;&lt;/p&gt;

</description>
      <category>lowcode</category>
      <category>nocode</category>
      <category>ifttt</category>
      <category>vonage</category>
    </item>
  </channel>
</rss>
