<?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: Amanda Cavallaro</title>
    <description>The latest articles on DEV Community by Amanda Cavallaro (@chibichibibr).</description>
    <link>https://dev.to/chibichibibr</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%2F364684%2Fb694a3c4-f859-400a-ae59-ad314bc2c13b.jpg</url>
      <title>DEV Community: Amanda Cavallaro</title>
      <link>https://dev.to/chibichibibr</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/chibichibibr"/>
    <language>en</language>
    <item>
      <title>Build a Storytelling Service With RCS Rich Cards and Gemini</title>
      <dc:creator>Amanda Cavallaro</dc:creator>
      <pubDate>Tue, 19 Aug 2025 14:27:06 +0000</pubDate>
      <link>https://dev.to/vonagedev/build-a-storytelling-service-with-rcs-rich-cards-and-gemini-1h6j</link>
      <guid>https://dev.to/vonagedev/build-a-storytelling-service-with-rcs-rich-cards-and-gemini-1h6j</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;This tutorial shows you how to build a generative AI storytelling service using the &lt;a href="https://developer.vonage.com/en/messages/overview" rel="noopener noreferrer"&gt;Vonage Messages API&lt;/a&gt; for RCS and &lt;a href="https://gemini.google.com/" rel="noopener noreferrer"&gt;Google’s Gemini&lt;/a&gt; AI. You'll learn what RCS is, how to send and receive RCS Rich Card messages, and how to integrate Gemini to generate short bedtime stories.&lt;/p&gt;

&lt;p&gt;Inspired by my toddler's bedtime routines, I wanted to create something useful. So I combined RCS messaging with Gemini AI to develop a simple storytelling service.&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%2Fzj0n7uh80dvxcuwyysvv.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%2Fzj0n7uh80dvxcuwyysvv.png" alt="RCS Story Demonstration" width="800" height="1777"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can find the complete source code on the&lt;a href="https://github.com/Vonage-Community/blog-messages-nodejs-rcs_bedtime_story_generator/tree/main" rel="noopener noreferrer"&gt; Vonage Community GitHub repository&lt;/a&gt;.&lt;/p&gt;

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

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://nodejs.org/en/download" rel="noopener noreferrer"&gt;Node.js is installed&lt;/a&gt; on your machine.&lt;/li&gt;
&lt;li&gt;An API tunneling service, such as &lt;a href="https://developer.vonage.com/en/getting-started/tools/ngrok" rel="noopener noreferrer"&gt;ngrok&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;A registered &lt;a href="https://api.support.vonage.com/hc/en-us/articles/15546468078108-Understanding-RCS-and-RBM" rel="noopener noreferrer"&gt;RCS Business Messaging (RBM) agent&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;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;span&gt;.&lt;/span&gt;
&lt;/li&gt;
&lt;li&gt;A &lt;a href="https://dashboard.nexmo.com/sign-up" rel="noopener noreferrer"&gt;Vonage API account.&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Vonage API Account&lt;/li&gt;
&lt;li&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;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  How to Get RCS Working on Your Phone
&lt;/h3&gt;

&lt;p&gt;To send and receive RCS messages in your Vonage application, you need a registered RBM agent and a phone with RCS capabilities.&lt;/p&gt;

&lt;p&gt;RCS through Vonage is currently only available for managed accounts. You’ll need to &lt;a href="https://www.vonage.com/contact-us/" rel="noopener noreferrer"&gt;contact your account manager&lt;/a&gt; to activate Developer Mode, which allows testing with allowlisted numbers.&lt;/p&gt;

&lt;p&gt;If you don't have a managed account, reach out to the &lt;a href="https://www.vonage.com/contact-us/" rel="noopener noreferrer"&gt;Vonage Sales Team&lt;/a&gt; for support.&lt;/p&gt;

&lt;h2&gt;
  
  
  Terminology
&lt;/h2&gt;

&lt;p&gt;RCS (Rich Communication Services): An industry standard that enhances traditional messaging with rich media, branded content, and read receipts. If a recipient’s device or network doesn’t support RCS, messages automatically fall back to SMS to ensure they are still delivered.&lt;/p&gt;

&lt;p&gt;Learn more in our &lt;a href="https://developer.vonage.com/en/messages/concepts/rcs" rel="noopener noreferrer"&gt;RCS documentation&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;SMS (Short Message Service): Traditional SMS supports only plain text. RCS allows branded buttons, images, and message status updates. &lt;a href="https://developer.vonage.com/en/blog/send-sms-messages-with-node-js-one-dev-minute" rel="noopener noreferrer"&gt;Learn to send SMS messages with Node.js&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;MMS (Multimedia Messaging Service): Unlike MMS, which often has lower media quality and file size limits, RCS supports high-quality media and features such as typing indicators and delivery status updates. Learn &lt;a href="https://developer.vonage.com/en/blog/what-can-i-do-with-mms" rel="noopener noreferrer"&gt;what you can do with MMS&lt;/a&gt; and &lt;a href="https://developer.vonage.com/en/blog/how-to-send-mms-with-node-js-dr" rel="noopener noreferrer"&gt;how to send MMS with Node.js&lt;/a&gt;.&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;h3&gt;
  
  
  Messages API Capability
&lt;/h3&gt;

&lt;h4&gt;
  
  
  Start an ngrok Tunneling Instance
&lt;/h4&gt;

&lt;p&gt;If you haven’t used ngrok before, &lt;a href="https://developer.vonage.com/en/getting-started/tools/ngrok" rel="noopener noreferrer"&gt;you can start here&lt;/a&gt;. I’ve added the steps to run an instance below the image in the next section.&lt;/p&gt;

&lt;p&gt;Run the following command to start an ngrok tunneling instance.&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;In the output, you’ll find a URL that starts with https:// and ends in .ngrok.app/. Make a note of it as you’ll need it for the next step to configure your webhooks.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Forwarding https://94cd51b63460.ngrok.app/ -&amp;gt; http://localhost:8000          
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Configure Webhooks
&lt;/h4&gt;

&lt;p&gt;Back in the Vonage API Dashboard, under your Apps, toggle the Messages option under capabilities and set your server's public URL from ngrok as the endpoint for inbound messages and events. it should look like: &lt;code&gt;https://94cd51b63460.ngrok.app/webhooks/inbound&lt;/code&gt; for inbound and &lt;code&gt;https://94cd51b63460.ngrok.app/webhooks/status&lt;/code&gt; for status. If you’d like to &lt;a href="https://developer.vonage.com/en/getting-started/concepts/webhooks" rel="noopener noreferrer"&gt;learn more about webhooks, you can find information on our Vonage documentation&lt;/a&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%2Fppa3ewlv8qq7eon9pb23.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%2Fppa3ewlv8qq7eon9pb23.png" alt="webhooks" width="800" height="328"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Initial Project Setup for Vonage Messages API
&lt;/h2&gt;

&lt;p&gt;Clone the &lt;a href="https://github.com/Vonage-Community/blog-messages-nodejs-rcs-bedtime-story-generator/blob/main/src/server.js" rel="noopener noreferrer"&gt;Vonage Community GitHub repository&lt;/a&gt; for this project and &lt;code&gt;npm install&lt;/code&gt; the dependencies.&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 debug @vonage/messages @vonage/server-sdk dotenv
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Create the Environment Variables File
&lt;/h2&gt;

&lt;p&gt;Create a .env file in your project root.&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_VONAGE_APPLICATION_ID, can be found within the application you’ve created

VONAGE_PRIVATE_KEY=./private.key, is the path to the private.key file that was generated when you created your application

RCS_SENDER_ID=YOUR_RCS_SENDER_ID

PHONE_NUMBER=YOUR_PHONE_NUMBER_E164 that will receive the RCS messages

PORT=3000

VONAGE_API_SIGNATURE_SECRET= is the secret used to sign the request that corresponds to the signature secret associated with the api_key included in the JWT claims. You can identify your signature secret on the Dashboard settings
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In your project, you'll also find a &lt;a href="https://github.com/Vonage-Community/blog-messages-nodejs-rcs_bedtime_story_generator/blob/main/src/vonage.js" rel="noopener noreferrer"&gt;vonage.js file&lt;/a&gt; that contains the Dotenv and Vonage Client Setup.&lt;/p&gt;

&lt;h2&gt;
  
  
  Add JWT Verification
&lt;/h2&gt;

&lt;p&gt;Add a JWT verification function to verify if the incoming request (e.g., message or call) came from Vonage. &lt;/p&gt;

