Frequently Asked Questions
Use the Vonage Messages API and Node.js SDK. Install the @vonage/server-sdk
package, initialize the Vonage client with your API credentials, and then use the messages.send()
method, providing the recipient's number, your Vonage number, and the message text. This allows you to programmatically send SMS messages from your Node.js application.
A Vonage Delivery Receipt (DLR) is a webhook notification that provides real-time updates on the delivery status of your SMS messages. These updates include statuses like 'delivered', 'rejected', 'failed', or 'undeliverable', giving you insights into whether your message reached the recipient's handset or encountered issues along the way. The information is crucial for applications requiring delivery confirmation.
While Vonage confirms message submission, it doesn't guarantee delivery. Webhooks offer asynchronous delivery updates. The /webhooks/status
endpoint in your app receives these updates, allowing you to react to successful deliveries or handle failures without blocking your main application flow.
Use the Vonage Messages API when you need to send and receive messages programmatically across different channels, including SMS. It's ideal for applications that require confirmation that messages have been successfully delivered to the recipient's device, providing reliable message delivery handling.
Create a Vonage application in the Vonage Dashboard, enable the 'Messages' capability, and configure the 'Status URL' to point to your Express app's webhook route (e.g., YOUR_BASE_URL/webhooks/status
). When Vonage sends a DLR POST request, your app must respond with '200 OK' to acknowledge receipt, ensuring Vonage doesn't retry.
ngrok creates a public tunnel to your local development server. This is crucial for testing webhooks during development, as Vonage needs a publicly accessible URL to send DLR callbacks to your /webhooks/status
endpoint when running locally.
Log in to your Vonage API Dashboard. Your API key and API secret are displayed on the main homepage. Copy these values and paste them into your .env
file (or other secure storage mechanism) as VONAGE_API_KEY
and VONAGE_API_SECRET
respectively.
The Vonage private key, downloaded when you create a Vonage Application, is crucial for authenticating your application with the Messages API. It's used along with your Application ID to ensure secure API access. Never commit this key to Git; use environment variables or a secure secret store.
A 401 Unauthorized error usually indicates incorrect or missing Vonage API credentials. Double-check your VONAGE_API_KEY
, VONAGE_API_SECRET
, VONAGE_APPLICATION_ID
, and VONAGE_PRIVATE_KEY_PATH
in your .env
file. Verify they match the values in your Vonage Dashboard, and that the private key file exists and is readable.
Check that your webhook endpoint (/webhooks/status
) is publicly accessible (ngrok for development). Ensure it responds with a 200 OK within a few seconds. Verify your Vonage Application's 'Status URL' is correctly set to the public URL, and the default SMS setting is 'Messages API', not 'SMS API'.
For enhanced security, use Signed Webhooks by configuring a webhook signing key in your Vonage Application. Your webhook handler should verify the signature in the request header using this key, preventing spoofing. See the Vonage documentation for details on Signed Webhooks.
Statuses like 'delivered' mean the message reached the handset. 'rejected' or 'failed' indicate delivery failures. 'undeliverable' suggests a permanent issue, while 'expired' means the message timed out before successful delivery. Check Vonage DLR documentation for a comprehensive list of statuses.
Yes, using an invalid or test phone number is a good way to test failure paths and see how your application handles DLR statuses like 'failed', 'rejected', or 'undeliverable', providing insights into your application's error handling.
Your /webhooks/status
endpoint should handle potential errors (e.g., database issues) gracefully. Use try...catch
blocks. Always return a 200 OK
to Vonage first, even if your internal processing fails, to avoid Vonage webhook retries. Log the error and handle it separately, potentially using a retry queue.
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. Understanding message delivery status is crucial for applications requiring confirmation that messages have reached the recipient's handset.
Project Goals:
Problem Solved:
While the Vonage API confirms successful submission of an SMS request almost instantly, this doesn't guarantee delivery to the end user's device. Network issues, carrier limitations, or invalid numbers can prevent delivery. This guide implements the webhook mechanism needed to get asynchronous confirmation (or failure notifications) from the mobile carrier network via Vonage.
Technologies Used:
@vonage/server-sdk
): Simplifies interaction with Vonage APIs within a Node.js environment..env
file intoprocess.env
.System Architecture:
Final Outcome:
By the end of this guide_ you will have a running Node.js Express application capable of:
Prerequisites:
1. Setting up the Project
Let's create the project structure_ install dependencies_ and configure the environment.
Create Project Directory: Open your terminal and create a new directory for your project_ then navigate into it.
Initialize Node.js Project: Initialize the project using npm_ accepting the defaults.
This creates a
package.json
file.Install Dependencies: Install Express for the web server_ the Vonage Server SDK_ and
dotenv
for environment variable management.express
: Web framework.@vonage/server-sdk
: Official Vonage SDK for Node.js.dotenv
: Loads environment variables from.env
.Create Project Structure: Create a basic structure for clarity.
src/server.js
: Main application code..env
: Stores sensitive credentials and configuration (DO NOT commit to Git)..gitignore
: Specifies intentionally untracked files that Git should ignore.Configure
.gitignore
: Addnode_modules
and.env
to your.gitignore
file to prevent committing them. Also explicitly ignore private key files.Set Up Environment Variables (
.env
): Open the.env
file and add the following variables. You'll obtain these values in the next section. Replace placeholders later.Explanation:
VONAGE_API_KEY
,VONAGE_API_SECRET
: Authenticate basic API requests. Found on your Vonage Dashboard homepage.VONAGE_APPLICATION_ID
,VONAGE_PRIVATE_KEY_PATH
: Used by the Messages API for authentication. You'll generate these. The path points to where you'll save the private key file. Security Warning: While.gitignore
prevents committing the key file during development, storing private keys directly in the project structure is not recommended for production. Use secure secrets management practices, such as environment variables injected by your hosting platform or a dedicated secrets manager.VONAGE_NUMBER
: The Vonage virtual number used to send the SMS. Must include the country code (e.g.,12015550123
).APP_PORT
: The port your local Express server listens on.BASE_URL
: The publicly accessible URL for your application. The initiallocalhost
value is a placeholder; it will be replaced by the public URL provided by ngrok, which is essential for Vonage to send webhooks to your local server during development.2. Configuring Vonage
Now, let's configure the necessary components in your Vonage account.
Get API Key and Secret:
API key
andAPI secret
..env
file forVONAGE_API_KEY
andVONAGE_API_SECRET
.Set Default SMS API (Important):
API settings
->Default SMS Setting
.Messages API
is selected as the default. This is critical; it ensures delivery receipts for messages sent via the Messages API are routed to the webhook URL configured in your Vonage Application. If the olderSMS API
is selected, DLRs might not arrive at your expected endpoint.Save changes
.Create a Vonage Application: The Messages API requires a Vonage Application for authentication and webhook configuration.
Applications
->Create a new application
.Node SMS DLR Guide App
).private.key
file. Save this file in the root directory of your project (the same level aspackage.json
and.env
). EnsureVONAGE_PRIVATE_KEY_PATH
in your.env
file points to this location (./private.key
). Vonage stores the public key.Messages
capability.YOUR_BASE_URL/webhooks/status
. ReplaceYOUR_BASE_URL
with a placeholder for now, likehttp://example.com/webhooks/status
. We will update this later with the actual ngrok URL. This is the endpoint Vonage will send delivery receipts to.YOUR_BASE_URL/webhooks/inbound
. This endpoint would receive incoming SMS replies (not the focus of this guide, but required by the Application setup). Use the same placeholder base URL.Generate new application
..env
file forVONAGE_APPLICATION_ID
.Link Your Vonage Number:
Linked numbers
section.Link
button next to it. This associates incoming messages and status updates for this number with your application's webhooks..env
file forVONAGE_NUMBER
.3. Implementing the Express Server
Let's write the code for our Express server to handle API requests and incoming webhooks.
Open
src/server.js
and add the following code:Code Explanation:
dotenv
,express
, and theVonage
SDK. Initializes Express.express.json()
andexpress.urlencoded()
to parse incoming request bodies.Vonage
client instance using credentials from.env
. It usespath.resolve
to construct an absolute path to the private key, ensuring it's found correctly regardless of the directory from which the Node.js script is executed./ping
Route: A simple health check endpoint./send-sms
Route (POST):to
(recipient number) andtext
(message content) from the JSON request body.to
number format (allows optional leading+
).vonage.messages.send()
with the required parameters (message_type
,text
,to
,from
,channel
).async/await
for cleaner handling of the promise returned by the SDK.message_uuid
on success or an error message on failure. Includes improved error logging from the Vonage response if available./webhooks/status
Route (POST):status
,message_uuid
,to
,timestamp
, and error details if present).200 OK
response immediately to acknowledge receipt. Failure to do so will cause Vonage to retry the webhook delivery./webhooks/inbound
Route (POST):200 OK
response.APP_PORT
.4. Running Locally with ngrok
To receive webhooks from Vonage on your local machine, you need to expose your local server to the internet. ngrok creates a secure tunnel for this.
Start ngrok: Open a new terminal window (keep the one for the server running later). Run ngrok, telling it to forward to the port your Express app listens on (defined by
APP_PORT
in.env
, which is3000
).Get Forwarding URL: ngrok will display session information, including a
Forwarding
URL that looks something likehttps://<random-string>.ngrok-free.app
. Copy thehttps
URL.Update BASE_URL (Temporary for Dev):
.env
file.BASE_URL
variable with thehttps
URL you just copied from ngrok. Make sure there's no trailing slash.BASE_URL
in.env
is primarily used here to make it easy to copy the URL into the Vonage Dashboard configuration. Your application code itself might not need to referenceprocess.env.BASE_URL
directly unless it needs to construct self-referential URLs.Update Vonage Application Webhooks:
Applications
-> Your App Name).Edit
.YOUR_NGROK_HTTPS_URL/webhooks/status
(e.g.,https://<random-string>.ngrok-free.app/webhooks/status
).YOUR_NGROK_HTTPS_URL/webhooks/inbound
.Save changes
.Why update Vonage? Vonage needs the public ngrok URL to know where to send the status and inbound webhooks.
5. Verification and Testing
Now, let's run the application and test the SMS sending and delivery receipt process.
Start the Node.js Server: In the terminal window where your project code is located, run:
You should see the output:
Server listening at http://localhost:3000
.Send an SMS using
curl
(or Postman): Open another terminal window. ReplaceYOUR_PHONE_NUMBER
with your actual mobile phone number (including country code, e.g.,+14155551212
) andYOUR_NGROK_URL
with your actual ngrok Forwarding URL. Use a generic message.Check Server Logs (Sending): Look at the terminal where your
node src/server.js
command is running. You should see logs indicating the attempt to send and the success response from Vonage, including themessage_uuid
:Check Your Phone: You should receive the SMS message on the phone number you specified.
Check Server Logs (Delivery Receipt): Wait a few seconds (delivery times vary). Watch the same server log terminal. You should see the incoming webhook request logged by the
/webhooks/status
endpoint. The timestamp will reflect the actual time of the event.status
. Common values includesubmitted
,delivered
,rejected
,undeliverable
,expired
.message_uuid
: Matches the ID returned when you initially sent the message. This allows you to correlate the status update with the original outbound message.Test Failure Case (Optional): Try sending to an invalid or non-existent number (if you know one that reliably fails). You should receive a DLR with a status like
failed
orrejected
, potentially with an error code.6. Error Handling and Logging
Production applications need more robust error handling and logging.
console.log
andconsole.error
with a structured logger likewinston
orpino
. This enables log levels, formatting, and easier integration with log management systems./send-sms
route, log detailed error information received from the Vonage API (err.response.data
) when available. This is crucial for debugging API interaction issues.try...catch
block.200 OK
to Vonage to prevent retries of the same webhook. Handle the internal failure separately (e.g., add to a retry queue).status
field (e.g., update a database record, notify an administrator on failure)..env
and Vonage configuration. Ensure the private key file path is correct and readable.to
number, missingtext
). Check request payload and API documentation./webhooks/status
endpoint takes too long to respond (> 3-5 seconds), Vonage will consider it failed and retry. Ensure your handler is fast and only performs essential processing before responding200 OK
. Offload heavy processing to a background job if necessary.7. Security Considerations
.env
file orprivate.key
file to version control (Git). Use.gitignore
./send-sms
) and webhooks. The example includes basic validation forto
andtext
. Use libraries likejoi
orexpress-validator
for more complex validation./send-sms
endpoint from abuse by implementing rate limiting (e.g., usingexpress-rate-limit
).8. Troubleshooting and Caveats
submitted
). Refer to Vonage SMS Features documentation for country-specific details.SMS API
is the default, Vonage may attempt to route delivery receipts via a different, unconfigured mechanism, and they will likely not arrive at theStatus URL
defined in your Vonage Application, even if you use the Messages API SDK to send the message./webhooks/status
) must be publicly accessible via HTTPS for Vonage to reach it. ngrok handles this in development. In production, ensure your server is correctly deployed and accessible, and that firewalls allow incoming POST requests from Vonage IP ranges if applicable.200 OK
status code quickly (within 3-5 seconds). Non-2xx responses or timeouts will cause Vonage to retry delivery, potentially leading to duplicate processing if not handled idempotently.VONAGE_PRIVATE_KEY_PATH
in.env
correctly points to theprivate.key
file downloaded during application creation, and that the Node.js process has read permissions for this file. Usingpath.resolve
helps, but file existence and permissions are still crucial.Logs
section in your Vonage Dashboard. Search for yourmessage_uuid
. It often provides details on API call errors or webhook delivery failures (including reasons like connection timeouts or non-200 responses from your webhook URL).@vonage/server-sdk
. Check the SDK's documentation if you encounter unexpected behavior.9. Deployment and CI/CD (Conceptual)
Deploying this application involves moving beyond ngrok.
VONAGE_API_KEY
,VONAGE_API_SECRET
,VONAGE_APPLICATION_ID
,VONAGE_NUMBER
,APP_PORT
,VONAGE_PRIVATE_KEY
- potentially the key content itself, not the path) securely using your hosting provider's mechanisms. Do not include the.env
file or theprivate.key
file directly in your deployment package.https://your-app-name.herokuapp.com
). Update theStatus URL
andInbound URL
in your Vonage Application settings to use this production URL.node src/server.js
(or similar).pm2
in production environments (if deploying to VMs/containers) to handle restarts, clustering, and monitoring.npm install pm2 -g
, then start withpm2 start src/server.js --name vonage-sms-app
.10. Conclusion and Next Steps
You have successfully built a Node.js Express application that can send SMS messages using the Vonage Messages API and receive delivery status updates via webhooks. This provides crucial visibility into message delivery success.
Further Enhancements:
message_uuid
,to
,status
,timestamp
) in a database to track history and query message status. Update the status in the/webhooks/status
handler./send-sms
endpoint./webhooks/inbound
endpoint to process replies from users.This guide provides a solid foundation. Remember to consult the official Vonage Messages API documentation for more advanced features and details.