Frequently Asked Questions
Use the Vonage Messages API and Node.js SDK. After setting up a Vonage application and configuring webhooks, you can send SMS messages by making a POST request to the `/send-message` endpoint with the recipient's number and the message text in the request body. The Vonage SDK simplifies the process of interacting with the API.
The Vonage Messages API is a versatile API that enables sending and receiving messages across various channels like SMS, MMS, WhatsApp, Facebook Messenger, and Viber. This API is used in conjunction with the Vonage Node.js SDK to build applications capable of rich, multi-channel communication.
Vonage uses JWT (JSON Web Tokens) for webhook security to ensure that incoming webhook requests originate from Vonage and haven't been tampered with. The `verifyVonageSignature` middleware in the example code verifies the JWT against your signature secret, protecting your application from unauthorized access.
ngrok is useful for testing webhooks during local development. It provides a publicly accessible URL that forwards requests to your local server. However, for production, use a stable, publicly accessible URL and deploy your application to a server.
Yes, the provided Node.js application and Vonage setup supports sending and receiving WhatsApp messages via the Vonage WhatsApp Sandbox. Ensure your WhatsApp number is allowlisted in the sandbox for testing. The code uses the WhatsAppText class from the Vonage Messages API to send WhatsApp messages.
Configure the inbound webhook URL in your Vonage application settings to point to your application's `/webhooks/inbound` endpoint. The Vonage server will send an HTTP POST request to this URL with message details whenever an SMS is received on your Vonage virtual number.
Vonage sends message status updates (e.g., delivered, read) to the Status URL you configured in the application settings. Implement the `/webhooks/status` route in your Express application to receive these updates and process them accordingly, such as storing them in a database.
A Vonage application acts as a container for your communication settings and authentication. It manages API keys, webhooks, and other configuration related to your Vonage services. It is essential for routing messages and handling security.
Use the `@vonage/jwt` library, specifically the `verifySignature` function. Implement middleware that extracts the JWT from the `Authorization` header and verifies it against your signature secret. Reject requests with invalid signatures.
Node.js version 18 or higher is recommended for Vonage integration. Ensure compatibility within your specific target Node.js version while keeping up-to-date with Node.js releases and security patches.
Navigate to the Messages Sandbox under Developer Tools in your Vonage dashboard. Activate the sandbox and allowlist your WhatsApp number by scanning the QR code or sending the provided message to the sandbox number. Configure the inbound and status webhooks within the sandbox settings.
Several reasons could prevent webhooks from working: ngrok tunnel may not be running or correctly configured, the webhook URL in the Vonage settings may be incorrect, credentials may be wrong, server may not be running or experiencing errors, or the private key may not exist.
Your Vonage API key and secret are found on the main page of your Vonage API dashboard. You should store these securely in environment variables, especially in a production setting.
Never commit your Vonage `private.key` file to version control. For production, store its contents securely, ideally in a dedicated secrets management service or as a secure environment variable. Avoid storing it directly on the server file system.
Developer Guide: Sending and Receiving SMS & WhatsApp Messages with Node.js, Express, and Vonage
This guide provides a step-by-step walkthrough for building a production-ready Node.js application using the Express framework to send and receive both SMS and WhatsApp messages via the Vonage Messages API. This guide utilizes the Express framework to structure the application and the Vonage Node SDK to handle communication with the Vonage APIs. We will cover project setup, core functionality, webhook handling, security considerations, testing, and deployment practices.
Goal: To create a unified backend service capable of handling bidirectional communication over SMS and WhatsApp, suitable for applications like customer support bots, notification systems, or interactive campaigns.
Technologies Used:
.env
file.System Architecture:
<!-- A diagram illustrating the flow of messages between the user, Vonage, ngrok, and the application would be placed here. Consider creating a PNG or SVG image for clarity, showing bidirectional paths for sending and receiving via webhooks. --> (Diagram placeholder: Illustrates message flow: User <-> Vonage <-> ngrok (dev) / Public URL (prod) <-> Your Node.js App)
Prerequisites:
npm install -g @vonage/cli
. Configure it withvonage config setup API_KEY API_SECRET
.Numbers
->Buy numbers
) capable of sending/receiving SMS in your desired region.1. Project Setup and Configuration
Let's initialize our Node.js project and install the necessary dependencies.
1.1 Create Project Directory:
Open your terminal and create a new directory for the project, then navigate into it.
1.2 Initialize npm:
Initialize the project using npm. The
-y
flag accepts default settings.This creates a
package.json
file.1.3 Install Dependencies:
Install Express for the web server, the Vonage SDKs for API interaction, and
dotenv
for environment variable management.express
: Web framework.@vonage/server-sdk
: Core Vonage SDK.@vonage/messages
: Specific helpers for the Messages API (likeWhatsAppText
).@vonage/jwt
: For verifying webhook signatures (essential for security).dotenv
: Loads environment variables from.env
intoprocess.env
.1.4 Create Project Structure:
Create the basic files and folders.
index.js
: Main application file..env
: Stores sensitive credentials and configuration (API keys, phone numbers). Never commit this file to version control..gitignore
: Specifies files/folders Git should ignore.1.5 Configure
.gitignore
:Add
node_modules
and.env
to your.gitignore
file to prevent committing them.1.6 Environment Variable Setup (
.env
):Open the
.env
file and add the following placeholders. We will populate these values in the next steps.Explanation of
.env
variables:VONAGE_API_KEY
,VONAGE_API_SECRET
: Found on the main page of your Vonage API Dashboard.VONAGE_APPLICATION_ID
: Generated when you create a Vonage Application (see next section).VONAGE_PRIVATE_KEY
: Path to theprivate.key
file downloaded when creating the Vonage Application. Place this file in your project root or update the path accordingly. See Security section for production handling.VONAGE_SIGNATURE_SECRET
: Found in your Vonage Dashboard Settings. Used to verify webhook authenticity.VONAGE_SMS_NUMBER
: Your purchased Vonage virtual number (include country code, no '+', e.g.,15551112222
).VONAGE_WHATSAPP_NUMBER
: The number assigned by the Vonage WhatsApp Sandbox (e.g.,14157386102
).PORT
: The local port your server will listen on.2. Vonage Application and Sandbox Setup
We need a Vonage Application to handle message routing and authentication, and the WhatsApp Sandbox for testing.
2.1 Create a Vonage Application:
A Vonage Application acts as a container for your communication settings and authentication.
Applications
in your Vonage API Dashboard.Create a new application
.Generate public and private key
. Immediately save theprivate.key
file that downloads. Place it in your project root directory (or update the.env
path). Vonage does not store this private key, so keep it safe.Messages
capability.Forwarding
URL (e.g.,https://<unique-code>.ngrok-free.app
). Copy thehttps
URL. Keep ngrok running.Inbound URL
andStatus URL
fields, appending the paths we'll create in our Express app:YOUR_NGROK_HTTPS_URL/webhooks/inbound
YOUR_NGROK_HTTPS_URL/webhooks/status
(Example:https://abcdef123456.ngrok-free.app/webhooks/inbound
)Generate new application
.VONAGE_APPLICATION_ID
field in your.env
file.Link virtual numbers
and link the Vonage virtual number you purchased for SMS. This routes incoming SMS for that number to this application's inbound webhook.2.2 Set Default SMS API (Important):
Ensure your account uses the Messages API (not the older SMS API) for webhooks.
API Settings
.Default SMS Setting
, selectMessages API
.Save changes
.2.3 Set Up Vonage WhatsApp Sandbox:
The Sandbox provides a testing environment without needing a dedicated WhatsApp Business number initially.
Messages Sandbox
underDeveloper Tools
in the Dashboard menu.14157386102
) and paste it intoVONAGE_WHATSAPP_NUMBER
in your.env
file.Webhooks
on the Sandbox page:YOUR_NGROK_HTTPS_URL/webhooks/inbound
(Same as application)YOUR_NGROK_HTTPS_URL/webhooks/status
(Same as application)Save webhooks
.2.4 Obtain Signature Secret:
API key
.Edit
(pencil icon) next to the API key.Signature secret
value.VONAGE_SIGNATURE_SECRET
in your.env
file.Your
.env
file should now be populated with real values.3. Implementing the Express Server and Core Logic
Now, let's write the Node.js code.
index.js
:Code Explanation:
.env
, requires modules, initializes Express and the Vonage SDK.express.json()
andexpress.urlencoded()
to parse incoming request bodies.verifyVonageSignature
Middleware: This is crucial for webhook security. It extracts the JWT from theAuthorization: Bearer <token>
header sent by Vonage, verifies it against yourVONAGE_SIGNATURE_SECRET
using@vonage/jwt
. If invalid, it rejects the request with a 401 Unauthorized status./webhooks/inbound
Route:verifyVonageSignature
.from
,to
,channel
,message_type
,text
.sms
andwhatsapp
channels.// TODO:
) explicitly marked for implementing your specific business logic (e.g., database storage, triggering workflows).sendWhatsAppConfirmation
upon receiving a WhatsApp message.200 OK
response. Vonage needs this acknowledgment; otherwise, it will retry sending the webhook, potentially causing duplicate processing./webhooks/status
Route:verifyVonageSignature
.delivered
,read
,failed
).// TODO:
) for updating message status in your system.200 OK
response./send-message
API Route:channel
,to
, andtext
in the JSON request body.from
number based on the channel.vonage.messages.send()
:WhatsAppText
class helper from@vonage/messages
.try...catch
for error handling during the API call, logging detailed errors.message_uuid
on success or error details on failure.sendWhatsAppConfirmation
Helper: A simple example function demonstrating how to send a reply back to a WhatsApp user. Note the use of Markdown (*...*
) within the text string for formatting in WhatsApp.PORT
, provides informative startup logs.4. Running and Testing the Application
4.1 Start the Server:
Ensure your ngrok tunnel (from step 2.1.6) is still running in one terminal. In your main project terminal, run:
You should see output similar to:
(Replace
YOUR_NGROK_HTTPS_URL
in the Vonage settings with the actual URL provided by ngrok).4.2 Testing Inbound SMS:
VONAGE_SMS_NUMBER
).node index.js
. You should see logs for:[INFO] Webhook Signature Verified Successfully.
[INFO] Incoming Message Webhook Received:
(with SMS details)[INFO] SMS Received: ""Your message text""
4.3 Testing Inbound WhatsApp:
VONAGE_WHATSAPP_NUMBER
).node index.js
. You should see logs for:[INFO] Webhook Signature Verified Successfully.
[INFO] Incoming Message Webhook Received:
(with WhatsApp details)[INFO] WhatsApp Text Received: ""Your message text""
[INFO] Sending WhatsApp confirmation to <your_whatsapp_number>...
[INFO] WhatsApp confirmation sent: <message_uuid>
4.4 Testing Outbound API (
/send-message
):Use
curl
or a tool like Postman/Insomnia to send requests to your local server's API endpoint (http://localhost:3000/send-message
).Send SMS:
(Replace
YOUR_PERSONAL_PHONE_NUMBER
with your actual number, including country code, e.g.,15551234567
)Send WhatsApp:
(Replace
YOUR_ALLOWLISTED_WHATSAPP_NUMBER
with your number allowlisted in the Sandbox, including country code)4.5 Testing Status Webhook:
[INFO] Status Webhook Received:
in your terminal as Vonage sends updates (e.g.,submitted
,delivered
,read
- 'read' status depends on recipient settings and channel).4.6 Testing Error Conditions (Recommended):
/send-message
endpoint. Observe the error logged in the console and the API response.curl
to send a POST request directly to your/webhooks/inbound
ngrok URL without a validAuthorization: Bearer <token>
header, or with an invalid token. Verify your server responds with a401 Unauthorized
and logs a signature warning.402 Payment Required
errors from the Vonage API if your account runs out of credit. Ensure your error handling logs these appropriately.5. Error Handling and Logging
console.log
,console.warn
,console.error
with text prefixes ([INFO]
,[WARN]
,[ERROR]
,[DEBUG]
).try...catch
blocks wrap Vonage API calls and webhook processing logic. The JWT verification middleware handles signature errors. A basic Express error handler catches unhandled exceptions.Winston
orPino
for structured JSON logs, which are easier to parse and analyze in log management systems (e.g., Datadog, Splunk, ELK stack). Include timestamps, log levels, request IDs (using middleware likeexpress-request-id
), and relevant context (likemessage_uuid
).error.response.data.type
orerror.response.status
(e.g., invalid number format400
, insufficient funds402
, authentication issues401
) and provide more informative responses or implement specific retry logic where appropriate.401
, server crashes500
, authentication errors401
on sending).6. Security Considerations
VONAGE_SIGNATURE_SECRET
secure and treat it like a password. Rotate it if compromised..env
for local development and secure environment variable management in production (e.g., platform secrets, HashiCorp Vault, AWS Secrets Manager, Google Secret Manager). See Section 9 for private key handling.400 Bad Request
)./send-message
API: Basic validation is included. Enhance it based on expected inputs (e.g., max text length, valid number formats using libraries likelibphonenumber-js
). Use libraries likeJoi
orexpress-validator
for defining and enforcing complex validation schemas./send-message
API endpoint (and potentially webhooks, though less common) from abuse or accidental loops. Use middleware likeexpress-rate-limit
.npm audit
or tools like Snyk, and update them promptly. Implementnpm audit fix
into your development workflow.VONAGE_PRIVATE_KEY
path points to a file locally. Do not commit theprivate.key
file to version control. For production, avoid storing the key as a file on the server filesystem if possible. Best practices include:private.key
file in a secure environment variable (potentially base64 encoded for easier handling in some systems). Read the key content from this variable inindex.js
instead of a file path.7. Database Integration (Conceptual)
This guide focuses on the core messaging logic. For persistent storage:
messages
(storingmessage_uuid
,vonage_message_uuid
,channel
,direction
['inbound'/'outbound'],sender_id
,recipient_id
,content
[text/URL],status
,error_info
,timestamp_received
,timestamp_sent
,timestamp_status_update
) and potentiallyconversations
orusers
.Prisma
,Sequelize
(SQL), orMongoose
(MongoDB) to interact with your chosen database./webhooks/inbound
: After validation, create a new record in yourmessages
table with the incoming message details./webhooks/status
: Find the message record using themessage_uuid
and update itsstatus
,timestamp_status_update
, and potentiallyerror_info
./send-message
: Before sending the message via Vonage API, create a record in yourmessages
table (with initial status like 'pending' or 'submitted'). After a successful API call, update the record with thevonage_message_uuid
returned by Vonage. If the API call fails immediately, log the error in the record.8. Troubleshooting and Caveats
VONAGE_API_KEY
,VONAGE_API_SECRET
,VONAGE_APPLICATION_ID
,VONAGE_PRIVATE_KEY
(content or path), andVONAGE_SIGNATURE_SECRET
in your environment. Ensure theprivate.key
file exists and is readable if using a file path, or that the environment variable contains the correct key content.VONAGE_SIGNATURE_SECRET
in your environment matches the one in your Vonage Dashboard settings exactly. Copy/paste carefully.req.headers
in logs if needed).Inbound URL
andStatus URL
in your Vonage Application settings exactly match your current ngrok HTTPS URL plus the correct path (/webhooks/inbound
or/webhooks/status
).node index.js
) and hasn't crashed. Check console logs for errors.