&lt;p&gt;The VONAGE_API_SIGNATURE_SECRET variable is the secret used to sign the request corresponding to the signature secret associated with the API key included in the JWT claims. You can identify your signature secret on the &lt;a href="https://dashboard.vonage.com/settings" rel="noopener noreferrer"&gt;Dashboard settings&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;You can learn more about &lt;a href="https://developer.vonage.com/getting-started/concepts/webhooks#verifying-the-request" rel="noopener noreferrer"&gt;verifying the request&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;const verifyJWT = (req) =&amp;gt; {
  // Verify if the incoming request came from Vonage
  const jwtToken = req.headers.authorization.split(" ")[1];
  if(!verifySignature(jwtToken, process.env.VONAGE_API_SIGNATURE_SECRET)) {
    console.error("Signature does not match");
    throw new Error("Not a Vonage API request");
  }

  console.log("JWT verified");
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Make sure to install the @vonage/jwt dependency.&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 @vonage/jwt
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Send an RCS Rich Card Message
&lt;/h2&gt;

&lt;p&gt;In your &lt;a href="https://github.com/Vonage-Community/blog-messages-nodejs-rcs_bedtime_story_generator/blob/main/src/server.js" rel="noopener noreferrer"&gt;server.js file,&lt;/a&gt; you'll find the finalized code with Gemini integration, but I wanted to give you a starting point on how to send a Rich Card Message in RCS with a hardcoded text so you can have a first experience with it and see it running before any more complex setup, with everything we've set up so far.&lt;/p&gt;

&lt;p&gt;Start off by adding the imports and defining your variables.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import Express from "express";

import { RCSCustom, RCSText } from "@vonage/messages";

import { vonage } from "./vonage.js";

import "dotenv/config";

const app = new Express();

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

const recipientNumber = process.env.PHONE_NUMBER;

if (!recipientNumber) {

  process.exit(1);

}

if (!process.env.RCS_SENDER_ID) {

  process.exit(1);

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

&lt;/div&gt;



&lt;p&gt;We'll also use an async wrapper for error handling in routes.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const catchAsync = (fn) =&amp;gt; (req, res, next) =&amp;gt; {

  fn(req, res, next).catch(next);

};

app.use(Express.json());

app.get(

  "/send-story-request",

  catchAsync(async (req, res) =&amp;gt; {

    await sendBedtimeStoryRequest(recipientNumber);

    res.status(200).json({ message: "Bedtime story request sent!" });

  })

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

&lt;/div&gt;



&lt;p&gt;Create the &lt;code&gt;/webhooks/status&lt;/code&gt; endpoint.&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(

  "/webhooks/status",

  catchAsync(async (req, res) =&amp;gt; {

    res.status(200).json({ ok: true });

  })

);


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

&lt;/div&gt;



&lt;p&gt;Create the &lt;code&gt;/webhooks/inbound&lt;/code&gt; endpoint.&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(

  "/webhooks/inbound",

  catchAsync(async (req, res) =&amp;gt; {

    const { channel, message_type, reply, from } = req.body;

    if (channel === 'rcs' &amp;amp;&amp;amp; message_type === 'reply' &amp;amp;&amp;amp; reply) {

      const receivedId = reply.id;

      const receivedTitle = reply.title;

      if (receivedId === 'GENERATE_STORY_REQUEST' || receivedTitle === 'Generate Story') {

        const replyToNumber = from;

        const helloWorldMessage = "Hello world!";

        await sendRCSGreeting(replyToNumber, helloWorldMessage);

      } else {

        // Unhandled reply

      }

    } else if (channel === 'rcs' &amp;amp;&amp;amp; message_type === 'text') {

      if (req.body.text &amp;amp;&amp;amp; req.body.text.toLowerCase() === 'generate story') {

        await sendRCSGreeting(from, "Hello world!");

      } else {

        await sendRCSGreeting(from, "I received your message: " + req.body.text);

      }

    }

    res.status(200).json({ ok: true });

  })

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

&lt;/div&gt;



&lt;p&gt;Add some error handling messages, and the app listens on the defined port (3000).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;app.all("*", (req, res) =&amp;gt; {

  res.status(404).json({

    status: 404,

    title: "Not Found",

  });

});

app.use((err, req, res, next) =&amp;gt; {

  res.status(500).json({

    status: 500,

    title: "Internal Server Error",

    detail: err.message,

  });

});

app.listen(port);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Create the &lt;code&gt;sendBedtimeStoryRequest&lt;/code&gt; that sends a new RCS Custom message that says ‘Bedtime Story Generator’, containing a button to generate a new story.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const sendBedtimeStoryRequest = async (number) =&amp;gt; {

  const message = new RCSCustom({

    to: number,

    from: process.env.RCS_SENDER_ID,

    custom: {

      contentMessage: {

        richCard: {

          standaloneCard: {

            cardOrientation: "VERTICAL",

            cardContent: {

              title: "Bedtime Story Generator",

              description: 'Tap "Generate Story" for a magical tale!',

              media: {

                height: "MEDIUM",

                contentInfo: {

                  fileUrl:

                    "https://cdn-icons-png.flaticon.com/512/2917/2917637.png",

                },

              },

              suggestions: [

                {

                  reply: {

                    text: "Generate Story",

                    postbackData: "GENERATE_STORY_REQUEST",

                  },

                },

              ],

            },

          },

        },

      },

    },

  });

  try {

    await vonage.messages.send(message);

  } catch (err) {

    if (err.response) {

      err.response.text().catch(() =&amp;gt; {});

    }

  }

};


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

&lt;/div&gt;



&lt;p&gt;Create the &lt;code&gt;sendRCSGreeting&lt;/code&gt; that sends an RCS message using the Vonage Messages API.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const sendRCSGreeting = async (to, messageText) =&amp;gt; {

  const message = new RCSText({

    to: to,

    from: process.env.RCS_SENDER_ID,

    text: messageText,

  });

  try {

    await vonage.messages.send(message);

  } catch (err) {

    if (err.response) {

      err.response.text().catch(() =&amp;gt; {});

    }

  }

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

&lt;/div&gt;



&lt;p&gt;To run the app, start the 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 server.js
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then visit the following URL in your browser, which triggers the first message to the user’s phone, inviting them to generate a story. The JSON confirmation in your browser, along with the received RCS message on your phone, are signs that the system is working.&lt;/p&gt;

&lt;p&gt;&lt;a href="http://localhost:3000/send-story-request" rel="noopener noreferrer"&gt;http://localhost:3000/send-story-request&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Integrate Google Gemini
&lt;/h2&gt;

&lt;p&gt;Now that we have the RCS messaging and webhook working, let's add Google Gemini to our storytelling service. &lt;/p&gt;

&lt;p&gt;When you navigate to &lt;a href="https://aistudio.google.com/app/prompts/new_chat" rel="noopener noreferrer"&gt;AI Studio&lt;/a&gt;), log in, and create a new chat, you can see ‘&amp;lt;&amp;gt;Get Code' at the top right and select your programming language of choice. Choose the model. I've used “Gemini 1.5 Flash Experimental,” but you can choose the one that makes the most sense for your project. &lt;/p&gt;

&lt;p&gt;To learn more, visit the &lt;a href="https://ai.google.dev/gemini-api/docs" rel="noopener noreferrer"&gt;Gemini Developer API documentation page&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Install the Gemini SDK
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm install @google/generative-ai
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Add your Gemini API key to .env.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;GEMINI_API_KEY="YOUR_GEMINI_API_KEY"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Initialize Gemini
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { GoogleGenerativeAI } from "@google/generative-ai";

const genAI = new GoogleGenerativeAI(process.env.GEMINI_API_KEY);

const geminiModel = genAI.getGenerativeModel({ model: "gemini-1.5-flash" });
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Generate Stories with Gemini
&lt;/h3&gt;

&lt;p&gt;With Gemini initialized, we update our&lt;code&gt;/webhooks/inbound&lt;/code&gt; handler. When the user clicks "Generate Story," instead of replying "Hello world!", we now call &lt;code&gt;geminiModel.generateContent&lt;/code&gt; with a specific prompt for a bedtime story. &lt;/p&gt;

&lt;p&gt;The generated text is then sent back to the user using &lt;code&gt;sendGeneratedStory&lt;/code&gt;. We also added handling for users who might type "Generate Story" manually.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;sendGeneratedStory&lt;/code&gt; function now takes the generated story text and uses RCSText to send it back as a regular RCS text message.&lt;/p&gt;

&lt;h2&gt;
  
  
  Test the Storytelling Service
&lt;/h2&gt;

&lt;p&gt;To run the app, (re)start the 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 server.js
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then visit the following URL in your browser: &lt;a href="http://localhost:3000/send-story-request" rel="noopener noreferrer"&gt;http://localhost:3000/send-story-request&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;From your device, you'll receive an RCS message. Tap the "Generate Story" to receive a Gemini-created bedtime story.&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%2Fhazklktprbzyi0mwxzbk.gif" 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%2Fhazklktprbzyi0mwxzbk.gif" alt="RCS Project" width="572" height="1209"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Conclusion&lt;/p&gt;

&lt;p&gt;This tutorial showed you how to build a Gemini-powered storytelling service using Vonage’s RCS API. The last time I did anything related to RCS was in 2020. I participated in a workshop where each attendee was sent an RCS-enabled SIM card. It was nice to get back to working with RCS again, and I can't wait to write more blog posts about this.&lt;/p&gt;

&lt;p&gt;Have a question or something to share? Join the conversation on the &lt;a href="https://developer.vonage.com/en/community/slack" rel="noopener noreferrer"&gt;Vonage Community Slack&lt;/a&gt;, stay up to date with the &lt;a href="https://ww3.nexmo.com/subscribe-the-vonage-developer-newsletter" rel="noopener noreferrer"&gt;Developer Newsletter&lt;/a&gt;, follow us on &lt;a href="https://x.com/vonagedev" rel="noopener noreferrer"&gt;X (formerly Twitter)&lt;/a&gt;, and subscribe to our &lt;a href="https://www.youtube.com/@VonageDev" rel="noopener noreferrer"&gt;YouTube channel &lt;/a&gt;for video tutorials. Stay connected, share your progress, and keep up with the latest developer news, tips, and events!&lt;/p&gt;

</description>
      <category>rcs</category>
      <category>gemini</category>
    </item>
    <item>
      <title>New Backend Integrations for the Firebase Studio App Prototyping Agent</title>
      <dc:creator>Amanda Cavallaro</dc:creator>
      <pubDate>Tue, 20 May 2025 21:26:15 +0000</pubDate>
      <link>https://dev.to/chibichibibr/new-backend-integrations-for-the-firebase-studio-app-prototyping-agent-2kc0</link>
      <guid>https://dev.to/chibichibibr/new-backend-integrations-for-the-firebase-studio-app-prototyping-agent-2kc0</guid>
      <description>&lt;h2&gt;
  
  
  Announcement
&lt;/h2&gt;

&lt;p&gt;New backend integrations for the Firebase Studio App Prototyping agent were announced today at the &lt;a href="https://www.youtube.com/watch?v=GjvgtwSOCao&amp;amp;list=PLOU2XLYxmsIJEQRQDtuYKVUmxYvRfWN5m" rel="noopener noreferrer"&gt;Google I/O 2025 Developer Keynote&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Shall we try it out together? Go to the &lt;a href="https://firebase.studio/" rel="noopener noreferrer"&gt;Firebase Studio&lt;/a&gt;, and use the App Prototyping agent. &lt;/p&gt;

&lt;h2&gt;
  
  
  The Use Case We Will Prototype: Improve Your Multifactor Auth With Vonage APIs and Firebase
&lt;/h2&gt;

&lt;p&gt;I've one project I've created (without the Studio), titled &lt;a href="https://developer.vonage.com/en/blog/improve-your-multifactor-auth-with-vonage-apis-and-firebase" rel="noopener noreferrer"&gt;Improve Your Multifactor Auth With Vonage APIs and Firebase&lt;/a&gt;, which uses Firebase Services to store functions with Cloud Functions, data in the Cloud Firestore database, and Firebase hosting.&lt;/p&gt;

&lt;p&gt;While this project wasn't created using the Prototyping agent, I am keen to build something similar and try it out, in theory I should describe an application that needs database and authentication then it is all created using emulators, which is how I do during my testing anyway and then once we click to publish after we set up the Firebase project and project billing account information, Firebase provisions the Firestore, Firebase Auth and App Hosting.&lt;/p&gt;

&lt;p&gt;So let's try it out!&lt;/p&gt;

&lt;h2&gt;
  
  
  Prototype the Agent with AI
&lt;/h2&gt;

&lt;p&gt;I've prototyped the agent using AI, explaining its purpose in the text area.&lt;br&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%2Fzym0jsn564bdsvzk1666.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%2Fzym0jsn564bdsvzk1666.png" alt="Hello, Name&amp;lt;br&amp;gt;
Welcome back&amp;lt;br&amp;gt;
Prototype an app with AI&amp;lt;br&amp;gt;
" width="800" height="610"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Blueprint Generation
&lt;/h2&gt;

&lt;p&gt;The blueprint then showed me the features, the style guidelines, and the Authentication and Cloud Firestore under a new section called “Stack”.&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%2Fnzeobtmq8l22242un69o.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%2Fnzeobtmq8l22242un69o.png" alt="Phone Number Input — User interface for inputting phone number and requesting a verification code.&amp;lt;br&amp;gt;
Send Verification Code — Utilize Vonage Verify 2 API to send a verification code to the user's phone number via SMS. This utilizes a private key from the environment.&amp;lt;br&amp;gt;
Store Request ID — Save the request ID (returned by the Vonage API) in a Firestore database, indexed by phone number.&amp;lt;br&amp;gt;
PIN and Password Input — User interface to input the received PIN and a new password.&amp;lt;br&amp;gt;
PIN Verification and Password Update — Verify the entered PIN against the Vonage Verify 2 API. Upon successful verification, update the password in the Firestore database.&amp;lt;br&amp;gt;
SIM Swap Detection — Check SIM swap status using the Vonage CAMARA API to check for risk. This is exposed as a backend tool.&amp;lt;br&amp;gt;
Color&amp;lt;br&amp;gt;
Layout&amp;lt;br&amp;gt;
Clean layout with sufficient spacing to facilitate a pleasant user experience.&amp;lt;br&amp;gt;
Typography&amp;lt;br&amp;gt;
Clean, sans-serif font for readability and a modern feel.&amp;lt;br&amp;gt;
Iconography&amp;lt;br&amp;gt;
Use simple, line-based icons for a clean and modern look.&amp;lt;br&amp;gt;
Animation&amp;lt;br&amp;gt;
Use subtle transitions when changing from one state to another.&amp;lt;br&amp;gt;
UI&amp;lt;br&amp;gt;
TypeScript, NextJS, Tailwind CSS&amp;lt;br&amp;gt;
Backend&amp;lt;br&amp;gt;
Experimental&amp;lt;br&amp;gt;
Cloud Firestore, Firebase Authentication&amp;lt;br&amp;gt;
Preview backend runs in this workspace until published" width="800" height="968"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I then clicked on the "Prototype this app" button at the bottom of the page.&lt;/p&gt;

&lt;h2&gt;
  
  
  Preview and Testing
&lt;/h2&gt;

&lt;p&gt;It created a preview, assigned my app the name "SecurePass," which I had not initially given it, and generated a cool UI for me. It's super cool; it's added a login and register button to the navigation bar. It all uses the &lt;a href="https://firebase.google.com/docs/emulator-suite" rel="noopener noreferrer"&gt;Firebase Emulator Suite&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;It got back to me with the following message: &lt;/p&gt;

&lt;p&gt;"OK, let's prototype this app!&lt;/p&gt;

&lt;p&gt;The first iteration of your app prototype is ready! Try it out in the preview window and describe the changes you'd like to make below.&lt;/p&gt;

&lt;p&gt;Want to make changes directly? Hit the &amp;lt;/&amp;gt; button at the top to switch to the code editor, or click 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%2F80fcs5taxsr9ymgv1ta4.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%2F80fcs5taxsr9ymgv1ta4.png" alt="UI Generated containing " width="800" height="616"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As I attempted to interact with the UI, I encountered some dependency issues. I had the option to either edit the code myself or use Gemini to help resolve the issues. I then had to adjust the dependencies and any necessary environment variables.&lt;/p&gt;

&lt;h2&gt;
  
  
  Publish
&lt;/h2&gt;

&lt;p&gt;When I was ready and happy with the code in the preview at the top right, I clicked on "Publish", which gave me a Firebase project ID, a billing account to choose from and a button to enable firebase services, then finally I could choose between publishing now or later - and there it was, hosted on the cloud, with auth and database enabled!&lt;/p&gt;

&lt;h2&gt;
  
  
  Final Remarks
&lt;/h2&gt;

&lt;p&gt;This was cool and fast to create. It feels like I'm talking to Gemini, being integrated with Firebase, and everything is magical. It goes beyond using &lt;a href="https://idx.dev/" rel="noopener noreferrer"&gt;project IDX&lt;/a&gt;. Funny thing, I went on the project IDX website to copy and paste for this link, and I see it now turned into Firebase Studio. As they state: "As part of evolving IDX past its preview stages, we are happy to announce that IDX is joining the Firebase family! Firebase Studio will build upon what we've created with IDX by further blending AI-assistance to help you build the next generation of apps.&lt;/p&gt;

&lt;p&gt;Your existing IDX workspaces, settings, sharing URLs, and more will continue to work in Firebase Studio. Let's get started!".&lt;/p&gt;

&lt;p&gt;Ha, that makes total sense, and I love that it's connected now. Makes the developer's life easier; everything you need is in one tool. I can see myself using this more often. Do you have any specific use cases in mind for how you plan to use this?&lt;/p&gt;

&lt;p&gt;Check out the &lt;br&gt;
&lt;a href="https://firebase.blog/posts/2025/05/studio-updates-from-io" rel="noopener noreferrer"&gt;Top Firebase Studio updates from Google I/O 2025&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>firebase</category>
      <category>studio</category>
      <category>cloud</category>
    </item>
    <item>
      <title>Attending Tech Conferences With a Toddler: A DevRel Mom’s Story</title>
      <dc:creator>Amanda Cavallaro</dc:creator>
      <pubDate>Mon, 27 Jan 2025 15:49:53 +0000</pubDate>
      <link>https://dev.to/vonagedev/attending-tech-conferences-with-a-toddler-a-devrel-moms-story-41np</link>
      <guid>https://dev.to/vonagedev/attending-tech-conferences-with-a-toddler-a-devrel-moms-story-41np</guid>
      <description>&lt;h2&gt;
  
  
  &lt;strong&gt;Introduction&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;My career didn't have to stop because I became a mother; if anything, my daughter’s existence complements and adds to my story. I am thankful I gave my daughter the experiences I will share in this blog post! &lt;/p&gt;

&lt;p&gt;Traveling to speak and attend conferences with a toddler can be an enjoyable experience. You both experience a new place together, meet new people, and learn about new cultures. &lt;/p&gt;

&lt;p&gt;Reading a blog post with tips like the ones I’ll share could have saved me from overpacking, learning to set my pride aside and ask for help when needed, managing my expectations, and being realistic.&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%2Fgoe79fnb1g2yjgpw7qpx.jpg" 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%2Fgoe79fnb1g2yjgpw7qpx.jpg" alt="The baby playing with Lego" width="800" height="1422"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Pro Tips for Travelling with a Toddler by Plane&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;When I pack to leave the house before the trip, everything seems to be highly organized and easy to store, but what I've realized is that on the way back, I've never managed to fully put everything back in its state and especially during the trip when you need to get a cup, or a change of clothes quickly, it's hard to keep items tidy. So I find it necessary to leave with a bag that's easy to grab and see things and to leave some empty room because things tend to occupy more space when they are not tidy.&lt;/p&gt;

&lt;p&gt;Here’s a list of the main things I would bring for a multi-day tech conference trip. I wouldn’t expect everything to be tidy all the time, but having a home to put things back in and find them does make things more visually accessible.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Cluster Organize per Categories&lt;/strong&gt;
&lt;/h3&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;Toy Bag&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;My toddler's first flights were all about waving at everyone, opening and closing the tray, and looking out the window; everything was new and fun to explore. Nowadays, she's traveled quite a bit, and at times, long-haul flights, so these are some of the toys I usually have with me that help out.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Magnetic tiles&lt;/li&gt;
&lt;li&gt;Mess-free coloring books&lt;/li&gt;
&lt;li&gt;Re-stickable stickers&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;Food Bag&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;None of the flights I've ever been on offered food suitable for babies, so I had to carry them. &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Powdered milk (you might not have access to a fridge, so if it's formula or any powered milk that works for you, that's a good idea)&lt;/li&gt;
&lt;li&gt;Milk that comes in liquid form can be stored outside the fridge&lt;/li&gt;
&lt;li&gt;Baby food that can be stored outside of the fridge&lt;/li&gt;
&lt;li&gt;Bibs/ cutlery&lt;/li&gt;
&lt;li&gt;Wipes, muslins&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;Documents Bag&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;My document bag is always within hand's reach because I carry many things and a baby, so I wear it as a cross-body bag.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Passports&lt;/li&gt;
&lt;li&gt;Letter from the other parent/ responsible in case of traveling solo&lt;/li&gt;
&lt;li&gt;Note down your blood type, allergies, or everything else. If you can, translate it into the local language&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;Electronics Bag&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;Think of everything you'll need to give your talk at the conference.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Portable charger&lt;/li&gt;
&lt;li&gt;Outlet adapter&lt;/li&gt;
&lt;li&gt;Phone charger&lt;/li&gt;
&lt;li&gt;Laptop&lt;/li&gt;
&lt;li&gt;Laptop charger&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;Baby Change Bag&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;You get to change diapers in different places and face new challenges.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Diapers/ Underwear (extra potty training items if that's the case)&lt;/li&gt;
&lt;li&gt;Wet wipes/ cotton disks&lt;/li&gt;
&lt;li&gt;One change of clothes&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;Medicines Bag&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;Check if the over-the-counter medications you can buy where you live can be brought with you, and make sure they meet the liquid limits for hand luggage.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Paracetamol / Ibuprofen under 100 ml at most airports or any other medicine you might need with a prescription&lt;/li&gt;
&lt;li&gt;Teething medicine&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;Clothes Bag&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;I bring a lot of clothes changes. For Devfest Modena, my baby wore a Firebase shirt, and I could hear the comments: "Oh look, that baby is wearing a Firebase shirt—so cool!"&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Get stretchy, easy-to-dress clothes, not ones that require too much effort to put on when dressing the child.&lt;/li&gt;
&lt;li&gt;Avoid traveling with the clothes you love too much. You might not have access to washing them quickly with the right products, and getting rid of stains after they've been there for days can be harsh. Instead, look for local laundry services or travel with necessary laundry products.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Airport Tips&lt;/strong&gt;
&lt;/h3&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;Going Through X-Ray Security&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;Usually, you put all your stuff on the belt, take your laptop out of the bag, take the belt off, and take off your shoes. Ugh, that's so annoying! Now, imagine doing it alone with a baby. How?&lt;/p&gt;

&lt;p&gt;First, you won't be allowed to use your stroller to walk through. You'll have to carry your baby with you. Ok, alright. What about collecting your things and ensuring the toddler doesn't run away? You can wait to collect the stroller and fasten their seatbelt; you can wait for your baby carrier to come through the x-ray and wear it. You can hold their hands as you're doing everything.&lt;/p&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;Read Both Airline and Airport Regulations&lt;/strong&gt;
&lt;/h4&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;Milk&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;When I traveled to a conference in Berlin, I read thoroughly through the airline regulations that allowed me to transport breast milk. However, the airport only allowed breast milk if the baby was with me. She wasn't. A lot of tears were shed from throwing away a liter of milk. I managed to collect and store it throughout the conference, and a sad story: this happened on International Breastfeeding Day.&lt;/p&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;Liquids&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;Some airports have started allowing you to carry more than 100 ml. But that's only the case sometimes at both the departure and arrival airports, so double-check everything to save everything.&lt;/p&gt;

&lt;p&gt;Some airlines allow toddlers to leave two items by the aircraft's door before they board, but others, especially low-cost airlines, only allow one. Since you'll need the car seat if you use cars or taxis to your destination, it should also go with you. Check before you book, though, because if you have more than one piece and it's not allowed, you'll have to check them.&lt;/p&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;Arrival&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;This part is particularly challenging for me because I have a hard time asking for help, so I tried for several trips only to have bags that would go under my seat and not depend on the overhead compartment because that would require asking someone to collect whatever I put up there for me. &lt;/p&gt;

&lt;p&gt;I find it particularly challenging at this point when the toddler has sat down for a whole flight, sees everyone standing, wants to walk, and there's a long queue of people waiting. At this point, I already have them in the baby carrier, and my backpack and my cross-body bag are ready.&lt;/p&gt;

&lt;p&gt;However, on my last few flights, I've decided to put my pride aside and accept that I need help. I chose this option because of the time I had to walk from leaving the plane to passport control to waiting for the bags on each flight. The embarked bags and stroller could arrive in different areas, even within the same airport and terminal. &lt;/p&gt;

&lt;p&gt;The amount of time I already had to babywear a baby and carry bags while waiting became a pain. It made sense to take the babywear and a 4-wheeled handbag in the overhead compartment with me. As I wait for my bag, it's easier and lighter to roll my luggage and let my toddler wander around and stretch their legs rather than worry about a toddler carrying a heavy bag on my back.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Conference Tips&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;You might be in a different city or country or have timezone differences. Food and sleep times can be changed, and your child might be over- or understimulated, having to sit or walk more than usual. There can be more tantrums, and we need to help them self-regulate, so plan accordingly and allow them time to adapt and adjust.&lt;/p&gt;

&lt;p&gt;Not all conferences have the same accessibility and inclusion initiatives. Some events do not allow individuals under a certain age, so it's worth checking beforehand if your child is allowed there. You should also check the code of conduct and the conference website and reach out to the organizers about any questions, especially if policies aren’t clear.&lt;/p&gt;

&lt;p&gt;Some events have a parent or quiet room, while others don't. Some are accessible for you to wander around with your stroller, while others don't. Some events have baby-changing rooms, while others don't. You don't have to worry about carrying too many toys at some events, as some sponsored toys keep children entertained. So, if any of these points are overwhelming, reach out to the organizers beforehand and/or plan how to manage these situations in case some are absent.&lt;/p&gt;

&lt;p&gt;People treat you exceptionally well at some events, and you feel welcome. Others are looked at and frowned upon for bringing a baby there. It’s essential to manage your expectations; you know yourself better than anyone else, so if a place doesn’t feel very welcoming, maybe consider attending/ speaking at a conference where your presence is valued. At the same time, this is also an opportunity to help the organizers share your feedback.&lt;/p&gt;

&lt;p&gt;Networking at conferences with a toddler is fun—you always have an icebreaker topic to start! Because toddlers require attention, I have only as long and deep conversations as possible with the present, but I can catch up with people and make new connections. &lt;/p&gt;

&lt;p&gt;There are so many kind people out there; they’ve offered to help by playing a cartoon on their phone, or if they’d like them to serve and bring any food or beverages for me during mealtimes, even offering to let me jump the food line.&lt;/p&gt;

&lt;p&gt;I’ve been able to watch some talks and attend workshops when nap time would coincide, but other than that, I’d save to watch the recordings at a later time. &lt;/p&gt;

&lt;p&gt;It’s essential to look around and understand how safe the place is; if there are stairs, escalators, places they might have a fall, or objects that could break and hurt them, assessing your surroundings is key to knowing when you can leave them run around a bit and not lose them.&lt;/p&gt;

&lt;p&gt;I’ve had not-so-ideal experiences at some conferences; I was so overwhelmed. I thought to myself, I don’t want to attend this conference in the future because some of my breast milk-expressing requests that were asked ahead of the conference time were unmet. After I traveled and arrived home safely, I contacted the organizers, letting them know of everything I went through, and they promised their best efforts to make sure no other new parent would have to go through that in the future. That resonated with me, and I felt comfortable sharing feedback because I am a developer advocate. I advocate for technical content and experience and how included and appreciated, we are to be present at conferences.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Where is the Baby While You're on Stage?&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;So far, I've asked for help from my friends and family while speaking at conferences. I'd still let organizers know I had a baby to account for unforeseen circumstances. &lt;/p&gt;

&lt;p&gt;Depending on the child’s age and the people they’ve been used to seeing or being around, they might resist being in the company of others. What I can share that worked for me was a selection of toys and activities prepared beforehand, in addition to favorite snacks and beverages packed. No one can know my child better than the ones who see her around more often, so being able to share with those who look after your child for that limited amount of time how to offer comfort and entertain her is key.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;When I gave a talk at &lt;a href="https://f3.events/?adobe_mc=MCMID%3D89448777371780096381139893056321793840%7CMCORGID%3DA8833BC75245AF9E0A490D4D%2540AdobeOrg%7CTS%3D1737990799" rel="noopener noreferrer"&gt;F3 in Prague&lt;/a&gt;, Czech Republic, I went on stage baby-wearing my child. I had my friend Laura Morinigo, also a speaker at the event, sit in the front row and be ready to take her if she started crying, so she did. She looked after her, and I babywore her for the talk's first and last minutes.&lt;/li&gt;
&lt;li&gt;When I spoke at &lt;a href="https://www.devtalks.ro/8-devtalks-cluj-napoca-2024?adobe_mc=MCMID%3D89448777371780096381139893056321793840%7CMCORGID%3DA8833BC75245AF9E0A490D4D%2540AdobeOrg%7CTS%3D1737990799" rel="noopener noreferrer"&gt;Devtalks Cluj-Napoca&lt;/a&gt;, Romania, my friend Sam Pavlovic looked after her. She was sitting on her stroller, and one exciting thing Sam shared was that because my voice was the one echoing in the room, she kept calm while being in the same room listening to her mom's voice.&lt;/li&gt;
&lt;li&gt;At &lt;a href="https://devfest.modena.it/?adobe_mc=MCMID%3D89448777371780096381139893056321793840%7CMCORGID%3DA8833BC75245AF9E0A490D4D%2540AdobeOrg%7CTS%3D1737990799" rel="noopener noreferrer"&gt;Devfest Modena&lt;/a&gt;, Italy, her uncle and aunt looked after her as they lived there. That day, she was very distressed and crying very loudly because she wanted to be near me; their approach was to take her out of the venue so as not to disturb everyone else and offer comfort.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Final Remarks&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;It's been an incredible ride for me to travel with my under-2-year-old daughter and show her different tech events in various countries. We have visited the Czech Republic, Romania, and Italy and attended countless events together in the UK. &lt;/p&gt;

&lt;p&gt;She has been on stage, given away swag, taken public transport, tried local food, slept on planes, and been on plane rides, only wanting to walk the whole time. I've carried strollers up and down stairs, and she's met several people from different nationalities and backgrounds.&lt;/p&gt;

&lt;p&gt;If you have more questions or want to share your story, connect with us on the &lt;a href="https://developer.vonage.com/en/community/slack" rel="noopener noreferrer"&gt;Vonage Developer Slack&lt;/a&gt; or &lt;a href="https://x.com/VonageDev?adobe_mc=MCMID%3D89448777371780096381139893056321793840%7CMCORGID%3DA8833BC75245AF9E0A490D4D%2540AdobeOrg%7CTS%3D1737990799" rel="noopener noreferrer"&gt;@VonageDev on X&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>devrel</category>
    </item>
    <item>
      <title>Improve Your Multifactor Auth With Verify and SIM Swap APIs</title>
      <dc:creator>Amanda Cavallaro</dc:creator>
      <pubDate>Fri, 23 Aug 2024 13:36:52 +0000</pubDate>
      <link>https://dev.to/vonagedev/improve-your-multifactor-auth-with-verify-and-sim-swap-apis-55c1</link>
      <guid>https://dev.to/vonagedev/improve-your-multifactor-auth-with-verify-and-sim-swap-apis-55c1</guid>
      <description>&lt;h2&gt;
  
  
  &lt;strong&gt;Introduction&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;SIM Swap attacks impose many risks, including identity theft and identity takeover, to name a few. This tutorial will showcase how to improve security when resetting passwords by checking whether your SIM card was swapped from your mobile phone and sending an SMS to recover the account. The flow uses the&lt;a href="https://developer.vonage.com/en/verify/overview" rel="noopener noreferrer"&gt; Verify API&lt;/a&gt; to verify a token and the&lt;a href="https://developer.vonage.com/en/sim-swap/overview" rel="noopener noreferrer"&gt; SIM Swap API&lt;/a&gt; to detect if a SIM card was swapped in the last few days. If so, the verification code won’t be sent.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Note: The Network APIs are available in the &lt;a href="https://developer.vonage.com/en/getting-started-network/registration#network-api-availability" rel="noopener noreferrer"&gt;following countries and Communication Service Providers (CSPs)&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Source Code&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;The application's source code can be found on our&lt;a href="https://github.com/Vonage-Community/blog-sim-swap_verifyv2-javascript-multifactor_authentication" rel="noopener noreferrer"&gt; GitHub repo&lt;/a&gt;.&lt;/p&gt;

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

&lt;ul&gt;
&lt;li&gt;A&lt;a href="https://dashboard.nexmo.com/sign-up" rel="noopener noreferrer"&gt; Vonage developer account&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Node.js and npm&lt;a href="https://nodejs.org/en/download/" rel="noopener noreferrer"&gt; installed on your machine&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;A code/text editor and basic JavaScript knowledge.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Application Architecture&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;The application follows a client-server architecture. The client handles user interactions through HTML and JavaScript, including entering phone numbers and submitting verification codes. The client and the server communicate via GET/POST requests. The server, developed in Node.js with Express, manages backend logic, including interfacing with Vonage’s SIM Swap and Verify v2 APIs for security checks and authentication.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Create a New Project&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Create a new project and change into its directory.&lt;br&gt;
&lt;code&gt;mkdir improve-your-auth &amp;amp;&amp;amp; cd improve-your-auth&lt;/code&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  &lt;strong&gt;Start a New Node Project&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;In your newly created project directory, initialize a new node project. This will create a new &lt;code&gt;package.json&lt;/code&gt; file. The &lt;code&gt;-y&lt;/code&gt; flag automatically fills in the defaults without asking for the details.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;npm init -y&lt;/code&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  &lt;strong&gt;Install the Dependencies&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;To install all the dependencies in one go, run the following command. It will automatically add them to your &lt;code&gt;package.json&lt;/code&gt; file and install them in your project's &lt;code&gt;node_modules&lt;/code&gt; directory.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;npm install @vonage/server-sdk @vonage/auth axios dotenv express&lt;br&gt;
&lt;/code&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  &lt;strong&gt;Create a New Vonage Application&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Now that we have specified the folders and dependencies we will use for the project, it's time to create a Vonage Application with Verify and SIM swap capabilities.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://ui.idp.vonage.com/ui/auth/registration" rel="noopener noreferrer"&gt;After signing up/in for a Vonage account&lt;/a&gt;, you can create a new application in the dashboard by navigating to&lt;a href="https://dashboard.nexmo.com/applications" rel="noopener noreferrer"&gt; 'Your Applications'&lt;/a&gt;, clicking to create a new application, giving it a name, such as 'multifactor authentication,' and toggling Verify V2 and Network APIs.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Note: Register your application with Vonage and the Communication Service Providers (CSP) before using the SIM Swap API. If your registration is already approved, you can start building your solution right away. If not, check out our guide on&lt;a href="https://developer.vonage.com/en/getting-started-network/registration" rel="noopener noreferrer"&gt; Vonage Network Registration&lt;/a&gt; for more details.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Create a public/private key pair for API authentication; this will download a &lt;code&gt;private.key&lt;/code&gt;. Add that file to your node project folder.&lt;/p&gt;
&lt;h2&gt;
  
  
  &lt;strong&gt;Server Side Implementation&lt;/strong&gt;
&lt;/h2&gt;
&lt;h3&gt;
  
  
  &lt;strong&gt;SIM Swap Overview&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;The important aspect of the SIM Swap API we will use for this demonstration is the ability to check whether the swap happened in the last few days to let the user know there could have been a potential fraud in case the swap wasn't made by them.&lt;/p&gt;

&lt;p&gt;The SIM Swap API strengthens SIM-based authentication methods, including SMS One-Time Passwords and silent authentication. It keeps track of the last SIM swap on a specific mobile number and checks the activation date of a SIM card in real time.&lt;/p&gt;
&lt;h3&gt;
  
  
  &lt;strong&gt;Create the Server File&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;The &lt;code&gt;server.js&lt;/code&gt; file is our main server script that integrates with the Vonage SIM Swap and Verify v2 APIs to authenticate users securely. It also serves the web pages for our banking dashboard and handles user login and verification.&lt;/p&gt;
&lt;h3&gt;
  
  
  &lt;strong&gt;Authentication Function&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;We need to authenticate our requests to communicate with the&lt;a href="https://developer.vonage.com/en/sim-swap/overview" rel="noopener noreferrer"&gt; SIM Swap API&lt;/a&gt;. Here's how we can set up an authentication function using OAuth2. It requires two POST requests, one to retrieve the &lt;code&gt;auth_req_id&lt;/code&gt; and the other to get a new access token.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;async function authenticate(phone, scope) {
  try {
    const authReqResponse = await axios.post(
      authReqUrl,
      {
        login_hint: phone,
        scope: scope,
      },
      {
        headers: {
          Authorization: `Bearer ${process.env.JWT}`,
          "Content-Type": "application/x-www-form-urlencoded",
        },
      }
    );
    const authReqId = authReqResponse.data.auth_req_id;

    const tokenResponse = await axios.post(
      tokenUrl,
      {
        auth_req_id: authReqId,
        grant_type: "urn:openid:params:grant-type:ciba",
      },
      {
        headers: {
          Authorization: `Bearer ${process.env.JWT}`,
          "Content-Type": "application/x-www-form-urlencoded",
        },
      }
    );
    return tokenResponse.data.access_token;
  } catch (error) {
    console.error(
      "Error during authentication:",
      error.response?.data || error.message
    );
    throw error;
  }
}

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

&lt;/div&gt;



&lt;h3&gt;
  
  
  &lt;strong&gt;SIM Swap Check&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;The &lt;code&gt;checkSim&lt;/code&gt; function checks if the phone number has been swapped recently. It uses the &lt;code&gt;authenticate&lt;/code&gt; function to get an access token and then queries the&lt;a href="https://developer.vonage.com/en/sim-swap/overview" rel="noopener noreferrer"&gt; SIM Swap API&lt;/a&gt;. I've set a &lt;code&gt;MAX_AGE&lt;/code&gt; environment variable, which you can set to the number of hours ago you want to check if the SIM swap happened.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;async function checkSim(phoneNumber) {
  try {
    const accessToken = await authenticate(scope);
    const response = await axios.post(simSwapApiUrl, {
      phoneNumber: phoneNumber,
      maxAge: process.env.MAX_AGE,
    }, {
      headers: {
        Authorization: `Bearer ${accessToken}`,
        "Content-Type": "application/json",
      },
    });
    return response.data.swapped;
  } catch (error) {
    console.error("Error checking SIM swap:", error.response?.data || error.message);
    throw error;
  }
}

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

&lt;/div&gt;



&lt;h2&gt;
  
  
  &lt;strong&gt;Add Verify V2 API&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;The&lt;a href="https://developer.vonage.com/en/verify/overview" rel="noopener noreferrer"&gt; Verify V2 API&lt;/a&gt; in our use case allows us to send a verification code to a user's phone number if no recent SIM swap has been detected.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Verification Request&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Below, we handle a verification request. If no SIM swap is detected, we proceed with sending a verification code using Verify V2 API:&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("/sendcode", async (req, res) =&amp;gt; {
  const phone = req.body.phone; // phone number to verify
  if (!await checkSim(phone)) {
    try {
      const response = await vonage.verify2.newRequest({
        brand: "Vonage Bank",
        workflow: [{ channel: Channels.SMS, to: phone }]
      });
      res.json({ message: "Verification code sent.", request_id: response.requestId });
    } catch (error) {
      console.error("Error during verification:", error);
      res.status(500).json({ message: "Error processing request." });
    }
  } else {
    console.log("SIM swap detected. Verification code not sent.");
    res.status(403).json({ message: "Verification denied due to recent SIM swap." });
  }
});
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  &lt;strong&gt;PIN Submission&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;After receiving the verification code, the user can submit it through our service. Here's how we verify the submitted PIN:&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("/verify", async (req, res) =&amp;gt; {
  const { pin, requestId } = req.body; // pin and request ID from user input
  try {
    const result = await vonage.verify2.checkCode(requestId, pin);
    if (result === "completed") {
      res.json({ message: "Verification successful." });
    } else {
      res.json({ message: "Invalid PIN. Please try again." });
    }
  } catch (error) {
    console.error("Error during PIN verification:", error);
    res.status(500).json({ message: "Error during PIN verification." });
  }
});

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

