Frequently Asked Questions
Use the Vonage Messages API with the `@vonage/server-sdk` in your Node.js application. Initialize the Vonage client with your API key, secret, application ID, and private key. Then, use `vonage.messages.send()` with the recipient's number, your Vonage virtual number, and the message text to send SMS messages.
The Vonage Messages API is a multi-channel communication platform that allows you to send and receive SMS, MMS, WhatsApp messages, and more. This guide demonstrates its use for sending SMS messages and receiving delivery status updates.
Webhooks provide a real-time, asynchronous mechanism for Vonage to push delivery status updates to your application. Instead of constantly polling the API, your application receives immediate notifications when the message status changes, like being delivered or failing.
Use a Vonage Application ID and its associated private key when using the Messages API. This ensures secure authentication using JWT (JSON Web Tokens), which are important when handling webhooks for security reasons.
Alphanumeric Sender IDs might be allowed, but you must check country-specific regulations. In some regions (e.g., the US), you must use a Vonage virtual number. If allowed, ensure it's pre-registered with Vonage.
Configure a 'Status URL' in your Vonage Application settings. This URL should point to a publicly accessible endpoint in your application (e.g., using ngrok for development). Vonage will send an HTTP POST request to this URL with delivery status updates.
ngrok creates a temporary public URL that tunnels to your local development server. This allows Vonage to send webhooks to your locally running application during development, essential for receiving delivery status updates.
Ensure your webhook endpoint returns a 2xx HTTP status code (ideally 200 OK or 204 No Content) as quickly as possible. This tells Vonage that you've received the webhook. Your endpoint logic should be idempotent to handle potential duplicate webhook deliveries.
Common statuses include 'submitted', 'delivered', 'failed', 'accepted', 'buffered', 'expired', and 'unknown'. 'Buffered' often means the recipient's device is offline. Each status describes a stage in the delivery process.
Verify that ngrok is running and correctly forwarding to your server's port, the Status URL in your Vonage Application settings is accurate (including the '/webhooks/status' path), and your server application is running without errors.
The `@vonage/server-sdk` simplifies interaction with Vonage APIs in Node.js. It handles authentication, request construction, and response parsing for sending SMS messages and other Vonage services.
Sensitive data, such as API keys, secrets, and private keys, should never be hardcoded. Environment variables (like in a `.env` file) offer a secure way to manage these credentials locally, keeping them out of your codebase.
A suggested schema includes columns for `message_uuid`, `to_number`, `from_number`, `message_body`, submission and status update timestamps, current status, error codes, and usage details.
Respond to the webhook request with a 200 OK immediately. Perform database updates or other time-consuming tasks asynchronously in the background to prevent blocking the webhook response and causing Vonage retries.
Use HTTPS, potentially IP whitelisting or secrets in URLs. Currently, simple signature validation is not supported for messages API webhooks. Cryptographically signed webhooks are more complex to implement for these particular APIs.
This guide provides a comprehensive walkthrough for building a Node.js application using the Express framework to send SMS messages via the Vonage Messages API and reliably receive delivery status updates through webhooks.
We will cover everything from initial project setup and configuration to implementing core functionality, handling webhooks, security considerations, and deployment strategies. By the end, you will have a robust system capable of sending SMS messages and tracking their delivery status.
Technologies Used:
@vonage/server-sdk
: The official Vonage Node.js SDK for interacting with Vonage APIs.dotenv
: A module to load environment variables from a.env
file.ngrok
: A tool to expose local development servers to the internet, necessary for receiving webhook callbacks during development.System Architecture:
The system involves two main flows:
delivered
,failed
). If configured, Vonage sends an HTTP POST request (webhook) containing this status information to a specified URL hosted by your Express application.Final Outcome:
ngrok
, ready to receive and log delivery status webhooks from Vonage.Prerequisites:
ngrok
: Installed and authenticated with your free account. (Download ngrok)npm install -g @vonage/cli
1. Setting Up the Project
This section covers initializing the Node.js project, installing dependencies, configuring environment variables, and setting up your Vonage account and application.
1.1. Initialize Project and Install Dependencies
Create Project Directory:
Initialize npm:
This creates a
package.json
file.Install Dependencies:
(You can replace
npm install
withyarn add
if you prefer using Yarn.)@vonage/server-sdk
: The Vonage Node.js library.express
: Web framework for handling webhook requests.dotenv
: To manage environment variables securely.1.2. Configure Environment Variables
Sensitive information like API keys should never be hardcoded. We'll use a
.env
file.Create
.env
file: Create a file named.env
in the root of your project directory (vonage-sms-status-guide
).Add Environment Variables: Open
.env
and add the following lines. We will fill these values in the next steps.Important: You must replace
YOUR_API_KEY
,YOUR_API_SECRET
,YOUR_APPLICATION_ID
,YOUR_VONAGE_VIRTUAL_NUMBER
, andRECIPIENT_PHONE_NUMBER
with your actual values obtained during the setup process.Create
.gitignore
: Ensure your.env
file and private key are not committed to version control. Create a.gitignore
file in the project root:1.3. Configure Vonage Account Settings
Crucially, for this guide using the Messages API for sending and receiving status updates, you must ensure the Messages API is set as the default for SMS handling in your account settings.
Default SMS Setting
is set toMessages API
. If it's set toSMS API
, change it and click Save changes.1.4. Create a Vonage Application
Vonage Applications group your virtual numbers and configurations (like webhook URLs) and use a public/private key pair for authentication when using certain APIs like the Messages API.
Node SMS Status Guide App
).private.key
file that downloads. Move this file into the root of your project directory (vonage-sms-status-guide
).ngrok
in the next step. Leave them blank for now, but keep this page open or note down the Application ID generated for this application..env
file and updateVONAGE_APPLICATION_ID
with the ID shown for your newly created application. Also, ensureVONAGE_PRIVATE_KEY_PATH
points to the location where you savedprivate.key
(e.g.,./private.key
).VONAGE_API_KEY
,VONAGE_API_SECRET
, andVONAGE_NUMBER
in your.env
file from your dashboard details. Choose aTO_NUMBER
(like your mobile) for testing.1.5. Expose Local Server with
ngrok
Webhooks require a publicly accessible URL.
ngrok
creates a secure tunnel from the internet to your local machine.Start
ngrok
: Open a new terminal window/tab (keep your project terminal open). Runngrok
, telling it to forward traffic to the port your Express server will run on (we'll use 3000).Copy the Forwarding URL:
ngrok
will display session information, including aForwarding
URL that looks something likehttps://randomstring.ngrok.io
. Copy this HTTPS URL.1.6. Configure Webhook URLs in Vonage Application
Now, link the public
ngrok
URL to your Vonage Application's message status callbacks.ngrok
HTTPS URL, appending/webhooks/status
. Example:https://randomstring.ngrok.io/webhooks/status
.https://randomstring.ngrok.io/webhooks/inbound
. This is where incoming SMS to your Vonage number would be sent.2. Implementing Core Functionality: Sending SMS
Now let's write the Node.js code to send an SMS message using the Vonage Messages API and the credentials configured in
.env
.Create
send-sms.js
: Create a file namedsend-sms.js
in your project root.Add Code to Send SMS: Paste the following code into
send-sms.js
:Explanation:
require('dotenv').config()
: Loads variables from your.env
file intoprocess.env
.Vonage
client instance. Crucially, for the Messages API, it usesapplicationId
andprivateKey
for authentication (JWT - JSON Web Token).apiKey
andapiSecret
might be used for other API calls or fallback.sendSms
Function:vonage.messages.send()
which is the correct method for the Messages API.MessagetypeText
to structure the payload correctly, definingto
,from
,channel
, and the messagetext
.messageUuid
on successful submission. This ID is crucial for correlating the sent message with its delivery status later.Test Sending:
Make sure your
.env
file is filled correctly.Make sure
private.key
is in the project root.Run the script from your project terminal:
You should see
SMS submitted successfully!
and amessageUuid
logged in the console.You should receive the SMS on the
TO_NUMBER
phone shortly after.3. Building the API Layer: Handling Status Webhooks
Now, let's create the Express server to listen for the delivery status webhook POST requests from Vonage.
Create
server.js
: Create a file namedserver.js
in your project root.Add Code for Express Server: Paste the following code into
server.js
:Explanation:
express.json()
is crucial for parsing the incoming JSON payload from Vonage webhooks intoreq.body
.express.urlencoded()
is included for completeness./webhooks/status
Route:/webhooks/status
path, matching the URL configured in the Vonage Application.message_uuid
,status
,timestamp
,error
, etc. Note: The exact field names (message_uuid
,status
, etc.) are common but can occasionally vary. Always inspect the raw logged body (console.log('Request Body: ...')
) from an actual webhook delivery to confirm the structure before relying on specific fields.200 OK
response. This tells Vonage the webhook was received successfully. If Vonage doesn't receive a 2xx response, it will retry sending the webhook, leading to duplicate processing./health
Route: A simple endpoint to check if the server is running, useful for monitoring.PORT
(matching the one used inngrok
).Run the Server:
Make sure
ngrok
is still running and forwarding to port 3000.Open your primary project terminal (where
package.json
is).Run the server:
You should see the
Server listening...
messages.Test the Full Loop:
Keep
server.js
running in one terminal andngrok
in another.Open a third terminal (or reuse one) in the project directory.
Send another SMS using
send-sms.js
:Check the phone for the SMS.
Watch the terminal where
server.js
is running. Within a few seconds to a minute (depending on the carrier), you should see the--- Delivery Status Webhook Received ---
log, followed by the JSON payload containing themessage_uuid
of the message you just sent and itsstatus
(e.g.,submitted
,delivered
,buffered
, orfailed
).4. Integrating with Vonage Service
This section summarizes the integration points covered in the setup and implementation steps.
VONAGE_API_KEY
andVONAGE_API_SECRET
are used primarily for account identification and potentially for APIs other than Messages/Voice that use basic auth. They are obtained from the main page of the Vonage API Dashboard.VONAGE_APPLICATION_ID
and theprivate.key
file (referenced byVONAGE_PRIVATE_KEY_PATH
) are essential for authenticating with the Messages API. They are generated when creating a Vonage Application in the dashboard. The private key must be stored securely and its path correctly specified in.env
.@vonage/server-sdk
is initialized using the Application ID and the path to the private key file (new Vonage({ applicationId, privateKey: privateKeyPath })
). The SDK handles the JWT generation needed for authentication.Status URL
configured in the Vonage Application settings (pointing to yourngrok
URL +/webhooks/status
) tells Vonage where to send delivery status updates via HTTP POST requests. Your Express server must listen on this specific path.5. Error Handling, Logging, and Retry Mechanisms
5.1. Error Handling
Sending (
send-sms.js
):try...catch
block captures errors during the API call.err.response.data
).Receiving (
server.js
):try...catch
block to prevent the server from crashing due to unexpected payload formats and still send a200 OK
response.5.2. Logging
messageUuid
, and detailed errors.winston
orpino
) to:5.3. Retry Mechanisms (Vonage Side)
2xx
response from your server within a timeout period.delivered
status for amessage_uuid
arrives). Check if you've already processed a specificmessage_uuid
with a terminal status before taking action.2xx
status. Perform time-consuming tasks asynchronously after sending the response.6. Database Schema and Data Layer (Conceptual)
In a production application, you'll want to store message information and status updates.
messages
table):id
(Primary Key, e.g., UUID or auto-incrementing integer)message_uuid
(VARCHAR, Unique): The ID received from Vonage upon sending. Crucial for correlation.to_number
(VARCHAR)from_number
(VARCHAR)message_body
(TEXT): The content of the sent message.submitted_at
(TIMESTAMP): When the message was submitted via the API.current_status
(VARCHAR): The latest status received ('submitted', 'delivered', 'failed', 'accepted', 'buffered', etc.).status_updated_at
(TIMESTAMP): When the latest status webhook was received.error_code
(VARCHAR, Nullable): If the status is 'failed', store the error code.error_reason
(TEXT, Nullable): Description of the error.usage_price
(DECIMAL, Nullable)usage_currency
(VARCHAR, Nullable)pg
,mysql2
).vonage.messages.send
, insert a new record into themessages
table with themessage_uuid
, recipient, sender, body, and initial status ('submitted')./webhooks/status
handler:message_uuid
andstatus
(and other relevant fields) fromreq.body
.messages
table usingmessage_uuid
.current_status
,status_updated_at
, and any error/usage details. Ensure updates are idempotent. Check if the new status is different or logically follows the current status before updating.200 OK
response immediately after receiving the request, potentially performing the database update asynchronously or ensuring it's very fast.7. Security Features
.env
locally, secure configuration management in deployment)..env
andprivate.key
are in your.gitignore
.private.key
on servers.ngrok
URL and production webhook endpoint to encrypt data in transit. Vonage requires HTTPS for webhook URLs./webhooks/status/YOUR_SECRET_TOKEN
). This is obscurity, not true security.TO_NUMBER
,VONAGE_NUMBER
) before use. Remove formatting, check length/prefix.req.body
) before accessing nested properties.express-rate-limit
) to prevent abuse if the endpoint URL is exposed.8. Handling Special Cases
delivered
andfailed
:submitted
: Message accepted by Vonage, not yet by the carrier.rejected
: Message rejected by Vonage (e.g., invalid number, insufficient funds).accepted
: Message accepted by the downstream carrier.buffered
: Message buffered by the downstream carrier (e.g., recipient device offline).expired
: Message failed to deliver within its validity period.unknown
: Final status could not be determined.message_uuid
andtimestamp
within the DLR payload.delivered
orfailed
status is never received for some messages. Consider timeouts or assumptions after a certain period.FROM
Number Regulations: Be aware of country-specific regulations regarding sender IDs. In some countries (like the US), you must use a Vonage virtual number. In others, you might be able to use an Alphanumeric Sender ID (if pre-registered). Using an invalidFROM
number will cause sending failures.9. Performance Optimizations
async/await
or Promises to avoid blocking the event loop.200 OK
/204 No Content
. Offload any slow processing (database updates, further API calls) to a background job queue (e.g., BullMQ, Kue) or handle it asynchronously after sending the response.message_uuid
column in yourmessages
table is indexed for fast lookups when processing status webhooks.10. Monitoring, Observability, and Analytics
/health
endpoint allows load balancers or monitoring services (like UptimeRobot, Pingdom) to check if your server instance is running.delivered
,failed
,buffered
, etc.).failed
delivery statuses.11. Troubleshooting and Caveats
VONAGE_API_KEY
,VONAGE_API_SECRET
,VONAGE_APPLICATION_ID
, andVONAGE_PRIVATE_KEY_PATH
. Ensure the private key file exists and is readable. Make sure you are using the correct credentials for the API (Messages API uses App ID/Key).to
orfrom
Number (400 Bad Request): Verify phone number formats (E.164 recommended, e.g.,+14155552671
). Ensure theFROM
number is a Vonage number linked to your application and capable of sending SMS in the target country.ngrok
is running and forwarding to the correct port (3000
).Status URL
in the Vonage Application settings exactly matches thengrok
HTTPS URL +/webhooks/status
.ngrok
or incoming connections.server.js
application is running and hasn't crashed.server.js
is likely not sending a2xx
response, or it's taking too long to respond. Check logs for errors and ensureres.status(200).send()
is called promptly.