Frequently Asked Questions
Use the Vonage Messages API with the Node.js SDK. Initialize the Vonage client with your API credentials, then use the `vonage.messages.send()` method with a `MessengerText` object specifying the recipient, sender, and message content. Ensure your Vonage number is linked to a Vonage Application.
It's a unified API from Vonage that allows you to send and receive messages across multiple channels, including SMS, MMS, and WhatsApp. This guide focuses on using it for two-way SMS communication.
Webhooks are essential for receiving incoming SMS messages and delivery status updates asynchronously. Vonage uses them to push real-time notifications to your application when a user replies or a message's status changes.
ngrok is useful during local development to create a temporary public URL that Vonage can send webhooks to. It is not recommended for production, which requires a proper deployment on a publicly accessible server.
No, Vonage has two separate APIs for SMS: the legacy SMS API and the newer Messages API. This guide uses the Messages API which has a different format for webhooks and generally offers more capabilities. Check your API settings on the Vonage dashboard if unsure.
Set up a POST route (e.g., `/webhooks/inbound`) in your Express app. Configure this URL as the 'Inbound URL' in your Vonage Application settings. Vonage will send a POST request to this endpoint whenever an SMS is sent to your Vonage number.
The private.key file, along with your application ID, is used to authenticate requests to the Vonage Messages API securely when you send messages. It's downloaded when you create a Vonage Application and should never be committed to version control.
A 200 OK response from your webhook endpoint acknowledges to Vonage that you've received the webhook. If your server doesn't send a 200 OK, or takes too long, Vonage might retry the webhook multiple times.
Create a POST route (e.g., `/webhooks/status`) and set it as the 'Status URL' in your Vonage Application. Vonage will send POST requests to this endpoint with updates on the delivery status of your outbound SMS messages.
The webhook request body includes the sender's number (`from.number`), message text (`text`), timestamp (`timestamp`), message UUID (`message_uuid`), and potentially other metadata. See the guide's code examples for handling the inbound SMS webhook for JSON examples.
Combine the outbound SMS sending logic with inbound webhook handling. When you receive an inbound message, extract the sender's number and use `sendSms()` to reply to them. See section 6 of the guide for a clear example of implementing auto-replies within `server.js`.
The `dotenv` package helps manage environment variables. It loads variables from a `.env` file into `process.env`, allowing you to store sensitive information like API keys and secrets separately from your code.
Test manually by sending SMS to your Vonage number and checking logs. Use ngrok's web interface to inspect webhooks. For automated tests, use Jest or Mocha to unit test functions and create mock webhooks to test server logic. For production readiness, implement E2E testing, verifying the complete messaging flow.
Validating webhooks ensures that the requests genuinely originate from Vonage, protecting your application from malicious actors or erroneous requests. Consider signature validation, IP whitelisting, or basic authentication where possible for production setups.
Developer guide: Implementing two-way SMS messaging with Node.js, Express, and Vonage
This guide provides a complete walkthrough for building a production-ready Node.js application using the Express framework to handle two-way SMS messaging via the Vonage Messages API. You'll learn how to send outbound SMS messages and set up webhooks to receive inbound messages and delivery statuses, enabling interactive communication flows.
By the end of this guide, you will have a functional Node.js application capable of:
We assume you have a basic understanding of Node.js, asynchronous programming (Promises, async/await), and REST APIs.
Project overview and goals
Goal: To create a robust Node.js service that can both send and receive SMS messages using Vonage's communication capabilities.
Problem Solved: This implementation enables applications to engage users via SMS for notifications, alerts, two-factor authentication (2FA), customer support, marketing campaigns, or any scenario requiring direct mobile communication. It provides the foundation for building interactive SMS-based services.
Technologies Used:
@vonage/server-sdk
: The official Vonage Node.js SDK simplifies interaction with Vonage APIs.ngrok
: A tool to expose local development servers to the internet, essential for testing Vonage webhooks without deploying (for local development testing only).dotenv
: A module to load environment variables from a.env
file intoprocess.env
, keeping sensitive credentials out of source code.System Architecture:
Expected Outcome: A running Node.js application with two main parts:
send-sms.js
) to send an outbound SMS on demand.server.js
) listening for incoming HTTP POST requests from Vonage webhooks (inbound messages and status updates).Prerequisites:
ngrok
: Installed and authenticated (a free account is sufficient). Download from ngrok.com.npm install -g @vonage/cli
. Useful for managing applications and numbers.1. Setting up the project
Let's initialize our Node.js project and install the necessary dependencies.
Create Project Directory: Open your terminal and create a new directory for the project, then navigate into it.
Initialize Node.js Project: This creates a
package.json
file to manage project details and dependencies.Install Dependencies: We need
express
for the web server,@vonage/server-sdk
to interact with the Vonage API, anddotenv
for managing environment variables.Project Structure: Create the following basic structure:
Configure
.gitignore
: Create a.gitignore
file in the root directory to prevent committing sensitive information and unnecessary files.Why
.gitignore
? This ensures your API secrets, private keys, and local environment configurations are not accidentally pushed to version control systems like Git, which is crucial for security.2. Vonage configuration
Before writing code, we need to configure our Vonage account and application settings. Note: Specific UI labels and navigation paths within the Vonage Dashboard may change over time.
API Key and Secret: Navigate to your Vonage API Dashboard. Your API Key and API Secret are displayed prominently at the top. You'll need these shortly.
Purchase a Vonage Number:
Numbers
->Buy Numbers
(or equivalent section) in the dashboard.VONAGE_NUMBER
.Select Messages API for SMS:
SMS Settings
, ensureDefault SMS Setting
is set toUse the Messages API
.Save changes
.Why this setting? It ensures that webhooks related to your Vonage number use the format expected by the Messages API and the
@vonage/server-sdk
methods we'll use.Create a Vonage Application: The Messages API primarily uses Applications for authentication via public/private key pairs, which is more secure for API access compared to only using the API Key/Secret (though Key/Secret might still be used by the SDK for other functionalities).
Applications
->Create a new application
(or equivalent).Nodejs SMS App
).Generate public and private key
. Immediately save theprivate.key
file that downloads. Move this file into your project's root directory (where.gitignore
will prevent committing it).Messages
capability.YOUR_NGROK_URL/webhooks/inbound
(We'll getYOUR_NGROK_URL
later using ngrok).YOUR_NGROK_URL/webhooks/status
http://example.com/inbound
. We will update them after startingngrok
.Generate new application
.Link Your Number to the Application:
Numbers
->Your numbers
.Edit
(pencil) icon orManage
button next to the number.Forwarding
orApplication
section, select the Vonage Application you just created (Nodejs SMS App
) from the dropdown underMessages
.Why link the number? This tells Vonage to route incoming messages and status updates for this specific number to the webhooks defined in the linked Application.
3. Environment setup (
.env
)Create the
.env
file in your project root and add your credentials. Replace the placeholder values with your actual details.VONAGE_API_KEY
,VONAGE_API_SECRET
: Used by the SDK for certain operations (e.g., some account management functions) or potentially as fallback authentication if Application ID/Key isn't configured for a specific client.VONAGE_APPLICATION_ID
,VONAGE_PRIVATE_KEY_PATH
: The primary credentials used by the Messages API client in this guide for sending messages via JWT generation using your private key.VONAGE_NUMBER
: The Vonage virtual number you purchased and linked to the application. This will be the sender (from
) number. Use E.164 format.MY_TEST_NUMBER
: The destination number (to
) for sending test messages. Use your own mobile number in E.164 format (country code + number, no spaces or symbols, e.g.,+14155552671
).4. Sending SMS messages
Let's create the script (
send-sms.js
) to send an outbound SMS.Explanation:
require('dotenv').config();
: Loads variables from your.env
file intoprocess.env
.@vonage/server-sdk
: Imports the necessary Vonage SDK components. We useVonage
for the client andMessengerText
as a helper class for constructing the SMS payload correctly for the Messages API.new Vonage(...)
: Initializes the client. Crucially, for the Messages API, we provideapplicationId
andprivateKey
. The SDK handles JWT generation for authentication behind the scenes.sendSms
function:to
) and message content (text
) as arguments.from
number (your Vonage number) from environment variables.vonage.messages.send()
which is the method for the Messages API.new MessengerText({...})
, specifyingchannel: 'sms'
.async/await
for cleaner asynchronous code.messageUuid
on success, which is useful for tracking.try...catch
for robust error handling, logging the detailed error response from Vonage if available.sendSms
.Run the Sending Script:
Execute the script from your terminal:
You should see output indicating the attempt and success (with a message UUID) or failure (with error details). Check your mobile phone for the incoming SMS!
5. Receiving SMS messages (Webhook Server)
Now, let's build the Express server (
server.js
) to handle incoming webhooks from Vonage.1. Start
ngrok
:Vonage needs a publicly accessible URL to send webhooks to.
ngrok
creates a secure tunnel from the internet to your local machine. Remember,ngrok
(especially the free tier) is suitable for development and testing only, not for production environments.Open a new terminal window (keep the first one for running the Node server later) and run:
Why port 3000? This matches the port our Express server will listen on.
ngrok
will display output similar to this:Copy the
https://<RANDOM_SUBDOMAIN>.ngrok-free.app
URL. This isYOUR_NGROK_URL
.2. Update Vonage Application Webhooks:
Applications
-> Your Application Name).ngrok
Forwarding URL into the webhook fields:https://<RANDOM_SUBDOMAIN>.ngrok-free.app/webhooks/inbound
https://<RANDOM_SUBDOMAIN>.ngrok-free.app/webhooks/status
Save changes
.3. Create the Express Server (
server.js
):Explanation:
express.json()
,express.urlencoded()
): Essential for parsing the incoming JSON and form-encoded data that Vonage sends in webhook requests./webhooks/inbound
Endpoint (POST):req.body
) received from Vonage. This is crucial for debugging and understanding the payload structure.from
(an object containing the sender'snumber
),text
(the message content),timestamp
, andmessage_uuid
. Includes basic validation.res.status(200).send(...)
. This acknowledges receipt to Vonage. Without this, Vonage will assume failure and retry sending the webhook, leading to duplicate processing./webhooks/status
Endpoint (POST):message_uuid
,status
('delivered', 'failed', etc.),timestamp
, andto
(recipient). Includes basic validation.200 OK
response.app.listen
): Starts the Express server on the specifiedPORT
(defaulting to 3000 to matchngrok
).4. Run the Webhook Server:
Go back to your first terminal window (where you ran
npm install
) and start the server:You should see the ""Server listening..."" message.
5. Test Receiving:
node server.js
is running. You should see the ""--- Inbound SMS Received ---"" log, followed by the JSON payload of the incoming message.ngrok
is running. You should seePOST /webhooks/inbound 200 OK
indicating the request was received and forwarded.ngrok
web interface (usuallyhttp://127.0.0.1:4040
).6. Test Status Updates:
node send-sms.js
.node server.js
terminal. After a short delay, you should see the ""--- Message Status Update Received ---"" log with the delivery status (likely 'delivered' or 'accepted' initially).ngrok
logs/interface forPOST /webhooks/status 200 OK
.6. Putting it together: Basic two-way messaging (Auto-Reply)
Let's modify the
server.js
to automatically reply to incoming messages.Refactor Sending Logic: Move the
sendSms
function fromsend-sms.js
intoserver.js
(or a separate utility file) so the webhook handler can call it. Ensure@vonage/server-sdk
,dotenv
, and theVonage
client initialization are also present inserver.js
.Modify
/webhooks/inbound
Handler:Explanation of Changes:
sendSms
function and Vonage client initialization are now part ofserver.js
./webhooks/inbound
handler is markedasync
.res.status(200).send(...)
before processing the message and sending the reply. This prevents Vonage webhook timeouts if the reply takes time.req.body.from.number
.replyText
.await sendSms(from.number, replyText)
to send the reply back to the original sender.Retest:
Ctrl+C
thennode server.js
.7. Error handling and logging
Our current setup uses basic
console.log
andconsole.error
. For production:message_uuid
s if necessary, especially if writing to a database. Always respond200 OK
quickly.try...catch
block aroundvonage.messages.send
is crucial. Parse theerr.response.data
for specific Vonage error codes and messages to understand failures (e.g., invalid number format, insufficient funds, carrier restrictions). Implement retry logic with exponential backoff for transient network errors when sending, if needed.8. Security considerations
ngrok
URL. For production:https://user:pass@yourdomain.com/webhooks/inbound
)..env
orprivate.key
. Use environment variables provided by your hosting platform or secrets management tools (like HashiCorp Vault, AWS Secrets Manager) in production.text
from incoming SMS messages (e.g., storing in DB, displaying in UI), sanitize it thoroughly to prevent Cross-Site Scripting (XSS) or other injection attacks. Libraries likeDOMPurify
(for HTML contexts) or robust validation/escaping are essential.express-rate-limit
.9. Database schema and data layer (Conceptual)
This guide doesn't implement a database, but this section provides a conceptual overview. The schema and code snippets below are illustrative examples, not a complete, production-ready implementation.
messages
: To store details of both inbound and outbound messages (UUID, direction, sender, recipient, text, timestamp, status, related message UUID for replies).conversations
(Optional): To group messages belonging to the same interaction thread./webhooks/inbound
: Create a newmessages
record with direction 'inbound'.sendSms
: Create a newmessages
record with direction 'outbound' and status 'submitted'./webhooks/status
: Find the message byvonage_uuid
(message_uuid from webhook) and update itsstatus
.prisma migrate dev
) to manage schema changes.10. Testing and verification
Testing is crucial for a reliable messaging application. The examples here are conceptual starting points.
send-sms.js
(or trigger sending via your app logic) -> Verify SMS received on mobile -> Verify server logs status webhook.ngrok
Inspector: Usehttp://127.0.0.1:4040
during development to inspect exact headers and payloads of incoming webhooks, which is invaluable for debugging.vonage.messages.send
) by mocking the Vonage API client.sendSms
).