&lt;/div&gt;



&lt;h2&gt;
  
  
  &lt;strong&gt;Create the Environment Variables File&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Create a &lt;code&gt;.env&lt;/code&gt; file for your project and add the environment variables found in the code snippet below. Refer to&lt;a href="https://developer.vonage.com/en/blog/how-to-use-environment-variables-in-node-js" rel="noopener noreferrer"&gt; Michael's blog post for a wonderful explanation of using environment variables in Node.js&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;VONAGE_API_SECRET&lt;/code&gt; and &lt;code&gt;VONAGE_API_SECRET&lt;/code&gt; can be found on the&lt;a href="https://dashboard.nexmo.com/" rel="noopener noreferrer"&gt; Vonage Dashboard&lt;/a&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%2Frx4qcijvlo8cs662pc17.jpg" 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%2Frx4qcijvlo8cs662pc17.jpg" alt="Vonage Dashboard" width="800" height="374"&gt;&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;# Your Vonage application 
VONAGE_API_KEY=your_api_key
VONAGE_API_SECRET=your_api_secret
VONAGE_APPLICATION_ID=your_application_id
VONAGE_APPLICATION_PRIVATE_KEY=/path/to/your/private.key

# Use this URL to generate a new JWT: https://developer.vonage.com/en/jwt
JWT=your_jwt_token

