Frequently Asked Questions
Use the Vonage Messages API with the @vonage/server-sdk in your Node.js application. The sendSms function demonstrates how to send text messages by specifying the recipient, sender, and message content. Remember to set up your API key, secret, application ID, private key path, and phone numbers correctly in your .env file.
The Vonage Messages API is a unified interface for sending various types of messages, including SMS. It offers robust features and multi-channel capabilities, making it suitable for applications needing reliable messaging and status tracking.
Webhooks provide real-time delivery status updates, including 'delivered,' 'failed,' or 'rejected,' directly to your application. This approach eliminates the need for constant polling and allows for immediate responses to message statuses, enabling better reliability and logging.
ngrok is essential during local development to expose your local server and receive webhooks from Vonage. For production deployments, you must use your server's public HTTPS URL configured in your Vonage application settings.
Yes, by setting up a webhook endpoint (e.g., /webhooks/status) in your Node.js application. Vonage will send real-time status updates to this endpoint, which you can then process to track deliveries, failures, and other events.
First, install the @vonage/server-sdk package. Then, configure your Vonage account, create an application, and obtain the necessary credentials (API Key, API Secret, Application ID, and Private Key). Finally, initialize the Vonage client in your Node.js code using these credentials.
The private key, along with the application ID, is crucial for authenticating your Node.js application with the Vonage Messages API and is the standard method when an application context is needed. This ensures secure communication and prevents unauthorized access to your account.
Responding with a 2xx status code (like 200 OK) is mandatory to acknowledge successful receipt of the Vonage webhook. Failure to respond correctly will cause Vonage to retry the webhook, leading to potential duplicate processing.
Design your webhook handler to be idempotent using the message_uuid, ensuring it can process the same status update multiple times without causing issues. If processing is lengthy, respond with 200 OK immediately and process asynchronously.
Check the error code and reason in the webhook payload. Common reasons include an invalid recipient number, the recipient blocking the number, carrier-specific restrictions, or insufficient funds in your Vonage account.
Store the message UUID, sender and recipient numbers, content, timestamps, status updates, and any error codes. Consider the provided conceptual database schema as a starting point.
Consult the Vonage Messages API documentation. They might use HMAC-SHA256 with your API secret or a dedicated webhook signing secret. Check if the Vonage SDK offers helper functions for signature verification.
Long SMS are split, but share a message UUID. Status updates may be per part or as a whole. Your logic should accommodate this, potentially grouping status updates by message UUID.
Implement webhook signature verification to prevent unauthorized requests. Use HTTPS, IP whitelisting if possible, and input sanitization to minimize security risks.
Vonage retries webhook delivery if your endpoint doesn't return a 2xx HTTP status code within a short time frame, indicating that the message hasn't been processed successfully.
Developer guide: Sending SMS and receiving delivery status callbacks with Node.js, Express, and Vonage
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 reliably receive delivery status updates through webhooks.
Project Overview and Goals
We will build a Node.js application that demonstrates two core functionalities:
delivered
,failed
,rejected
) for the messages sent.This solves the common need for applications to not only send notifications or messages via SMS but also to track their delivery success, enabling better reliability, logging, and user feedback.
Technologies Used:
@vonage/server-sdk
: The official Vonage Node.js SDK for interacting with the API.dotenv
: A module to load environment variables from a.env
file for secure credential management.ngrok
: A tool to expose local development servers to the internet, necessary for testing webhooks during local development. Production deployments will use your server's public URL.System Architecture:
(Note: For published documentation_ consider replacing this ASCII diagram with an image for consistent rendering across different platforms.)
Final Outcome:
By the end of this guide_ you will have a functional Node.js application capable of:
/webhooks/status
).Prerequisites:
ngrok
: Installed and authenticated. Download ngrok (A free account is sufficient).1. Setting up the Project
Let's initialize the project_ install dependencies_ and set up the basic structure.
Create Project Directory: Open your terminal and create a new directory for your project_ then navigate into it.
Initialize Node.js Project: Initialize npm to create a
package.json
file.Install Dependencies: We need
express
for the web server_@vonage/server-sdk
to interact with the Vonage API_ anddotenv
to manage environment variables.Create Project Structure: Create the necessary files and directories.
index.js
: Main file for the Express server (webhook listener).send-sms.js
: Script to trigger sending an SMS message..env
: Stores sensitive credentials (API keys_ etc.)..gitignore
: Specifies files/directories Git should ignore.Configure
.gitignore
: Addnode_modules
and.env
to your.gitignore
file to prevent committing dependencies and sensitive credentials.Note: We also add
private.key
assuming you might save the downloaded key file directly in the project root during development.Warning: While convenient for local development_ storing private keys directly in the project folder carries risks. Never commit your private key file to version control (Git). Ensure
.gitignore
correctly lists the key file name.Configure
.env
File: Open the.env
file and add placeholders for your Vonage credentials. We will fill these in later.YOUR_PERSONAL_PHONE_NUMBER
with your actual mobile number in E.164 format (e.g._14155552671
).2. Integrating with Vonage
Now_ let's configure your Vonage account_ create an application_ and obtain the necessary credentials.
Log in to Vonage Dashboard: Access your Vonage API Dashboard.
Find API Key and Secret: Your API Key and Secret are displayed prominently on the main dashboard page. Copy these values and paste them into your
.env
file forVONAGE_API_KEY
andVONAGE_API_SECRET
.Set Default SMS API: It's crucial to ensure your account uses the Messages API for sending SMS_ as this guide relies on it.
Create a Vonage Application: The Messages API requires an application context for authentication using a private key.
SMS Status Guide App
).private.key
file. Save this file securely. For development_ you can place it in your project's root directory (as configured in.env
). Vonage typically names thisprivate.key
_ but ensure the path you set in.env
matches the exact filename and location where you saved it.ngrok
URL. For now_ you can leave them blank or enter temporary placeholders likehttp://example.com/status
..env
file forVONAGE_APPLICATION_ID
.Link Your Vonage Number: You need to link your Vonage virtual number to the application you just created.
.env
file forVONAGE_NUMBER
.Update
.env
with Private Key Path: Ensure theVONAGE_PRIVATE_KEY_PATH
in your.env
file correctly points to the location where you saved the downloaded private key file (e.g._./private.key
if it's in the root and namedprivate.key
). Remember to match the actual filename if it differs.Your
.env
file should now contain your actual credentials (except for the webhook URLs_ which we'll handle later).3. Implementing Core Functionality: Sending SMS
Let's write the script to send an SMS message using the Vonage Node.js SDK and the Messages API.
Edit
send-sms.js
: Open thesend-sms.js
file and add the following code:Code Explanation:
require('dotenv').config()
: Loads variables from the.env
file intoprocess.env
.process.env
. Includes basic validation.Auth
withapplicationId
andprivateKey
as this is the required authentication method for sending via the Messages API when an application context is needed (which is standard practice). While the API Key/Secret are included in theAuth
object, the Application ID and Private Key primarily drive authentication for this Messages API operation; the Key/Secret might be leveraged by other SDK functionalities or legacy API interactions.new Vonage(credentials, options)
creates the Vonage client instance.sendSms
Function:async
function handles the asynchronous API call.vonage.messages.send({...})
: The core method call.message_type: "text"
: Specifies a standard text message.text
: The content of the SMS.to
: The recipient's phone number (from.env
).from
: Your Vonage virtual number (from.env
).channel: "sms"
: Explicitly defines the channel.messageUuid
, which is crucial for correlating status updates.try...catch
block to catch errors during the API call. It logs detailed error information if available in the Vonage response (err.response.data
).async sendSms
function immediately when the script executes (node send-sms.js
).Test Sending (Optional - Before Webhook Setup): You can test sending now, although you won't receive status updates yet.
You should see output indicating success or failure and receive the SMS on your personal phone. Keep the logged
messageUuid
handy.4. Building the API Layer: Webhook Endpoint for Status Updates
Now, we'll create the Express server and the webhook endpoint (
/webhooks/status
) to receive delivery status updates from Vonage.Edit
index.js
: Openindex.js
and add the following code for the Express server:Code Explanation:
express.json()
: Parses incoming JSON request bodies (Vonage status webhooks use JSON).express.urlencoded()
: Parses URL-encoded bodies (less common for status webhooks but included for completeness)./webhooks/status
Endpoint (POST):req.body
: Contains the JSON payload from Vonage.message_uuid
,status
,timestamp
. This is crucial for debugging.if/else if
blocks to demonstrate how you might react to different statuses (delivered
,failed
,rejected
). This is where you would integrate with your application's logic (e.g., updating a database). TheIMPLEMENTATION POINT
comments highlight these areas.res.status(200).send('OK')
): Critically important. You must respond with a2xx
status code (like 200 or 204) quickly. If Vonage doesn't receive a timely2xx
response, it assumes the delivery failed and will retry sending the webhook, leading to duplicate processing./health
Endpoint (GET): A simple endpoint to check if the server is running.5. Running Locally 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 Your Local Server: Open a terminal in your project directory and run:
You should see "Server listening on port 3000..." (or your configured port).
Start
ngrok
: Open a second terminal window (leave the first one running your server). Runngrok
to tunnel traffic to your local server's port (e.g., 3000).Get
ngrok
URL:ngrok
will display output similar to this:Copy the
https://<random-string>.ngrok-free.app
URL. This is your public webhook URL.Update Vonage Application Status URL:
SMS Status Guide App
).ngrok
URL into the Status URL field, appending/webhooks/status
. It should look like:https://<random-string>.ngrok-free.app/webhooks/status
https://<random-string>.ngrok-free.app/webhooks/inbound
if you plan to handle incoming SMS replies later (requires adding a/webhooks/inbound
route inindex.js
).Verification: Send a Test SMS:
Go back to the terminal where your
node index.js
server is not running.Run the send script again:
Note the
messageUuid
logged by the script.Observe Webhook:
node index.js
server is running.message_uuid
in the webhook payload matches the one logged bysend-sms.js
.status
field (e.g.,submitted
,delivered
,failed
). You might receive multiple updates for a single message as it progresses.Inspect with
ngrok
Web Interface: You can also open thengrok
Web Interface (usuallyhttp://127.0.0.1:4040
) in your browser to see incoming requests to your tunnelled endpoint in real-time, inspect headers, and replay requests for debugging.6. Error Handling, Logging, and Retries (Considerations)
While the basic logging is in place, here's how to enhance it for production:
next(err)
.console.log
with a structured logging library like Winston or Pino. Log levels (info, warn, error), timestamps, and request IDs make debugging easier. Log status updates to a persistent store or logging service.2xx
response. Ensure your endpoint responds quickly. If your processing logic is slow, acknowledge the request immediately (res.status(200).send()
) and perform the processing asynchronously (e.g., using a job queue like BullMQ or Kue).message_uuid
and potentially thetimestamp
or a unique webhook attempt ID (if provided by Vonage) to ensure you don't process the same update twice. Store processedmessage_uuid
+status
combinations temporarily if needed.7. Security Features
Securing your webhook endpoint is crucial:
@vonage/server-sdk
might offer helper functions for this.req.body
. Reject requests with invalid signatures immediately.ngrok
provides HTTPS URLs, and your production deployment must use HTTPS to protect data in transit.express-rate-limit
) to prevent potential abuse or denial-of-service if your endpoint is exposed accidentally.8. Database Schema and Data Layer (Example Consideration)
For production use, you'll likely want to store SMS details and status updates.
Why Store Data? Tracking message history, auditing, analytics, providing status feedback to users, handling retries based on failure codes.
Example Schema (Conceptual):
Implementation:
send-sms.js
): Insert a new record intosms_messages
with themessage_uuid
and initial details.index.js
):sms_messages
usingmessage_uuid
.sms_status_updates
.last_status
,last_status_timestamp
, and potentiallyfinal_status
,error_code
,error_reason
in thesms_messages
table.9. Special Cases and Handling
submitted
,delivered
,failed
,expired
,rejected
,accepted
,unknown
, etc.). Handlefailed
andrejected
specifically, potentially logging theerror.code
anderror.reason
provided in the webhook. Consult the official Vonage documentation for detailed explanations of all status and error codes.message_uuid
. Your status updates might reflect individual parts or the message as a whole depending on the carrier and Vonage processing.timestamp
field) are typically in UTC. Store them appropriately (e.g.,TIMESTAMPTZ
in PostgreSQL) and convert to local timezones only for display purposes.10. Monitoring, Observability, and Analytics (Considerations)
/health
endpoint is a basic start. Production systems often require more detailed checks (e.g., database connectivity).prom-client
to expose metrics for Prometheus/Grafana.11. Troubleshooting and Caveats
ngrok
Issues:ngrok
is running and the correct URL (HTTPS) is configured in the Vonage dashboard Status URL.ngrok
accounts have limitations (e.g., URLs expire). Restartngrok
and update the Vonage dashboard if needed.ngrok
..env
values. Ensure the private key file path (VONAGE_PRIVATE_KEY_PATH
) is correct, matches the actual filename, and the file is readable by your application.https://..../webhooks/status
) in the Vonage application settings.node index.js
output) for errors during webhook processing.node send-sms.js
output) for API errors during sending.dotenv
is loading variables correctly (console.log(process.env.VONAGE_API_KEY)
early in the script to test).send-sms.js
log formessageUuid
).ngrok
is running and accessible.failed
/rejected
status):error.code
anderror.reason
in the webhook payload.vonage.messages.send
only means Vonage accepted the message for delivery, not that it was delivered. The webhook provides the actual delivery status.12. Deployment and CI/CD (Conceptual)
.env
variables securely using your hosting provider's mechanism (e.g., Heroku Config Vars, AWS Secrets Manager, Docker secrets). Never commit.env
files or private keys to Git.web: node index.js
), push code, set environment variables via the dashboard/CLI.Dockerfile
to containerize the application. Manage theprivate.key
securely (e.g., mount as a volume or use Docker secrets).ngrok
URL in the Vonage Application Status URL settings. Ensure it's HTTPS.VONAGE_PRIVATE_KEY_PATH
environment variable. Do not store it in version control.