Frequently Asked Questions
Use the Vonage Messages API and Node.js SDK. The `sendSms` function in the provided code demonstrates how to initialize the Vonage client and send an SMS message using your API credentials and a Vonage virtual number. It handles asynchronous delivery receipts via webhook, and it includes error handling using try-catch blocks. It includes a clientRef that you can use to correlate messages with your internal system identifiers.
The Vonage Messages API is a multi-channel communication platform that allows you to send SMS, MMS, WhatsApp messages, and more. In this Node.js application, it's used to send SMS messages and configure status webhooks to receive delivery updates.
Vonage uses the Status URL to send real-time delivery receipts (DLRs) to your application as webhooks. This lets your application know the status of sent messages (e.g., delivered, failed) asynchronously, without having to poll the API. You must use a publicly accessible URL like one provided by ngrok during development or your production server's URL for receiving these updates.
Update the Vonage Application's Status URL in the Vonage Dashboard *before* sending an SMS message, or after restarting your application. This ensures that Vonage knows where to send delivery status updates to your webhook endpoint.
Yes, use ngrok to create a secure tunnel to your locally running Express server. This provides a public HTTPS URL that Vonage can use to reach your webhook endpoint during development. Update your `.env` file's BASE_URL and your application's Status URL on Vonage Dashboard with this ngrok URL. Be sure to stop and restart your application after setting this URL.
Set up a webhook endpoint in your Node.js Express application (e.g., `/webhooks/status`) and configure this URL as the Status URL in your Vonage application settings. The webhook endpoint receives real-time delivery status updates from the Vonage API, typically a few seconds to a minute after the message has been sent, depending on network availability.
The Vonage Application ID is a unique identifier for your application within the Vonage platform. It's used along with your private key to authenticate requests to the Messages API and link your virtual numbers and webhooks to your application.
The private key is crucial for secure authentication with the Vonage Messages API. It's used to generate JWTs (JSON Web Tokens) for requests, ensuring only authorized applications can send messages and access related data. Never expose your private key publicly and never commit it to version control.
Use ngrok during local development to expose your local webhook server to the public internet so Vonage can send delivery status updates to your webhook endpoint. Ngrok isn't needed in production once deployed to a server with a public URL.
Implement webhook signature verification using `verifySignature` method from `@vonage/server-sdk`. This ensures requests are from Vonage, preventing spoofing attacks. Configure signature secret in Vonage account settings. This step is critical for production.
The 'delivered' status in a Vonage delivery receipt (DLR) webhook indicates that the SMS message has successfully reached the recipient's mobile handset. Not all carriers or countries reliably report this final status. Sometimes the status might remain 'submitted' or 'accepted', even if delivered. Thorough testing is necessary. If you are getting 'submitted', try texting to a different carrier.
Verify ngrok is running and that the URL matches the Status URL configured in your Vonage account. If the Node.js server is running and no webhooks are received, also confirm no firewall is blocking incoming traffic. Inspect the ngrok inspection interface to see if the requests are being received. If the requests are not being received, check the Vonage Status page for system issues. Also check that the recipient number and virtual number formats are valid. Ensure you are responding to the Vonage webhook with a 2xx status code. Ensure your application has Messages set as the default SMS API.
The `clientRef` is an optional user-defined reference string when sending SMS messages using the Vonage API. It lets you associate a unique identifier from your system with each message, allowing for easier tracking, logging, and reconciliation within your own application logic. It appears in status webhooks and logs.
This guide provides a step-by-step walkthrough for building a Node.js application using the Express framework to send SMS messages via the Vonage Messages API and receive real-time delivery status updates via webhooks.
Project Goal: Create a reliable system to send SMS messages programmatically and track their delivery status, ensuring you know whether a message reached the recipient's handset.
Core Problems Solved:
Technologies Used:
.env
file intoprocess.env
.System Architecture:
delivered
,failed
). Vonage then triggers a webhook event based on this DLR.Final Outcome: A Node.js application capable of sending an SMS message and logging its delivery status received via a webhook.
Prerequisites:
npm install -g @vonage/cli
. You may need your API Key/Secret for initial CLI setup.1. Vonage Account and API Setup
Before writing code, configure your Vonage account and application settings.
VONAGE_NUMBER
.Node SMS Status App
).private.key
). Save this file securely. For this guide, we suggest placing it in your project directory and adding it to.gitignore
.http://localhost:3000/webhooks/inbound
andhttp://localhost:3000/webhooks/status
. We will update the Status URL later with our ngrok URL.2. Project Setup
Initialize the Node.js project and install necessary dependencies.
Create Project Directory:
Initialize Node.js Project:
Install Dependencies:
@vonage/server-sdk
: The official Vonage Node.js library.express
: Web framework to create the webhook endpoint.dotenv
: To manage environment variables securely.Create Project Structure:
Configure Environment Variables (
.env
): Create a file named.env
in the project root and add the following, replacing the placeholder values with your actual credentials and details:VONAGE_APPLICATION_ID
: The ID of the Vonage application you created.VONAGE_PRIVATE_KEY_PATH
: The file path relative to your project root where you saved theprivate.key
file. (Adjust if using a different storage method).VONAGE_NUMBER
: The E.164 formatted Vonage virtual number linked to your application.TO_NUMBER
: The E.164 formatted phone number you want to send the test SMS to.PORT
: The port your local Express server will run on.BASE_URL
: This will hold the public URL generated by ngrok. We'll use it to tell Vonage where to send webhooks.Configure Git Ignore (
.gitignore
): Create a.gitignore
file to prevent committing sensitive information and unnecessary files:3. Implementing Core Functionality: Sending SMS & Handling Status Webhooks
Now, let's write the Node.js code.
index.js
:Code Explanation:
require('dotenv').config()
loads variables from your.env
file.fs.readFileSync
reads the private key file content. Error handling is added here.new Vonage(...)
creates the Vonage client instance.applicationId
and the content of theprivateKey
.sendSms
Function:text
andrecipient
number as arguments.vonage.messages.send()
with anSMS
object containingto
,from
, andtext
.from
number must be the Vonage virtual number linked to your Application ID.clientRef
is an optional field you can use to correlate messages with your internal system identifiers.messageUuid
. This UUID is crucial for tracking the message status.async/await
withtry/catch
for handling the API call result. Enhanced error logging provides more details if the API call fails.app
) is created.express.json()
andexpress.urlencoded()
middleware are essential for parsing incoming webhook request bodies (Vonage sends JSON payloads)./webhooks/status
):app.post('/webhooks/status', ...)
defines the route that will listen for delivery status updates from Vonage.req.body
(the webhook payload) for inspection. This is very helpful during development.status
(e.g.,submitted
,delivered
,rejected
,failed
),message_uuid
,to
,from
,timestamp
, and anyerror
details.204 No Content
status code usingres.status(204).send()
. This acknowledges receipt to Vonage. If you don't send a2xx
response quickly, Vonage will assume the webhook failed and will retry, potentially leading to duplicate processing on your end.TODO
comment reminds you where to add signature verification.app.listen()
starts the server on the specifiedPORT
.BASE_URL
environment variable to remind the developer to configure ngrok and update the.env
file.setTimeout
shows how you might trigger thesendSms
function for testing.if (require.main === module)
ensures thestart()
function only runs when the script is executed directly.4. Running and Testing with ngrok
To receive webhooks from Vonage on your local machine, you need to expose your local server to the internet using ngrok.
Start ngrok: Open a new terminal window/tab (keep the one for your Node app separate) and run:
Get ngrok URL: ngrok will display output similar to this:
Copy the
https
Forwarding URL (e.g._https://xxxxxxxxxxxx.ngrok.io
). This is your public base URL.Update
.env
File: Open your.env
file and set theBASE_URL
:Save the
.env
file.Update Vonage Application Status URL:
Node SMS Status App
).YOUR_NGROK_HTTPS_URL/webhooks/status
(e.g._https://xxxxxxxxxxxx.ngrok.io/webhooks/status
).Start Your Node.js Application: In the terminal where your project code resides_ run:
You should see the server start message and the configured webhook URL. If you see an error reading the private key_ ensure the path in
.env
is correct and the file exists.Trigger the SMS Send: To send an SMS immediately on startup for testing_ modify the
start()
function inindex.js
like this:Stop (
Ctrl+C
) and restart your Node app (node index.js
) after saving this change. Remember to revert this change or use a different trigger mechanism for non-testing scenarios.Observe Output:
messageUuid
.delivered
,failed
, etc.).POST /webhooks/status 204 No Content
).http://127.0.0.1:4040
): You can inspect the incoming requests and responses in detail here, which is excellent for debugging.5. Error Handling and Logging
sendSms
function includes atry...catch
block. It logs specific Vonage API errors if available (err.response.data
) or the general error message. In production, you'd integrate this with a more robust logging framework (like Winston or Pino) and potentially an error tracking service (like Sentry).2xx
to Vonage quickly. Log the error for later investigation.2xx
response. Your primary responsibility is to ensure your endpoint is reliable and responds quickly. For the outgoing SMS, if the initialsendSms
API call fails due to transient network issues, you could implement a retry mechanism (e.g., using libraries likeasync-retry
) with exponential backoff before considering the send failed.6. Security Considerations
.env
file orprivate.key
to version control. Use environment variables or a secrets management system in production. Consider loading the private key content directly from an environment variable instead of a file path for added security in some deployment scenarios.Authorization
header of webhook requests, signed using this secret.verifySignature
method from the@vonage/server-sdk
within your/webhooks/status
handler before processing the request body. This step is essential for any production application. This guide does not include the implementation code for signature verification, but you can find details and examples in the Vonage documentation on Signed Webhooks.sendSms
function, ensurerecipient
numbers are in the expected format (E.164).express-rate-limit
).7. Troubleshooting and Caveats
401 Unauthorized
Error on Sending: Double-checkVONAGE_APPLICATION_ID
. EnsureVONAGE_PRIVATE_KEY_PATH
in.env
points to a validprivate.key
file and that the Node.js process has read permissions for it. Verify the key content itself is correct.TO_NUMBER
is correct and includes the country code (E.164 format).VONAGE_NUMBER
is linked to theVONAGE_APPLICATION_ID
in the dashboard.VONAGE_NUMBER
). Using the number itself is generally more reliable.https://
URL is correct.YOUR_NGROK_HTTPS_URL/webhooks/status
. A typo here is common.http://127.0.0.1:4040
) to see if requests are arriving but maybe failing (non-2xx response).private.key
Permissions / Read Error: Ensure the Node.js process has read permissions for theprivate.key
file and the path in.env
is correct relative to where you runnode index.js
.BASE_URL
in.env
and the Status URL in the Vonage dashboard. Paid ngrok plans offer stable subdomains.delivered
status). The status might remainsubmitted
oraccepted
(meaning accepted by the carrier) even if delivered. Test thoroughly in your target regions.delivered
is the confirmation you're looking for when available.8. Deployment Considerations (Beyond Localhost)
.env
files). Pass the private key content via an environment variable if possible, rather than deploying the key file.npm install -g pm2
) to keep your Node.js application running reliably, manage logs, and handle restarts. (pm2 start index.js --name vonage-sms-status
)messageUuid
,status
,timestamp
,clientRef
) in a database for tracking, analytics, and auditing. Update the status in your database when the webhook arrives.9. Verification and Testing
sendSms
function (e.g., using the modifiedstart
function or another method).TO_NUMBER
phone.Message submitted successfully! Message UUID: ...
).--- Delivery Status Webhook Received ---
).status: delivered
).http://127.0.0.1:4040
to inspect the exact request payload received from Vonage and the204 No Content
response sent back by your app.TO_NUMBER
(if possible, check Vonage documentation for test numbers that simulate failures). Observe if afailed
orrejected
status webhook is received.submitted
or eventually becomesexpired
. Turn the phone back on; it might update todelivered
later (depending on carrier retry logic and message validity period).Conclusion
You have successfully built a Node.js application using Express that can send SMS messages via the Vonage Messages API and receive delivery status updates through webhooks. This provides crucial visibility into whether your messages are reaching their destination.
Remember that for production environments, implementing webhook signature verification is critical for security. Additionally, robust error handling, logging, and secure credential management are essential.
Next Steps:
Inbound URL
and adding a corresponding route handler.