# Number of hours to check SIM Swap events
MAX_AGE=72
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  &lt;strong&gt;Client Side Implementation&lt;/strong&gt;
&lt;/h2&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Add the Content and Styling&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;In the index.html file, we will add two forms: one for entering a phone number and another for logging in with a PIN. This layout enables the user to authenticate their identity securely. For simplicity and clarity, I am leaving the password in plain text. Of course, in real-life/ production scenarios, you’ll need to encrypt the password and eventually add a Salt value to strengthen the security.&lt;/p&gt;

&lt;p&gt;In the&lt;a href="https://github.com/Vonage-Community/blog-sim-swap_verifyv2-javascript-multifactor_authentication/blob/main/views/main.html" rel="noopener noreferrer"&gt; main.html file&lt;/a&gt;, we will have our bank dashboard, which is accessible once the user successfully logs in.&lt;/p&gt;

&lt;p&gt;The&lt;a href="https://github.com/Vonage-Community/blog-sim-swap_verifyv2-javascript-multifactor_authentication/blob/main/public/style.css" rel="noopener noreferrer"&gt; style.css file&lt;/a&gt; contains the styling for both HTML files. You can use the simple styles I've added for this project, or be creative and create your own!&lt;/p&gt;

&lt;h3&gt;
  
  
  Add the &lt;code&gt;client.js&lt;/code&gt; File
&lt;/h3&gt;

&lt;p&gt;In the&lt;a href="https://github.com/Vonage-Community/blog-sim-swap_verifyv2-javascript-multifactor_authentication/blob/main/public/client.js" rel="noopener noreferrer"&gt; client.js file&lt;/a&gt;, we handle what happens when users fill out forms on our website. It manages the steps where users type in their phone numbers and get a verification code if their SIM card hasn't been swapped out recently.&lt;/p&gt;

&lt;p&gt;The script quickly lets users know if they can't be authenticated because of a recent SIM swap or if they will receive a code to proceed with logging in. This ensures that only users with secure accounts can access sensitive features.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Test It Out&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;To see everything in action, start up the application by running:&lt;br&gt;
&lt;code&gt;node server.js&lt;br&gt;
&lt;/code&gt;&lt;br&gt;
Then, open your web browser and navigate to:&lt;br&gt;
&lt;code&gt;http://localhost:3000/&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Here’s what you should expect: imagine you've forgotten your password. Click on 'Forgot Password' to start the recovery. You'll be prompted to enter your phone number and request verification.&lt;/p&gt;

&lt;p&gt;If the application detects a recent SIM swap, a warning pops up: &lt;strong&gt;Warning! A recent SIM pairing change related to the User’s mobile account occurred. Proceed?"&lt;/strong&gt; If you didn't initiate this swap, and you choose 'No, it wasn't me', it's a sign there might be fraud happening with your number. This is your cue to check in with your mobile provider.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Note: In the demonstration, you're prompted to confirm that you've swapped the SIM card, in a real-life scenario likely the user would be invited to directly contact the service provider for additional identity checks.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;S﻿imilarly, this approach could be applied to multifactor authentication on log in, where a check would occur before sending the one-time token, and if a recent SIM swap is detected, user would be invited to directly contact the service provider for additional identity checks.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;On the other hand, if you swapped your SIM and selected 'Yes, it was me,' the app uses the Verify API to send a verification code to your phone. Enter this code on the next screen and set a new password. Once that's done, you can use your new credentials to log into your simulated bank account.&lt;/p&gt;

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

&lt;p&gt;Congratulations, you've reached the end of this tutorial! You've learned to use the Verify API to verify a token and the SIM Swap API to detect if the phone number was swapped in the last few days.&lt;/p&gt;

&lt;p&gt;If you have further questions, contact&lt;a href="https://developer.vonage.com/en/community/slack" rel="noopener noreferrer"&gt; Vonage Community Slack&lt;/a&gt; or&lt;a href="https://www.twitter.com/VonageDev" rel="noopener noreferrer"&gt; message us on X&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Read Further&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Check out the blog post:&lt;a href="https://developer.vonage.com/en/verify/code-snippets/check-verification-code-v2?source=verify&amp;amp;lang=javascript" rel="noopener noreferrer"&gt; Check Verification Code&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;You can also learn more about the&lt;a href="https://developer.vonage.com/en/sim-swap/overview" rel="noopener noreferrer"&gt; SIM Swap API&lt;/a&gt; in our Developer Documentation.&lt;/p&gt;

&lt;p&gt;Learn about&lt;a href="https://developer.vonage.com/en/blog/getting-started-with-sim-swap-api" rel="noopener noreferrer"&gt; Getting Started with The SIM Swap API&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>simswap</category>
    </item>
    <item>
      <title>Send SMS Messages with Cloud Functions For Firebase Gen 2</title>
      <dc:creator>Amanda Cavallaro</dc:creator>
      <pubDate>Thu, 11 Apr 2024 09:53:37 +0000</pubDate>
      <link>https://dev.to/vonagedev/send-sms-messages-with-cloud-functions-for-firebase-gen-2-46an</link>
      <guid>https://dev.to/vonagedev/send-sms-messages-with-cloud-functions-for-firebase-gen-2-46an</guid>
      <description>&lt;h2&gt;
  
  
  Overview
&lt;/h2&gt;

&lt;p&gt;W﻿e have a tutorial on &lt;a href="https://developer.vonage.com/en/blog/send-and-receive-sms-messages-with-firebase-functions-dr" rel="noopener noreferrer"&gt;How to Send and Receive SMS With Firebase Functions&lt;/a&gt;; this blog post tackles the same use case. However, we will create and deploy a second-generation HTTP function using the Google Cloud console and the &lt;a href="https://developer.vonage.com/en/messages/overview?source=messages" rel="noopener noreferrer"&gt;Vonage Messages API&lt;/a&gt; instead of the &lt;a href="https://developer.vonage.com/en/messaging/sms/overview" rel="noopener noreferrer"&gt;SMS API&lt;/a&gt;.&lt;/p&gt;

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

&lt;p&gt;You will need a few items to get going:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://console.firebase.google.com" rel="noopener noreferrer"&gt;Firebase project&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dashboard.nexmo.com" rel="noopener noreferrer"&gt;Vonage API credentials&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Firebase Setup
&lt;/h3&gt;

&lt;p&gt;Create a Firebase project in the &lt;a href="https://console.firebase.google.com" rel="noopener noreferrer"&gt;Firebase console&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Give your project a name that will generate a project ID that you will later choose from the terminal/ command prompt.&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%2Fqvgmxo2rz0s3eu25hqqi.jpg" 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%2Fqvgmxo2rz0s3eu25hqqi.jpg" alt="project creation" width="800" height="527"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you use Google Analytics, I will not do this project.&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%2F28p12xnuizmwozjuyafp.jpg" 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%2F28p12xnuizmwozjuyafp.jpg" alt="Google Analytics" width="800" height="692"&gt;&lt;/a&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%2Fwhp5t7ndl98dpqbaf45m.jpg" 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%2Fwhp5t7ndl98dpqbaf45m.jpg" alt="Wait for project creation" width="800" height="443"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Note: Remember to choose the pay-as-you-go billing plan; otherwise, you might get an error similar to "Error: Your project  must be on the Blaze (pay-as-you-go) plan to complete this command. Required API artifactregistry.googleapis.com can't be enabled until the upgrade is complete."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Install the Firebase CLI from the command prompt/ terminal:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-g&lt;/span&gt; firebase-tools
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Login and initialize your project from the command prompt/ terminal:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;firebase login
firebase init
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You will be prompted to select diverse options, as seen below.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;? Which Firebase features do you want to set up for this directory? Press Space to select features, then Enter to confirm your choices.&lt;/strong&gt; Realtime Database: Configure a security rules file for Realtime Database and (optionally) provision default instance, Functions: Configure a Cloud Functions directory and its files&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;? Please select an option: Use an existing project ? Select a default Firebase project for this directory:&lt;/strong&gt; vonage-sms-project (vonage-sms-project) (Select here the name of the project you have created. In my case, it is vonage-sms-project (vonage-sms-project)&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;? It seems like you haven’t initialized Realtime Database in your project yet. Do you want to set it up? (Y/n)&lt;/strong&gt; Choose Y&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;? Please choose the location for your default Realtime Database instance:&lt;/strong&gt; &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;us-central1&lt;/strong&gt; &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;❯ europe-west1&lt;/strong&gt; &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;asia-southeast1&lt;/strong&gt; &lt;/p&gt;

&lt;p&gt;I﻿n my case Europe-west1 is the closest to me; choose the one that makes more sense to you.  &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;? What file should be used for Realtime Database Security Rules?&lt;/strong&gt; (database.rules.json)&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;? What language would you like to use to write Cloud Functions? (Use arrow keys)&lt;/strong&gt; &lt;/p&gt;

&lt;p&gt;❯ JavaScript  (Choose JavaScript)&lt;/p&gt;

&lt;p&gt;TypeScript &lt;/p&gt;

&lt;p&gt;Python&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;? Do you want to use ESLint to catch probable bugs and enforce style?&lt;/strong&gt; (y/N)&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;? Do you want to install dependencies with npm now? (Y/n)&lt;/strong&gt;  ChooseYes. And wait for the dependencies to be installed.&lt;/p&gt;

&lt;p&gt;This will set up the required folders and files to get started.&lt;/p&gt;

&lt;h3&gt;
  
  
  Enable Google Cloud APIs
&lt;/h3&gt;

&lt;p&gt;From the Google Cloud Console, &lt;a href="https://console.cloud.google.com/flows/enableapi?apiid=cloudfunctions,cloudbuild.googleapis.com,artifactregistry.googleapis.com,run.googleapis.com,logging.googleapis.com,pubsub.googleapis.com&amp;amp;redirect=https://cloud.google.com/functions/docs/console-quickstart" rel="noopener noreferrer"&gt;enable the Cloud Functions, Cloud Build, Artifact Registry, Cloud Run, Logging, and Pub/Sub APIs&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  First Function: InboundSMS
&lt;/h2&gt;

&lt;p&gt;I’ll show you how to create and deploy the function from the IDE/ code editor. Alternatively, you can &lt;a href="https://cloud.google.com/functions/docs/console-quickstart#create_a_functionahttps://cloud.google.com/functions/docs/console-quickstart#create_a_function" rel="noopener noreferrer"&gt;create functions from the Google Cloud Functions dashboard&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Open &lt;a href="https://github.com/Vonage-Community/blog-sms_api-firebase_functions/blob/master/functions/index_second_generation.js" rel="noopener noreferrer"&gt;functions/index.js&lt;/a&gt;, delete all the code you can see and add the following code to capture incoming SMS messages and log them to the Firebase Realtime Database.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;onRequest&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;firebase-functions/v2/https&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;admin&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;firebase-admin&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nx"&gt;admin&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;initializeApp&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="nx"&gt;exports&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;inboundSMS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;onRequest&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;params&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;admin&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;database&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;ref&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/msgq&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;params&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sendStatus&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Deploy the function from the functions folder.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;firebase deploy &lt;span class="nt"&gt;--only&lt;/span&gt; functions
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After the function is deployed, you will be given an HTTP URL needed to add to our webhook in the Vonage setup in the next session. It should look like something along the lines of &lt;a href="https://us-central1-vonage-project.cloudfunctions.net/inboundSMS" rel="noopener noreferrer"&gt;https://us-central1-vonage-project.cloudfunctions.net/inboundSMS&lt;/a&gt;; or &lt;a href="https://inboundsms-njjebckulq-uc.a.run.app" rel="noopener noreferrer"&gt;https://inboundsms-njjebckulq-uc.a.run.app&lt;/a&gt;. &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Note: Note it because we will need it soon. In case you didn’t make a note of it, you can go to the &lt;a href="https://console.cloud.google.com/functions/list" rel="noopener noreferrer"&gt;Google Cloud Functions Overview page&lt;/a&gt;, click on the inboundSMS function, and you can find the URL right at the top.&lt;/p&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%2Fxmqbxe4v77q9bee2cc8d.jpg" 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%2Fxmqbxe4v77q9bee2cc8d.jpg" alt="You can find the URL right at the top" width="800" height="582"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Vonage Setup
&lt;/h2&gt;



&lt;p&gt;From the Vonage Dashboard, set the webhook URL for your number to the function endpoint URL from deployment. It should look like something along the lines of &lt;a href="https://us-central1-vonage-project.cloudfunctions.net/inboundSMS" rel="noopener noreferrer"&gt;https://us-central1-vonage-project.cloudfunctions.net/inboundSMS&lt;/a&gt; or &lt;a href="https://inboundsms-njjebckulq-uc.a.run.app" rel="noopener noreferrer"&gt;https://inboundsms-njjebckulq-uc.a.run.app&lt;/a&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%2Fp2exjfsojw34y5gz94bp.jpg" 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%2Fp2exjfsojw34y5gz94bp.jpg" alt="Inbound SMS URL added to inbound and status" width="614" height="816"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Install the &lt;a href="https://github.com/Vonage/vonage-node-sdk" rel="noopener noreferrer"&gt;Vonage Server SDK for Node.js (@vonage/server-sdk)&lt;/a&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt; @vonage/server-sdk
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next, add dotenv to the dependency list.&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 dotenv --save
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Add a file named &lt;code&gt;.env&lt;/code&gt; with your Vonage credentials, which can be found in the &lt;a href="https://dashboard.nexmo.com" rel="noopener noreferrer"&gt;Vonage Dashboard&lt;/a&gt;, and add the following environment variables:&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%2Fomcpdqf9inxxlurwlwpf.jpg" 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%2Fomcpdqf9inxxlurwlwpf.jpg" alt="Vonage Dashboard, red arrows showing where to find the API Key and the API Secret" width="800" height="374"&gt;&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;VONAGE_API_KEY&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;
&lt;span class="nv"&gt;VONAGE_API_SECRET&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;
&lt;span class="nv"&gt;VONAGE_APPLICATION_ID&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;
&lt;span class="nv"&gt;VONAGE_PRIVATE_KEY&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A﻿dd Vonage to your &lt;code&gt;functions/index.js&lt;/code&gt; file.&lt;br&gt;
&lt;/p&gt;

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

const vonage = new Vonage({
  apiKey: VONAGE_API_KEY,
  apiSecret: VONAGE_API_SECRET,
  applicationId: VONAGE_APPLICATION_ID,
  privateKey: VONAGE_PRIVATE_KEY
});
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Make sure there's a phone number linked to this application.&lt;/p&gt;

&lt;p&gt;Send an SMS to the virtual phone number you purchased and linked to this application. &lt;/p&gt;

&lt;p&gt;If you head for your Firebase Realtime database on the dashboard, you can see the &lt;code&gt;msgq&lt;/code&gt; node has been updated with the message you sent from your phone.&lt;/p&gt;

&lt;h2&gt;
  
  
  Second Function: SendSMS
&lt;/h2&gt;

&lt;p&gt;Add the send function that will allow us to send the &lt;a href="https://developer.vonage.com/en/tutorials/send-sms-with-messages/send-sms?lang=javascript" rel="noopener noreferrer"&gt;SMS Message Using the Vonage Messages API&lt;/a&gt; that will be logged in the Firebase Realtime database.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;SMS&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@vonage/messages&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;onValueCreated&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;firebase-functions/v2/database&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; 

&lt;span class="nx"&gt;exports&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;sendSMS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;onValueCreated&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/msgq/{pushId}&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;text&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;val&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

  &lt;span class="nx"&gt;vonage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;messages&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;SMS&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
        &lt;span class="na"&gt;text&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;to&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;from&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Vonage APIs&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="p"&gt;})&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;resp&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;resp&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;catch&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Deploy the functions again from the functions folder.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;firebase deploy &lt;span class="nt"&gt;--only&lt;/span&gt; functions
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Send an SMS to the virtual phone number you purchased and linked to this application. &lt;/p&gt;

&lt;p&gt;If you head for your Firebase Realtime database on the dashboard, you can see the &lt;code&gt;msgq&lt;/code&gt; node has been updated with the message you sent from your phone.&lt;/p&gt;

&lt;p&gt;When a new message is added to &lt;code&gt;/msgq&lt;/code&gt;, this function will be triggered. It will use the Vonage Messages API to respond to the user. The messages sent and submitted will be logged in our Firebase Realtime database.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Note: If you get an error message “Error: secretOrPrivateKey must be an asymmetric key when using ES256” make sure your private key is valid and correct and being imported correctly.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Test it Out
&lt;/h2&gt;

&lt;p&gt;After it is deployed, test it out by sending an SMS message to the number linked to the Vonage application, and you will see the message added to the Firebase Realtime database.&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%2F776dwr55te7uzpw03x7s.jpg" 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%2F776dwr55te7uzpw03x7s.jpg" alt="Realtime database containing three nodes under msgq" width="800" height="698"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  C﻿onclusion
&lt;/h2&gt;

&lt;p&gt;Now, you can send and receive SMS messages using Firebase Cloud Functions Gen 2 and the Vonage Messages API! You have now completed all the steps for this tutorial. &lt;a href="https://github.com/Vonage-Community/blog-sms_api-firebase_functions/blob/master/functions/index_second_generation.js" rel="noopener noreferrer"&gt;You can see the full code on GitHub&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Do you have any questions about this blog post? Join our &lt;a href="https://developer.vonage.com/en/community/slack" rel="noopener noreferrer"&gt;Vonage Community Slack&lt;/a&gt; or &lt;a href="https://www.twitter.com/VonageDev" rel="noopener noreferrer"&gt;message us on X&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>firebase</category>
      <category>javascript</category>
    </item>
    <item>
      <title>Build an Escape Plan With the Vonage Voice API and Get a Ghost Call</title>
      <dc:creator>Amanda Cavallaro</dc:creator>
      <pubDate>Wed, 13 Mar 2024 16:57:39 +0000</pubDate>
      <link>https://dev.to/vonagedev/build-an-escape-plan-with-the-vonage-voice-api-and-get-a-ghost-call-2m3m</link>
      <guid>https://dev.to/vonagedev/build-an-escape-plan-with-the-vonage-voice-api-and-get-a-ghost-call-2m3m</guid>
      <description>&lt;h2&gt;
  
  
  Overview
&lt;/h2&gt;

&lt;p&gt;In this tutorial, I'll show you how to use the &lt;a href="https://developer.vonage.com/en/voice/voice-api/overview" rel="noopener noreferrer"&gt;Vonage Voice API&lt;/a&gt; to create a subtle way to excuse yourself from a situation you'd rather not be in. You can trigger a ghost call by sending an SMS to a virtual number!&lt;/p&gt;

&lt;p&gt;This &lt;a href="https://github.com/Vonage-Community/blog-voice-api_sms-node-ghost_call" rel="noopener noreferrer"&gt;project's code is on GitHub&lt;/a&gt;.&lt;/p&gt;

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

&lt;p&gt;Before starting to build the project, ensure you have:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A &lt;a href="https://dashboard.nexmo.com/sign-up" rel="noopener noreferrer"&gt;Vonage developer account&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Node.js and npm &lt;a href="https://nodejs.org/en/download/" rel="noopener noreferrer"&gt;installed on your machine&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://ngrok.com/download" rel="noopener noreferrer"&gt;Ngrok&lt;/a&gt; for creating a secure tunnel to your localhost.&lt;/li&gt;
&lt;li&gt;A text editor and basic JavaScript knowledge.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Use Ngrok to Expose Your Local Server
&lt;/h2&gt;

&lt;p&gt;Ngrok exposes your local webhooks on the public internet and allows you to receive external calls on them:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Start ngrok with &lt;code&gt;ngrok http 3000&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Note the HTTPS forwarding address (e.g., &lt;code&gt;https://xyz.ngrok.com&lt;/code&gt;).&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Setting Up the Vonage Application
&lt;/h2&gt;



&lt;p&gt;After signing up for a Vonage account:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Create a New Application:&lt;/strong&gt; Go to &lt;a href="https://dashboard.nexmo.com/applications" rel="noopener noreferrer"&gt;'Your Applications'&lt;/a&gt; in the dashboard and toggle the Voice and Messages capabilities.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Generate Credentials:&lt;/strong&gt; Create a public/private key pair for API authentication; this will download a &lt;code&gt;private.key&lt;/code&gt; to be added to our project folder.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Link a Virtual Number:&lt;/strong&gt; &lt;a href="https://developer.vonage.com/en/numbers/code-snippets/buy#buy-a-number" rel="noopener noreferrer"&gt;Acquire and link a virtual number&lt;/a&gt; to your application.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Configure Webhooks:&lt;/strong&gt; Set your server's public URL from ngrok as the endpoint for inbound messages and events. it should look like: &lt;a href="https://xyz.ngrok.com/inbound" rel="noopener noreferrer"&gt;https://xyz.ngrok.com/inbound&lt;/a&gt; for inbound and &lt;a href="https://xyz.ngrok.com/event" rel="noopener noreferrer"&gt;https://xyz.ngrok.com/event&lt;/a&gt; for events. &lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;![Messages Inbound and Status URLs. It shows that the Inbound URL and the Status URL should be filled with the ngrok url followed by /inbound and /status respectively]&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%2Fjzijfo7gsrrm30iq9cel.jpg" 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%2Fjzijfo7gsrrm30iq9cel.jpg" alt="Messages Inbound and Status URLs" width="800" height="669"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Server-Side Implementation
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Initial Project Setup
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Create a New Project Directory:&lt;/strong&gt;
Open your terminal and navigate where you want to create your new project. Then, use the following command to create and change to a new directory for your project:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;   &lt;span class="nb"&gt;mkdir &lt;/span&gt;vonage-ghost-call &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;cd &lt;/span&gt;vonage-ghost-call
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Initialize a Node.js Project:&lt;/strong&gt;
In your new project directory, initialize a Node.js project. This will create a &lt;code&gt;package.json&lt;/code&gt; file that manages your project's dependencies and scripts. Use the &lt;code&gt;npm init&lt;/code&gt; command to specify details or press Enter to accept defaults. The &lt;code&gt;-y&lt;/code&gt; flag automatically fills in the defaults without asking for the details.
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;   npm init &lt;span class="nt"&gt;-y&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Install the Dependencies:&lt;/strong&gt;
Now, it's time to install the dependencies required for the project:&lt;/li&gt;
&lt;/ol&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;express&lt;/code&gt;: A web framework for Node.js.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;dotenv&lt;/code&gt;: Used to load environment variables from a &lt;code&gt;.env&lt;/code&gt; file.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;@vonage/server-sdk&lt;/code&gt;: The Vonage Server SDK for Node.js.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;@vonage/voice&lt;/code&gt;: The Vonage Voice API SDK.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;To install all these in one go, run the following command, which will automatically add these packages to your &lt;code&gt;package.json&lt;/code&gt; file and add them to your project's &lt;code&gt;node_modules&lt;/code&gt; directory.&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;h2&gt;
  
  
  Create the Environment Variables File
&lt;/h2&gt;

&lt;p&gt;Create a &lt;code&gt;.env&lt;/code&gt; file in your project and add the following environment found in the code snippet below. &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The &lt;code&gt;VONAGE_KEY&lt;/code&gt; and &lt;code&gt;VONAGE_SECRET&lt;/code&gt; can be found on the &lt;a href="https://dashboard.nexmo.com/" rel="noopener noreferrer"&gt;Vonage Dashboard&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;![Vonage Dashboard. It shows where the API Key and API Secrets are. Right under the text 'API key and API Secret']&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%2F7uiok547um4m5s6y2bnh.jpg" 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%2F7uiok547um4m5s6y2bnh.jpg" alt="Vonage Dashboard" width="800" height="374"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The &lt;code&gt;VONAGE_APPLICATION_ID&lt;/code&gt; can be found in the application you have created, which can be found in the &lt;a href="https://dashboard.nexmo.com/applications" rel="noopener noreferrer"&gt;Vonage Applications&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;FROM_IMPORTANT_FRIEND&lt;/code&gt; is the phone number for the phone call.&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;ANSWER_URL&lt;/code&gt; determines how to handle a call and who to connect the call to. It does that by executing an NCCO that utilizes numerous capabilities of the Voice API; an example value could be &lt;code&gt;https://raw.githubusercontent.com/nexmo-community/ncco-examples/gh-pages/text-to-speech.json&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;PRIVATE_KEY_PATH&lt;/code&gt; is the path of the &lt;code&gt;private.key&lt;/code&gt; file we downloaded earlier when we generated the public/private key pair for API authentication.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;VONAGE_KEY&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;
&lt;span class="nv"&gt;VONAGE_SECRET&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;
&lt;span class="nv"&gt;VONAGE_APPLICATION_ID&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;
&lt;span class="nv"&gt;PRIVATE_KEY_PATH&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;
&lt;span class="nv"&gt;ANSWER_URL&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;
&lt;span class="nv"&gt;FROM_IMPORTANT_FRIEND&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Implement the Server Side Code
&lt;/h2&gt;

&lt;p&gt;In your &lt;a href="https://github.com/Vonage-Community/blog-voice-api_sms-node-ghost_call/blob/main/index.js" rel="noopener noreferrer"&gt;&lt;code&gt;index.js&lt;/code&gt; file&lt;/a&gt;, start the project by importing the required modules. You'll set up Express to handle incoming HTTP requests and configure the Vonage client with credentials stored in your environment variables:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Import dependencies&lt;/span&gt;
&lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;dotenv&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;config&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;express&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;express&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Vonage&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@vonage/server-sdk&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;app&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;express&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="c1"&gt;// Middleware for parsing incoming requests&lt;/span&gt;
&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;use&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;express&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;use&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;express&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;urlencoded&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;extended&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt; &lt;span class="p"&gt;}));&lt;/span&gt;

&lt;span class="c1"&gt;// Initialize Vonage API client with environment variables&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;vonage&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Vonage&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;apiKey&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;VONAGE_KEY&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;apiSecret&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;VONAGE_SECRET&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;applicationId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;VONAGE_APPLICATION_ID&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;privateKey&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;PRIVATE_KEY_PATH&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Handle Inbound SMS Messages
&lt;/h3&gt;

&lt;p&gt;The server is listening for new SMS messages to come in. When the server gets a new SMS message, it makes an outbound phone call to the phone number that sent the SMS message. This is contained in the server code's &lt;code&gt;/inbound&lt;/code&gt; part.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Route to handle inbound SMS&lt;/span&gt;
&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/inbound&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;requesterNumber&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="c1"&gt;// Function to trigger an outbound call&lt;/span&gt;
  &lt;span class="nf"&gt;triggerOutboundCall&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;requesterNumber&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;status&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;end&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="c1"&gt;// Server listens to a specified port&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;PORT&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;PORT&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="mi"&gt;3000&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;listen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;PORT&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`App listening on port &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;PORT&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Outbound Call Without NCCO
&lt;/h3&gt;

&lt;p&gt;If you need to make an outbound call with a pre-recorded message, you can make the call without specifying an &lt;a href="https://developer.vonage.com/en/voice/voice-api/concepts/call-control-objects" rel="noopener noreferrer"&gt;NCCO&lt;/a&gt;. The Voice API lets you directly initiate an outbound call and play an audio file to the recipient without configuring advanced call control logic.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;triggerOutboundCall&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;requesterNumber&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;ANSWER_URL&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ANSWER_URL&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// URL to NCCO JSON&lt;/span&gt;

  &lt;span class="nx"&gt;vonage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;voice&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createOutboundCall&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;to&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[{&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;phone&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;number&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;requesterNumber&lt;/span&gt; &lt;span class="p"&gt;}],&lt;/span&gt;
    &lt;span class="na"&gt;from&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;phone&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;number&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;FROM_IMPORTANT_FRIEND&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="na"&gt;answer_url&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;ANSWER_URL&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="nx"&gt;handleResponse&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;handleResponse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;resp&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;resp&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this setup, &lt;code&gt;ANSWER_URL&lt;/code&gt; points to a JSON file that dictates the call flow. For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"action"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"talk"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"voiceName"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Amy"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"text"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"There's an urgent need for you elsewhere. Please excuse yourself."&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Outbound Call With NCCO
&lt;/h3&gt;

&lt;p&gt;For a more tailored call experience, NCCO provides greater flexibility. This is especially useful for dynamic call flows.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;makeCallWithNCCO&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;requesterNumber&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;ncco&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;action&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;talk&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;voiceName&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Amy&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;text&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Hey, sorry to bother you, but I need your help; an urgent unforeseen circumstance has happened.&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; 
  &lt;span class="p"&gt;];&lt;/span&gt;

  &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;resp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;vonage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;calls&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="na"&gt;to&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[{&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;phone&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;requesterNumber&lt;/span&gt; &lt;span class="p"&gt;}],&lt;/span&gt;
      &lt;span class="na"&gt;from&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;phone&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;number&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;FROM_IMPORTANT_FRIEND&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
      &lt;span class="nx"&gt;ncco&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;resp&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This function &lt;code&gt;makeCallWithNCCO&lt;/code&gt; dynamically creates the call flow based on the NCCO specifications.&lt;/p&gt;

&lt;p&gt;In this example, the &lt;code&gt;ncco&lt;/code&gt; variable holds an array of actions to control the call. The &lt;a href="https://developer.vonage.com/en/voice/voice-api/ncco-reference#talk" rel="noopener noreferrer"&gt;&lt;code&gt;talk&lt;/code&gt; action&lt;/a&gt; reads a message when the call is answered.&lt;/p&gt;

&lt;h3&gt;
  
  
  Steps to Run the Application
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Ensure &lt;code&gt;.env&lt;/code&gt; has all credentials.&lt;/li&gt;
&lt;li&gt;Start the server by running the &lt;code&gt;node index.js&lt;/code&gt; command.&lt;/li&gt;
&lt;li&gt;Send an SMS message to your virtual number to trigger the ghost call!&lt;/li&gt;
&lt;li&gt;The app will place a call with your chosen method - get ready to have a reason to leave that situation you didn’t want to be in!&lt;/li&gt;
&lt;/ol&gt;

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

&lt;p&gt;Today, you've learned how to avoid personal convenience. By sending an SMS message, you can trigger a call that provides a plausible reason to step out of that situation you don’t want to be in using JavaScript, Node.js, and the Vonage Voice API.&lt;/p&gt;

&lt;p&gt;This &lt;a href="https://github.com/Vonage-Community/blog-voice-api_sms-node-ghost_call" rel="noopener noreferrer"&gt;project's code is on GitHub&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Join the discussion and share your insights with us in the &lt;a href="https://developer.vonage.com/en/community/slack" rel="noopener noreferrer"&gt;Vonage Developer Community on Slack&lt;/a&gt; or &lt;a href="https://twitter.com/vonagedev" rel="noopener noreferrer"&gt;follow us on X, previously known as Twitter&lt;/a&gt;!&lt;/p&gt;

</description>
      <category>node</category>
      <category>javascript</category>
      <category>vonage</category>
    </item>
    <item>
      <title>Being a First-Time Mom in Developer Relations</title>
      <dc:creator>Amanda Cavallaro</dc:creator>
      <pubDate>Wed, 06 Mar 2024 11:34:20 +0000</pubDate>
      <link>https://dev.to/vonagedev/being-a-first-time-mom-in-developer-relations-549n</link>
      <guid>https://dev.to/vonagedev/being-a-first-time-mom-in-developer-relations-549n</guid>
      <description>&lt;h2&gt;
  
  
  Life before the Baby
&lt;/h2&gt;

&lt;p&gt;Ever since I was 17, I have lived a busy life juggling work, studies, and volunteer activities. My days were filled with productivity, and my free time was spent resting. I relished the freedom to control my schedule, working whenever I pleased. But then, life threw me a beautiful curveball.&lt;/p&gt;

&lt;h2&gt;
  
  
  I Am Pregnant! Now What?
&lt;/h2&gt;

&lt;p&gt;When I found out I would have a baby, my head was spinning with so many thoughts and worries. My big question was: how will this affect my job? Like many women, I shared the fear of informing my boss and colleagues about my pregnancy. I was concerned about falling behind in my team's work, keeping up with the broader tech industry, and catching up when I returned from maternity leave. Thankfully, I was lucky to have a team that cares about work-life balance and the well-being of its members. &lt;/p&gt;

&lt;h3&gt;
  
  
  Conversations with Manager, HR, and the Team
&lt;/h3&gt;

&lt;p&gt;My manager cultivated a culture of support and understanding within the team, making it easier for me to confide in him during the early months of my pregnancy. I felt shielded and protected, knowing I could count on my team's understanding and support. Balancing impending motherhood with work commitments was challenging, but with their assistance, I successfully managed to navigate this delicate phase.&lt;/p&gt;

&lt;p&gt;I attended some meetings without turning my camera on and would ask to reschedule for some meetings when I wasn’t feeling my best. The team assigned me to work on some projects that took place during my maternity leave; at the time, they didn't know about my pregnancy, and I wasn't ready to share the big news yet. I didn’t want them to count on me for something I knew I couldn’t commit to, so my manager helped me shift some responsibilities without sharing the news with the broader team before I was ready to do so.&lt;/p&gt;

&lt;h3&gt;
  
  
  Telling the Developer Relations Team the Big News
&lt;/h3&gt;

&lt;p&gt;When the time came to share my exciting news with the entire developer relations team, I was well-prepared. I had a plan in place that would allow our team workflow to be prepared and continue running smoothly; I prepared hands-off documents, and I made sure all my responsibilities would have enough people to look after them. When I shared the news, the moment grew even more special as I received heartwarming responses, later followed by thoughtful gifts and sweet messages.&lt;/p&gt;

&lt;h2&gt;
  
  
  What About My Studies?
&lt;/h2&gt;

&lt;p&gt;Navigating university while pregnant was tough, especially at the beginning when I didn't know how to handle the changes. The first thing to suffer was my time management, and the struggle was real. &lt;/p&gt;

&lt;p&gt;The thought of pausing my studies crossed my mind as I grappled with the challenges. I wanted to finish my post-graduate degree in Full Stack Web Development before the baby came. Gradually, I started learning to adapt and even reclaimed some of my time even when the struggles of studying some days with morning sickness and fatigue felt so hard.&lt;/p&gt;

&lt;p&gt;The support from my family, friends, and understanding coworkers was invaluable. Despite the difficulties, I kept going and proudly graduated with my big pregnant belly!&lt;/p&gt;

&lt;h2&gt;
  
  
  Being on Maternity Leave and Being Able to Disconnect
&lt;/h2&gt;

&lt;p&gt;I decided to save most of my vacation days for the period leading up to my parental leave. This strategy extended my leave and proved invaluable during the challenging final months of my pregnancy. Disconnecting from work was difficult for someone used to constant productivity because, on many levels, my coworkers became an extended circle of friends, and I found myself missing those interactions and the daily structure that work provides. However, I quickly found myself immersed in preparing for my baby's arrival.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Baby Is Here!
&lt;/h2&gt;

&lt;p&gt;The arrival of our baby brought immense joy, with grandparents and relatives traveling from afar to meet the newest member of our family. Due to COVID and a desire to keep her safe, we limited her early interactions, venturing out only for peaceful walks in our neighborhood and occasional virtual video introductions.&lt;/p&gt;

&lt;h2&gt;
  
  
  Coming Back to Work
&lt;/h2&gt;

&lt;p&gt;During the last months of my leave, I had some check-in meetings with my manager, where we caught up and created a plan on what I would work on when I returned to work. It was imperative to me not to go back to work on the first day and feel overwhelmed or left behind, so together, we agreed on the work I would prioritize when coming back. That helped build my confidence, and when my leave was coming to an end, I felt so ready to be back!&lt;/p&gt;

&lt;p&gt;I set up my breast pump on the computer table and took the necessary breaks. I also had numerous one-on-one meetings with my team members to share my news, catch up on the latest features and announcements, and found time to watch the weekly meeting recordings.&lt;/p&gt;

&lt;h2&gt;
  
  
  She Went on Stage as a Keynote Co-speaker
&lt;/h2&gt;

&lt;p&gt;My baby girl joined me on stage as I presented my journey in tech during the keynote of the Women Techmakers International Women’s Day in London. Sharing my story about becoming a mom in tech was an emotional experience, and her presence added a beautiful touch to the moment.&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%2F3aepqkg7kzqk16ioyy3q.jpg" 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%2F3aepqkg7kzqk16ioyy3q.jpg" alt="Screenshot of a twitter post, link below" width="800" height="757"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Source - &lt;a href="https://twitter.com/WomenTechmakers/status/1646589095152369664" rel="noopener noreferrer"&gt;X&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  New Doors Opened for Me to Think of Inclusion
&lt;/h2&gt;

&lt;p&gt;Becoming a mother fundamentally changed my perspective on tech events. Aspects I hadn't thought about pre-parenthood, like broader accessibility, the availability of parents' rooms, and baby-friendly environments, suddenly became crucial. This shift in focus not only influenced my own experiences but also inspired me to advocate for more inclusive spaces within the tech community, ensuring they cater to the needs of parents and their children.&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%2Frvv09q1dgcup11n7fmzj.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%2Frvv09q1dgcup11n7fmzj.png" alt="Mom and daughter wearing avocado socks" width="600" height="200"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Traveled to Prague with a Baby
&lt;/h2&gt;

&lt;p&gt;My good friend &lt;a href="https://twitter.com/puf" rel="noopener noreferrer"&gt;puf&lt;/a&gt; invited me to speak at the &lt;a href="https://f3.events/" rel="noopener noreferrer"&gt;Flutter Firebase Festiva&lt;/a&gt;l and I took on the traveling with a baby challenge, and I embarked on a journey to Prague with my little one in tow. I was exposed to a plethora of new experiences.&lt;/p&gt;

&lt;h3&gt;
  
  
  Planning for the Trip
&lt;/h3&gt;

&lt;p&gt;As a frequent traveler for both personal and business purposes, I prided myself on being a light packer, efficiently organizing and packing what is important with room to bring souvenirs back. However, when the baby came, prioritizing what to pack, what to bring onboard, and how to best store and prepare baby food, among several other things, took it to a whole other level. I had fun in the process and learned a lot, but it was different from what I would call an easy experience.&lt;/p&gt;

&lt;h3&gt;
  
  
  Being with the Baby at the Tech Events
&lt;/h3&gt;

&lt;p&gt;I brought her to the speaker’s dinner. I was positively overwhelmed with kindness and people offering to help if I needed anything; the same occurred throughout the festival.&lt;/p&gt;

&lt;p&gt;I brought her to the keynote and took turns sitting down and letting her walk around on the floor. I sat in the back of the room near the exit in case she needed more attention. That way I could easily leave the room. It turned out that the only times you could hear her excitement was during the keynote moments when everyone was cheering, so she also wanted to show everyone her clapping skills and shout in excitement!&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%2F94zfvlwhsbmvj2l0vwt8.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%2F94zfvlwhsbmvj2l0vwt8.png" alt="A baby behind an audience watching the keynote" width="800" height="600"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It turns out that having a baby at a conference is an icebreaker, as I had so many interesting conversations from her being there! The conversations ranged from people saying, “You inspired me to bring my kids,” to “I got tired of seeing everything you had to do for your baby. For the next event, I don’t even want to bring mine”.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Actual Talk and Having the Baby on Stage
&lt;/h3&gt;

&lt;p&gt;I gave a talk with my baby co-speaker and awesome &lt;a href="https://twitter.com/ManuSakuraRo" rel="noopener noreferrer"&gt;Manuela&lt;/a&gt; about building an appointment scheduler using Firebase. I explained the implementation in JavaScript and demonstrated how to use the Vonage APIs to receive SMS messages on their devices; Manuela showed the same experience using Flutter.&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%2Fwnjtmg4msq6hgdtoov88.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%2Fwnjtmg4msq6hgdtoov88.png" alt="Two women and a baby on stage giving away swag and one man standing in front of them. Everyone is laughing." width="800" height="532"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I brought a baby carrier that only had a bottom base, without the arm straps, to make it easy to hand my baby over to my good friend Laura. &lt;a href="https://twitter.com/thisislalaok" rel="noopener noreferrer"&gt;Laura&lt;/a&gt;, who was also a speaker at the event, agreed to sit in the front row, ready to take the baby if she grew tired on stage. As expected, the baby needed a break at one point, and Laura took care of her. However, by the end of the talk, the baby was back on stage with me for the question and answer session and to help give away swag!&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%2Fogwg4d6jio6in0ihztp3.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%2Fogwg4d6jio6in0ihztp3.png" alt="Baby giving away swag to an attendee. Two women speakers on stage. One woman is holding the baby." width="800" height="532"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Support From the Community
&lt;/h3&gt;

&lt;p&gt;The support I received from the community was heartwarming. Fellow attendees offered to help with my baby, ensuring I could eat and take breaks. This sense of camaraderie reinforced my belief in the power of community within the tech industry. I engaged in so many exciting conversations about people telling me how they felt inspired to also bring their little ones to future tech events they are going to attend, and people who asked to share tips as to what’s like to travel to a baby, what to pack, what to have in mind, etc. This exchange of experiences was enriching for all the parties!&lt;/p&gt;

&lt;p&gt;When I returned home, I received this supportive message from puf. Ps. my nickname is ‘Chibi’:&lt;/p&gt;

&lt;p&gt;“Chibi! I hope you and Marina (you'll have to imagine my best rolling r) made it home safely last night - and that at least one of you is soundly sleeping. What an adventure you've been on!&lt;/p&gt;

&lt;p&gt;Marina's first flight, your first tech talk abroad since becoming a mom, and introducing her to the Flutter ＆ Firebase communities with such pizzaz. Sure, she's the cutest kid in the world, we all know that. But you're the one who decided to take all the plunges this trip and changed the shape of the event for all of us because of that.&lt;/p&gt;

&lt;p&gt;I am so proud of you. More than that: I'm grateful, so incredibly grateful. Thank you! 🙏❤️”&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%2Fi6motwrz90eu7inacwu7.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%2Fi6motwrz90eu7inacwu7.png" alt="two women, two men in a circle with a baby in the center of attention" width="510" height="765"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Redefining Time
&lt;/h2&gt;

&lt;p&gt;Motherhood has redefined my concept of time. I no longer solely control my schedule; I now work around my baby's needs and rely on my support network. My daughter has expanded my horizons, making me proud to bring her along on my developer relations journey.&lt;/p&gt;

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

&lt;p&gt;Becoming a mom in developer relations has been a remarkable adventure, reshaping my life and career in ways I never imagined. It has taught me the power of adaptability, community, and inclusivity. My journey as a developer advocate and a mother continues to evolve, and I'm excited to inspire others to embrace their unique paths.&lt;/p&gt;

&lt;p&gt;Are you also a parent in tech? Let me know your journey as well! You are very welcome to join our &lt;a href="https://developer.vonage.com/community/slack" rel="noopener noreferrer"&gt;Vonage Community Slack&lt;/a&gt; or send us a message on &lt;a href="https://twitter.com/VonageDev" rel="noopener noreferrer"&gt;X, formerly known as Twitter&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>devrel</category>
      <category>womenintech</category>
      <category>wecoded</category>
    </item>
    <item>
      <title>Vonage Joins Bots Brasil Conference 2021</title>
      <dc:creator>Amanda Cavallaro</dc:creator>
      <pubDate>Wed, 22 Dec 2021 15:26:04 +0000</pubDate>
      <link>https://dev.to/vonagedev/vonage-joins-bots-brasil-conference-2021-4em</link>
      <guid>https://dev.to/vonagedev/vonage-joins-bots-brasil-conference-2021-4em</guid>
      <description>&lt;h2&gt;
  
  
  Have You Heard of Bots Brasil?
&lt;/h2&gt;

&lt;p&gt;Since 2016, Bots Brasil has been one of the most significant communities in Latin America for conversational interfaces, artificial intelligence, and bots. They have organized events, shared content, and helped professionals and companies in the conversational industry.&lt;/p&gt;

&lt;h2&gt;
  
  
  Bots Brasil 2021 Conference
&lt;/h2&gt;

&lt;p&gt;In 2021, Bots Brasil organized its 4th annual and first remote conference. This year's theme was "bringing conversations together". As the world has had to adapt to the pandemic, there's been a digital transformation on a global scale. The rise of new technologies and new media has brought communications closer to people at scale.&lt;/p&gt;

&lt;p&gt;At Bots Brasil 2021 conference, we explored how the conversational market has helped people and companies to stay close even though they are far away. We were proud to be a gold sponsor.&lt;/p&gt;

&lt;p&gt;There were eight tracks: &lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Careers&lt;/li&gt;
&lt;li&gt;Success Cases and Learnings&lt;/li&gt;
&lt;li&gt;Curatorship and Computational Linguistics&lt;/li&gt;
&lt;li&gt;Diversity and Inclusion&lt;/li&gt;
&lt;li&gt;Artificial Intelligence&lt;/li&gt;
&lt;li&gt;Integration and Development&lt;/li&gt;
&lt;li&gt;Trends and Market&lt;/li&gt;
&lt;li&gt;UX Design and Writing&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Watch the Talks We’ve Given at the Conference
&lt;/h2&gt;

&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/7pEzVf1S410"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;In this session, we learned to build a Facebook Messenger bot with the Vonage Messages API. This bot tells users whether the restaurant is currently delivering. If the restaurant is closed, it notifies the user when deliveries resume.&lt;/p&gt;

&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/t_aBilqUuqg"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;In this session, we discussed the Vonage AI solution and described a use case we have done for the Israeli Employment office, in which we reached over 1 million citizens monthly, using voice and WhatsApp bots. This success story was a great way to understand how to use conversational AI to increase the conversation rate and reduce costs in the business communication world.&lt;/p&gt;

&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/PezL3MzcheA"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;In this session, we looked at how to assign a phone number to a chatbot created using Dialogflow, Google Cloud, Node.js, and Vonage API integrations. The architecture shown allows the user to call their agent by phone and integrate other services such as SMS and WhatsApp.&lt;/p&gt;

&lt;p&gt;There were more than 1500 registrations and 60 live and recorded talks with Brazilian Sign Language (LIBRAS) interpretation. &lt;a href="https://www.youtube.com/playlist?list=PL3j5_lNQE6qW094EBC-rvHPOq7v0RZNBU" rel="noopener noreferrer"&gt;You can check them out in this youtube playlist on Bots Brasil Youtube Channel&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Vonage Booth
&lt;/h2&gt;

&lt;p&gt;Vonage had a booth with Amanda Cavallaro (me!), Daniel Barna, Fábio Flores, and Sidney Gomes during the event's three days. &lt;/p&gt;

&lt;p&gt;We had the opportunity and privilege to talk to different people at different levels in their careers and talk about our APIs and bots from different angles and perspectives.&lt;/p&gt;

&lt;p&gt;It was a very different experience to be in an online stand at a conference compared to the experience of physically being at a booth. We talked to many different people throughout the day like usual, but showing them the demos was a challenge to replicate online. Regardless, we formed new connections and made an impact!&lt;/p&gt;

&lt;p&gt;&lt;a href="/content/blog/vonage-joins-bots-brasil-conference-2021/vonage-feed.png" class="article-body-image-wrapper"&gt;&lt;img src="/content/blog/vonage-joins-bots-brasil-conference-2021/vonage-feed.png" title="Vonage is a sponsor at Bots Brasil 2021 Conference" alt="Vonage's logo inside of a Bots Brasil 2021 Conference layout"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Final Remarks
&lt;/h2&gt;

&lt;p&gt;It was a remarkable experience to be part of the story of the 4th edition of the Bots Brasil Conference, we even created a video in Brazilian Portuguese explaining what our Developer Relations team does here at Vonage. Watch it below if you're interested!&lt;/p&gt;

&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/RsX_rF1ntPU"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;h2&gt;
  
  
  Next Steps
&lt;/h2&gt;

&lt;p&gt;If you'd like to know more about Bots Brasil, &lt;a href="https://linktr.ee/botsbrasil" rel="noopener noreferrer"&gt;check out their LinkTree&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;And if you are interested in bots, please find some links below with content we've covered for you over the years:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://learn.vonage.com/blog/2020/09/09/build-a-whatsapp-currency-conversion-bot-with-node-js/" rel="noopener noreferrer"&gt;Build a WhatsApp Currency Conversion Bot With Node.js&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://learn.vonage.com/blog/2020/06/01/using-dialogflow-with-firebase-and-the-vonage-messages-sandbox-dr/" rel="noopener noreferrer"&gt;Using Dialogflow with Firebase and the Vonage Messages Sandbox&lt;/a&gt;   &lt;/p&gt;

&lt;p&gt;&lt;a href="https://learn.vonage.com/blog/2021/09/02/state-machines-for-messaging-bots/" rel="noopener noreferrer"&gt;State Machines for WhatsApp Messaging Bots with Node.js&lt;/a&gt;  &lt;/p&gt;

&lt;p&gt;&lt;a href="https://learn.vonage.com/blog/2018/07/11/add-two-factor-authentication-to-a-microsoft-bot-with-nexmos-verify-api-dr/" rel="noopener noreferrer"&gt;Add 2FA to a Microsoft bot with Nexmo's Verify API &lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://learn.vonage.com/blog/2018/10/16/build-a-facebook-messenger-bot-with-messages-api-and-dialogflow-dr/" rel="noopener noreferrer"&gt;Build a Facebook Messenger Bot with Messages API and Dialogflow    &lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://learn.vonage.com/blog/2019/07/04/build-an-ivr-with-ruby-on-rails-dr/" rel="noopener noreferrer"&gt;How to Build a Simple IVR with Ruby on Rails&lt;/a&gt;    &lt;/p&gt;

&lt;p&gt;&lt;a href="https://learn.vonage.com/blog/2020/08/12/build-a-simple-customer-support-channel-with-whatsapp/" rel="noopener noreferrer"&gt;Build a Simple Customer Support Channel with WhatsApp&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://learn.vonage.com/blog/2018/07/10/voice-classification-nlp-google-cloud-dr/" rel="noopener noreferrer"&gt;Automatically Classify Call Recordings using NLP&lt;/a&gt;  &lt;/p&gt;

&lt;p&gt;&lt;a href="https://learn.vonage.com/blog/2021/03/10/connecting-voice-calls-to-an-amazon-lex-bot/" rel="noopener noreferrer"&gt;Connecting Voice Calls to an Amazon Lex Bot&lt;/a&gt;    &lt;/p&gt;

&lt;p&gt;&lt;a href="https://learn.vonage.com/blog/2019/04/08/build-interactive-voice-response-node-express-javascript-dr/" rel="noopener noreferrer"&gt;Build an Interactive Voice Response Menu using Node.js and Express&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;&lt;a href="https://learn.vonage.com/blog/2019/06/20/creating-a-complex-ivr-system-with-ease-with-xstate-dr/" rel="noopener noreferrer"&gt;Creating a Complex IVR System with Ease with XState&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;&lt;a href="https://learn.vonage.com/blog/2017/08/31/bots-ai-launching-bot-getting-discovered-dr/" rel="noopener noreferrer"&gt;Bots and AI: Launching a Bot and Getting It Discovered&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;&lt;a href="https://learn.vonage.com/blog/2017/09/07/ai-bot-use-cases-dr/" rel="noopener noreferrer"&gt;Bots and AI: Great Bot Use Cases in Production Today   &lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://learn.vonage.com/blog/2017/09/14/ai-bot-messaging-push-notifications-sms-dr/" rel="noopener noreferrer"&gt;Bots and AI: Bot Messaging vs. Push Notifications vs. SMS  &lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://learn.vonage.com/blog/2017/10/05/ai-bot-platform/" rel="noopener noreferrer"&gt;Bots and AI: What Is a Bot Platform, Exactly?&lt;/a&gt;  &lt;/p&gt;

&lt;p&gt;&lt;a href="https://learn.vonage.com/blog/2017/11/02/bots-ai-mastering-invocation-names-alexa-skills/" rel="noopener noreferrer"&gt;Bots and AI: Mastering Invocation Names for Alexa Skills&lt;/a&gt;   &lt;/p&gt;

&lt;p&gt;&lt;a href="https://learn.vonage.com/blog/2017/11/16/bots-ai-personal-assistants-voice-assistants/" rel="noopener noreferrer"&gt;Bots and AI: How Personal Will Personal Assistants Be?&lt;/a&gt;&lt;/p&gt;

</description>
      <category>bots</category>
      <category>chatbots</category>
      <category>conference</category>
      <category>community</category>
    </item>
    <item>
      <title>Send and Receive SMS Messages with Firebase Functions | One Dev Minute</title>
      <dc:creator>Amanda Cavallaro</dc:creator>
      <pubDate>Wed, 22 Dec 2021 15:21:22 +0000</pubDate>
      <link>https://dev.to/vonagedev/send-and-receive-sms-messages-with-firebase-functions-one-dev-minute-5f0i</link>
      <guid>https://dev.to/vonagedev/send-and-receive-sms-messages-with-firebase-functions-one-dev-minute-5f0i</guid>
      <description>&lt;p&gt;Welcome to &lt;a href="https://www.youtube.com/playlist?list=PLWYngsniPr_mwb65DDl3Kr6xeh6l7_pVY" rel="noopener noreferrer"&gt;One Dev Minute&lt;/a&gt;! This series is hosted on the &lt;a href="https://www.youtube.com/vonagedev" rel="noopener noreferrer"&gt;Vonage Dev YouTube channel&lt;/a&gt;. The goal of this video series is to share knowledge in a bite-sized manner.&lt;/p&gt;

&lt;p&gt;This quick walk-through will show you how to create an SMS message log and a response to the sender using Firebase Cloud Functions and the Real Time Database alongside the Vonage SMS API. &lt;/p&gt;

&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/c8gHy_KvQAE"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;h2&gt;
  
  
  Transcript
&lt;/h2&gt;

&lt;p&gt;You can send SMS messages using Cloud Functions for Firebase.&lt;/p&gt;

&lt;p&gt;You'll need to create a couple of accounts: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;a Firebase&lt;/li&gt;
&lt;li&gt;and a Vonage API one.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Create the project in the Firebase console and choose whether or not you will use Analytics.&lt;/p&gt;

&lt;p&gt;Wait for your project to be created.&lt;/p&gt;

&lt;p&gt;Select the Firebase billing plan, in this case, it is the pay as you go.&lt;/p&gt;

&lt;p&gt;In the Command line, install the Firebase tools.&lt;/p&gt;

&lt;p&gt;Login to Firebase and authenticate. Create the project folder and change directory inside of it.&lt;/p&gt;

&lt;p&gt;Initialize the Cloud Functions for Firebase.&lt;/p&gt;

&lt;p&gt;Install the dependencies we are going to use inside the functions folder.&lt;/p&gt;

&lt;p&gt;Create a &lt;code&gt;.env&lt;/code&gt; file and add the Vonage environment variables there.&lt;/p&gt;

&lt;p&gt;Inside the file &lt;code&gt;index.js&lt;/code&gt;, add all the required dependencies and environment variables and initialize Firebase.&lt;/p&gt;

&lt;p&gt;In the same file, create the first function which will act as a webhook to capture and log incoming SMS messages from a Vonage phone number.&lt;/p&gt;

&lt;p&gt;Let's then create a function for Firebase to send the response SMS and to react to database updates.&lt;/p&gt;

&lt;p&gt;Deploy the function, send an SMS message from your phone to the Vonage application phone number.&lt;/p&gt;

&lt;p&gt;You'll then receive a response SMS message on your phone and an update to Firebase Real-Time Database.&lt;/p&gt;

&lt;p&gt;You can find the full code on GitHub. Thank you for watching and happy coding!&lt;/p&gt;

&lt;h2&gt;
  
  
  Links
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://www.youtube.com/redirect?event=video_description&amp;amp;redir_token=QUFFLUhqazJ0UDFleGVwSnBfQU1ORTRLYkhDM0xrbkpZQXxBQ3Jtc0trcjJnY0E4QjRybFUwVk5GRWJQSVhMcnJERC1MbHQyWEpqaHNLSklyWjRiMFdZYmt2RzlaVVQ5UWRMYnVDa1V6SE1RcG5jTm5RSl9MbkRWNlhYZkRsYUtkc2JDXzZBM3p4NXRzNkZnTHp0LVMxbEdNUQ&amp;amp;q=https%3A%2F%2Fgithub.com%2Fnexmo-community%2Ffirebase-functions-sms-example" rel="noopener noreferrer"&gt;This Tutorial's Code on GitHub&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.youtube.com/redirect?event=video_description&amp;amp;redir_token=QUFFLUhqbUttd1Q0OHBsYU9fWlZyaHZlZ2JhN25FVE1LQXxBQ3Jtc0tsbFNxSVV1Q3ZtNzRUSkU4QUJwYVhHaENZZkJNYXZoemx0YkVjOUpWMmhMcXluRjBYVU4wNVcwdGU5SWFjU0FDUXRCUW1VNEd6U1ZjNTd5ZHl0V20xTW5fSUZfUXBzNldYUDltMlprOEhZRDBpMFMxMA&amp;amp;q=https%3A%2F%2Flearn.vonage.com%2Fblog%2F2020%2F01%2F24%2Fsend-and-receive-sms-messages-with-firebase-functions-dr%2F" rel="noopener noreferrer"&gt;Find the Written Tutorial Here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.youtube.com/redirect?event=video_description&amp;amp;redir_token=QUFFLUhqbkdBRVRBMDZsY05fYTJJeE14UmxsMFFGUWJGQXxBQ3Jtc0trY21SMGtEaGRsaVBKUmdpMkxDMlh6NWFrU2JtNjRNcHlGM200bGoyaVRiOGFnN2lYOUFFNnY3V1hZaVFaMWlEamtFOGU0eDdtWmxEVnlJLWlzWFptT3NJM2RpZFQtclg2Z09zVUpHcmZUXzM1T3BOTQ&amp;amp;q=https%3A%2F%2Fdeveloper.vonage.com" rel="noopener noreferrer"&gt;Check Out the Developer Documentation&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.youtube.com/redirect?event=video_description&amp;amp;redir_token=QUFFLUhqa3VKcWlvTTJqXzRTODh6SEdoNUlvdmJuMHo1d3xBQ3Jtc0tub3hvYlFpbnhQVktXdWZFcENEVHNlbFNfUmFZenNOVUFoTmUwWHBwekxrSDBLWW1LZDg5UFBnZ2t4UWpBaFlFazBIcDF2bjRLc1c1ZGVNRUhKblFFRmZDLTQtQXIxMnBVQ1RKR1dGTG5xd0dPRzdqZw&amp;amp;q=https%3A%2F%2Fdeveloper.vonage.com%2Fmessaging%2Fsms%2Foverview" rel="noopener noreferrer"&gt;Details About Vonage SMS Functionality&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.youtube.com/redirect?event=video_description&amp;amp;redir_token=QUFFLUhqbUdadHRpUm4zZkNSSkdmQnMzUUEzdTFxR2ZPd3xBQ3Jtc0trSTc4S0tUbmNGVEFxaHk3Zk5CbmE5c3pQMzgzczd0QUF0M3Y3aTMzWFhiVlhHTkdDa3I3aUFxNGZqN05SZ09TUG1wcFd6UW1FRkl0THFJbWFBRHBTbXg5c1lwbG4zSjZzRXdGS0dGR2l3dHQ2LUQ0NA&amp;amp;q=https%3A%2F%2Ffirebase.google.com%2Fdocs%2Ffunctions%2Fget-started" rel="noopener noreferrer"&gt;Getting Started with Firebase Functions&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>firebase</category>
      <category>serverless</category>
      <category>sms</category>
      <category>node</category>
    </item>
    <item>
      <title>Call Control Objects (NCCOs) | One Dev Minute</title>
      <dc:creator>Amanda Cavallaro</dc:creator>
      <pubDate>Wed, 22 Dec 2021 13:22:54 +0000</pubDate>
      <link>https://dev.to/vonagedev/call-control-objects-nccos-one-dev-minute-67l</link>
      <guid>https://dev.to/vonagedev/call-control-objects-nccos-one-dev-minute-67l</guid>
      <description>&lt;p&gt;Welcome to &lt;a href="https://www.youtube.com/playlist?list=PLWYngsniPr_mwb65DDl3Kr6xeh6l7_pVY" rel="noopener noreferrer"&gt;One Dev Minute&lt;/a&gt;! This series is hosted on the &lt;a href="https://www.youtube.com/vonagedev" rel="noopener noreferrer"&gt;Vonage Dev YouTube channel&lt;/a&gt;. The goal of this video series is to share knowledge in a bite-sized manner. &lt;/p&gt;

&lt;p&gt;In this video, Amanda Cavallaro, our Developer Advocate, talks about the Call Control Objects, which are a set of actions that instruct Vonage how to control the call to your Vonage application. For instance, you can connect a call, send synthesized speech using talk, stream audio, or record a call.&lt;/p&gt;

&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/26rm0MP2up0"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;h2&gt;
  
  
  Transcript
&lt;/h2&gt;

&lt;p&gt;A Call Control Object - or an NCCO - is a set of instructions that a voice call will follow.&lt;/p&gt;

&lt;p&gt;An NCCO is composed of one or more actions. Their order is important, as it describes the flow of the call. Options are used to customize an action. A Call Control Object is represented by a JSON array.&lt;/p&gt;

&lt;p&gt;In this example, we can see a connect action with the options to make a call from a given number to an endpoint of type phone with a number.&lt;/p&gt;

&lt;p&gt;This second example is similar to the first one, but instead, it makes a call from a given phone number to an endpoint of type app, connecting to a client app, and we are also sending updates from the event URL. &lt;/p&gt;

&lt;p&gt;You can join multiple calls into one conversation conference call.&lt;br&gt;
In this example, you can see one action talk with a descriptive text showing you’re joining a conference. It's followed by an action that creates the conversation for the conference call.&lt;/p&gt;

&lt;p&gt;We can also leverage speech recognition. Here’s a code snippet that shows how to handle a user's input.&lt;/p&gt;

&lt;p&gt;We can accept Dual Tone Multi Frequency (DTMF), speech, or both.&lt;/p&gt;

&lt;p&gt;You can learn further from the links below.&lt;/p&gt;

&lt;h2&gt;
  
  
  Links
&lt;/h2&gt;

&lt;p&gt;More resources related to NCCO:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://developer.vonage.com/voice/voice-api/guides/ncco" rel="noopener noreferrer"&gt;NCCO Guide&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://developer.vonage.com/voice/voice-api/ncco-reference" rel="noopener noreferrer"&gt;NCCO Reference&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://learn.vonage.com/blog/2019/10/25/introducing-the-ncco-examples-collection-dr/" rel="noopener noreferrer"&gt;NCCO Examples Collection&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://developer.vonage.com/voice/voice-api/guides/call-flow" rel="noopener noreferrer"&gt;Call Flow&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Join the &lt;a href="https://developer.nexmo.com/community/slack" rel="noopener noreferrer"&gt;Vonage Developer Community Slack&lt;/a&gt;&lt;/p&gt;

</description>
      <category>videoapi</category>
      <category>javascript</category>
      <category>node</category>
    </item>
    <item>
      <title>Speaking at a Twitter Space</title>
      <dc:creator>Amanda Cavallaro</dc:creator>
      <pubDate>Thu, 24 Jun 2021 17:15:59 +0000</pubDate>
      <link>https://dev.to/chibichibibr/speaking-at-a-twitter-space-11p9</link>
      <guid>https://dev.to/chibichibibr/speaking-at-a-twitter-space-11p9</guid>
      <description>&lt;p&gt;Have you seen Twitter Spaces before? It is a relatively new way to have live audio conversations with a group of people on Twitter.&lt;/p&gt;

&lt;p&gt;&lt;a class="mentioned-user" href="https://dev.to/eddiejaoude"&gt;@eddiejaoude&lt;/a&gt; invited me to speak at "Creating content like a pro" on Twitter Spaces.&lt;/p&gt;

&lt;p&gt;I was a little anxious because the share button content was just to a "reminder" to join. I am so used to having a link to some actual call.&lt;/p&gt;

&lt;p&gt;So when the clock stroke 17:30 there I was ready to click at the top of twitter space on the twitter app on my android phone.&lt;/p&gt;

&lt;p&gt;I clicked to request speaker privileges and Eddie promptly accepted it. If at any time I no longer want this privilege I can click on the gear and select "switch to listening".&lt;/p&gt;

&lt;p&gt;I started exploring the UI and seeing if I could...perhaps speak on the chat? There is no chat! Oh but there are reactions, ok that is familiar! There are live captions which is also great for accessibility!&lt;/p&gt;

&lt;p&gt;The very first seconds I thought to myself: how does it work? How will I know when it's my turn to talk? How will I know I am not speaking over someone else?&lt;/p&gt;

&lt;p&gt;To my good surprise Eddie started guiding us, asking us to introduce ourselves and whenever there was a question from the audience, Eddie would promptly keep track of the speakers who unmuted themselves and get back to them after the other speaker gave their response.&lt;/p&gt;

&lt;p&gt;I must say I enjoyed this type of interaction because even if you are a "speaker" it is a conversation so I could learn a lot from the others as well!&lt;/p&gt;

</description>
      <category>twitterspaces</category>
      <category>content</category>
      <category>devrel</category>
      <category>community</category>
    </item>
    <item>
      <title>Tools I Use</title>
      <dc:creator>Amanda Cavallaro</dc:creator>
      <pubDate>Thu, 10 Jun 2021 09:31:51 +0000</pubDate>
      <link>https://dev.to/chibichibibr/tools-i-use-2nhk</link>
      <guid>https://dev.to/chibichibibr/tools-i-use-2nhk</guid>
      <description>&lt;p&gt;&lt;strong&gt;Microphone and Headphones&lt;/strong&gt;&lt;br&gt;
Focusrite Scarlett 2i2 (Professional recording)&lt;br&gt;
AudioTechnica BPSH1 (Professional recording)&lt;br&gt;
Trust GXT 232 (Everyday)&lt;br&gt;
Bose 7000 (Everyday)&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Lights&lt;/strong&gt;&lt;br&gt;
2 Neewman&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Webcam&lt;/strong&gt;&lt;br&gt;
Logitech BRIO 4k&lt;br&gt;
OBS Virtual camera.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Background&lt;/strong&gt;&lt;br&gt;
Greenscale attached to the chair&lt;br&gt;
&lt;a href="https://www.youtube.com/watch?v=Z0HIo0P0-qM" rel="noopener noreferrer"&gt;This OBS tutorial by Hanselman&lt;/a&gt; really helped me out.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Video Recording/Streaming Software&lt;/strong&gt;&lt;br&gt;
I show u instant&lt;br&gt;
OBS&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Screen controller&lt;/strong&gt;&lt;br&gt;
Switch Res X&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Online Platforms&lt;/strong&gt;&lt;br&gt;
Streamyard&lt;br&gt;
Youtube&lt;br&gt;
Twitch&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Post Production/ Editing&lt;/strong&gt;&lt;br&gt;
iMovie&lt;br&gt;
Adobe suite&lt;/p&gt;

&lt;p&gt;Desktop setup ideas: &lt;br&gt;
&lt;iframe class="tweet-embed" id="tweet-1393617682780598275-226" src="https://platform.twitter.com/embed/Tweet.html?id=1393617682780598275"&gt;
&lt;/iframe&gt;

  // Detect dark theme
  var iframe = document.getElementById('tweet-1393617682780598275-226');
  if (document.body.className.includes('dark-theme')) {
    iframe.src = "https://platform.twitter.com/embed/Tweet.html?id=1393617682780598275&amp;amp;theme=dark"
  }



&lt;/p&gt;

&lt;p&gt;What about you, which tools do you use?&lt;/p&gt;

</description>
      <category>tools</category>
      <category>devrel</category>
      <category>streamer</category>
      <category>community</category>
    </item>
  </channel>
</rss>
