Frequently Asked Questions
Use the Vonage Messages API and Node.js SDK. Install the `@vonage/server-sdk` package, initialize a Vonage client with your API credentials, and use the `vonage.messages.send()` method with a new `SMS` object containing the recipient, sender, and message text. This allows you to send text messages programmatically.
A Vonage webhook is a mechanism for receiving real-time notifications from the Vonage APIs about events related to your application, such as delivery status updates for SMS messages or incoming messages sent to your Vonage number. Your application provides URLs where Vonage sends these updates as HTTP POST requests.
Webhooks provide reliable delivery confirmation. Sending an SMS through an API is often "fire and forget," meaning the initial response only confirms the message was *accepted*, not *delivered*. Webhooks give you real-time feedback as the message travels through the mobile network to the recipient's device.
Create a Vonage application in your dashboard, enable the Messages capability, and provide the URL of your webhook endpoint for the 'Status URL' field. This URL will receive POST requests from Vonage containing delivery updates. ngrok can be used during development to expose a local server URL.
The Vonage Messages API is a versatile API enabling you to send and receive messages across various channels, including SMS, MMS, WhatsApp, and more. This tutorial demonstrates its use specifically for sending and tracking the delivery status of SMS messages.
Set up an 'Inbound URL' for your Vonage application in the dashboard. When someone sends an SMS to your Vonage number, Vonage sends an HTTP POST request to this URL containing the message content. Your application can then process this inbound message data.
You will need Node.js and npm installed, a Vonage account (free tier is available), a rented Vonage virtual number, and ngrok installed and authenticated. The Vonage account gives you API credentials and test credits. ngrok is used to expose your local development server.
Ngrok creates a public URL that tunnels to your local development server. This is necessary because Vonage's webhooks need to reach your local machine, which isn't directly accessible from the internet. Ngrok provides the bridge between your local server and Vonage's webhooks.
Do *not* use ngrok or unprotected webhook endpoints in production. Secure your webhooks using either Signed Webhooks with a shared secret or JWT verification as described in the Vonage documentation. This prevents unauthorized parties from sending fake requests to your server.
The `message_uuid` is a unique identifier for each message sent through the Vonage Messages API. It is included in both the initial API response when sending the message and in all subsequent status webhook updates. Use it to track the lifecycle of individual messages.
Vonage provides various status updates, including 'submitted' (accepted by Vonage), 'delivered' (confirmed by the carrier), 'rejected' (rejected by Vonage or the carrier), and 'undeliverable'. Consult the Vonage documentation for a complete list and explanation of these statuses.
The Vonage Node.js SDK (`@vonage/server-sdk`) simplifies interaction with Vonage APIs within a Node.js environment. It handles the complexities of API requests and responses, making it easier to send SMS messages, receive webhooks, and work with other Vonage services.
Yes, emojis are generally supported. However, using emojis or non-GSM characters might cause the message to be encoded as Unicode, which can reduce the maximum character count per SMS part (segment). Vonage handles this, but it's something to be aware of.
The `express.json()` middleware is crucial for parsing incoming JSON data. Vonage's webhook POST requests contain the payload (delivery status, inbound message data) as JSON in the request body. Without `express.json()`, you won't be able to access this JSON data in your route handlers.
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 through webhooks.
By the end of this tutorial, you will have a functional application capable of:
This enables you to reliably send messages and track their journey to the recipient's handset, providing crucial feedback for your communication workflows.
Project Overview and Goals
What We're Building:
We will construct a simple Node.js application consisting of two main parts:
index.js
) to send an outbound SMS message using the Vonage Messages API.server.js
) to listen for incoming webhook events from Vonage, specifically:submitted
,delivered
,rejected
).Problem Solved:
Sending an SMS via an API is often a ""fire and forget"" operation. The initial API response only confirms that the message was accepted by the platform, not that it was delivered to the user's phone. Mobile carrier networks can introduce delays or failures. This guide addresses the need for reliable delivery confirmation by implementing status webhooks. It also provides the foundation for two-way communication by handling inbound messages.
Technologies Used:
@vonage/server-sdk
): Simplifies interaction with Vonage APIs within a Node.js environment..env
file intoprocess.env
.System Architecture:
Prerequisites:
1. Setting up the project
Let's create the project structure and install the necessary dependencies.
Create Project Directory: Open your terminal or command prompt and create a new directory for your project, then navigate into it.
Initialize Node.js Project: This creates a
package.json
file to manage dependencies and project metadata.Install Dependencies: We need the Vonage SDK, the Express framework, and
dotenv
for managing environment variables.Create Project Files: Create the main files for sending SMS and running the webhook server.
Configure
.gitignore
: Prevent sensitive information and unnecessary files from being committed to version control. Add the following lines to your.gitignore
file:Project Structure: Your project directory should now look like this:
2. Integrating with Vonage (Account and Application Setup)
Before writing code, we need to configure Vonage to enable communication and provide necessary credentials.
Obtain API Key and Secret:
.env
file shortly.Create a Vonage Application: Applications act as containers for your communication settings, including webhook URLs and security credentials (like private keys) needed for certain APIs like Messages.
Node SMS Status Guide App
).private.key
file that downloads. For simplicity in this guide, we recommend saving it directly into your project's root directory (vonage-sms-status-guide/
), which matches the default path we'll use in.env
. Remember that the key file's location just needs to match theVONAGE_PRIVATE_KEY_PATH
variable in your.env
file; you could place it in a dedicated subdirectory or even outside the project structure in a production scenario. We've already addedprivate.key
to.gitignore
for security regardless of location within the project.ngrok
. For now, you can leave them blank or enter placeholder URLs likehttp://example.com/inbound
andhttp://example.com/status
.Link Your Vonage Number: You need to associate your purchased Vonage virtual number with the application you just created so Vonage knows where to route incoming messages and which webhooks to use for status updates related to that number.
Configure
.env
File: Open the.env
file and add your credentials. Replace the placeholder values with your actual keys, ID, number, and your test phone number. Ensure your Vonage number andTO_NUMBER
are in E.164 format (without the leading '+').Security Note: The
.env
file should never be committed to public repositories. Ensure.env
is listed in your.gitignore
file.3. Exposing Local Server with ngrok
Vonage needs to send webhook events (status updates, inbound messages) to a publicly accessible URL. During development,
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). Run
ngrok
to forward traffic to the port your Express server will listen on (we'll use port 3000).Copy the Forwarding URL:
ngrok
will display session information, including aForwarding
URL ending in.ngrok.io
or similar (use thehttps
version). It will look something likehttps://<random-subdomain>.ngrok.io
.Action: Copy this
https://...ngrok.io
URL. Keep thisngrok
terminal window running.Update Vonage Application Webhook URLs:
YOUR_NGROK_FORWARDING_URL/webhooks/status
(e.g.,https://<random-subdomain>.ngrok.io/webhooks/status
)YOUR_NGROK_FORWARDING_URL/webhooks/inbound
(e.g.,https://<random-subdomain>.ngrok.io/webhooks/inbound
)Purpose: This tells Vonage where to send HTTP POST requests for status updates and inbound messages related to the numbers linked to this application.
4. Implementing Core Functionality (Sending SMS)
Now, let's write the code to send an SMS message using the Vonage Node.js SDK.
Edit
index.js
: Add the following code to yourindex.js
file.Code Explanation:
require('dotenv').config();
: Loads variables from your.env
file intoprocess.env
.const fs = require('fs');
: Imports Node.js's built-in file system module, needed to read the private key file.require('@vonage/server-sdk')
: Imports the main Vonage SDK class.require('@vonage/messages')
: Imports specific message types (likeSMS
) for the Messages API.new Vonage(...)
: Initializes the Vonage client. For the Messages API v1 (used for sending SMS, WhatsApp, etc.), authentication primarily relies on theapplicationId
and the associatedprivateKey
content for enhanced security and linking capabilities like webhooks. TheprivateKey
option requires the actual key data, not the file path, hence the use offs.readFileSync()
. Debug mode ({ debug: true }
) provides verbose logging from the SDK, useful during development.sendSms
function:to
,from
, andtext
as arguments.vonage.messages.send()
which is the core method for the Messages API.new SMS(...)
object specifying the message details. The SDK handles structuring the request correctly for the API.async/await
for cleaner handling of the promise returned bysend()
.messageUuid
upon successful submission to Vonage. This ID is crucial for correlating status updates.sendSms
with values from.env
.5. Building the API Layer (Webhook Server)
This Express server will listen for HTTP POST requests from Vonage at the URLs we configured (
/webhooks/status
and/webhooks/inbound
).Edit
server.js
: Add the following code to set up the Express server and webhook endpoints.Code Explanation:
require('express')
: Imports the Express framework.app = express()
: Creates an Express application instance.PORT
: Defines the port to listen on, defaulting to 3000.express.json()
andexpress.urlencoded()
: These are essential for parsing the incoming request bodies sent by Vonage. Vonage typically sends webhook data as JSON./webhooks/status
Route:POST
handler for the status URL.req.body
: Contains the parsed payload from Vonage.message_uuid
,status
,timestamp
,error
fields) and update your system accordingly (e.g., mark a message as delivered in a database).res.status(204).send()
: Crucial: Sends an HTTP204 No Content
response back to Vonage. Vonage requires a2xx
status code to confirm successful receipt. If it doesn't receive one within a timeout period, it will retry sending the webhook, potentially leading to duplicate processing./webhooks/inbound
Route:POST
handler for the inbound URL.params.from.number
), the message text (params.text
), etc.204 No Content
response./
Route: A simpleGET
route for checking if the server is running via a browser or health check tool.app.listen()
: Starts the server and makes it listen for connections on the specified port.6. Verification and Testing
Let's run the application and verify that SMS sending and webhook handling work correctly.
Start the Webhook Server: In your primary terminal window (in the
vonage-sms-status-guide
directory), start the Express server.You should see output confirming the server is listening on port 3000.
Ensure ngrok is Running: Check the other terminal window where you started
ngrok
. It should still be running and showSession Status online
. If not, restart it (ngrok http 3000
) and re-update the webhook URLs in your Vonage application settings if the forwarding URL changed.Send a Test SMS: In a third terminal window/tab (or stop and restart the
server.js
process after sending if you only have two), run theindex.js
script to send the SMS.index.js
terminal):Attempting to send SMS...
Message sent successfully!
Message UUID: <a-long-unique-identifier>
SMS send request initiated.
Check Your Phone: You should receive the SMS message on the phone number specified in
TO_NUMBER
within a few seconds to a minute.Monitor the Webhook Server Console: Watch the terminal where
server.js
is running. As the message progresses through the network, Vonage will send POST requests to your/webhooks/status
endpoint via ngrok.server.js
terminal):--- Incoming Request ---
) for each webhook call.--- Status Webhook Received ---
followed by the JSON payload.status
values. Common statuses include:submitted
: The message has been accepted by Vonage and sent towards the carrier.delivered
: The carrier confirmed successful delivery to the handset. (This is the goal!)rejected
: Vonage or the carrier rejected the message (checkerror
field for reason).undeliverable
: The carrier could not deliver the message (e.g., invalid number, phone off for extended period).message_uuid
you saw logged byindex.js
.(Optional) Test Inbound SMS:
VONAGE_NUMBER
).server.js
console again.server.js
terminal):--- Incoming Request ---
--- Inbound Webhook Received ---
followed by the JSON payload containing the message details (sender number, text content, etc.).Verification Checklist:
server.js
starts without errors.ngrok
is running and forwarding to the correct port (3000)./webhooks/status
and/webhooks/inbound
.node index.js
logs aMessage UUID
and no errors.TO_NUMBER
).server.js
logs show incoming requests to/webhooks/status
.message_uuid
and progress through statuses (e.g.,submitted
->delivered
)./webhooks/inbound
inserver.js
.7. Error Handling, Logging, and Retries
index.js
script includes basictry...catch
blocks to handle errors during SDK initialization or thesend
call. It logs detailed API errors if available.server.js
includes a basic final error handling middleware, but production applications should have more specific error handling within routes.to
orfrom
number format (use E.164), insufficient funds, network issues. Theerror
object in status webhooks provides codes and reasons for failures.console.log
andconsole.error
for basic logging.debug: true
option provides verbose internal logging. Disable this in production.2xx
status code within a specific timeout (usually a few seconds). This is why quickly sendingres.status(204).send()
is vital.message_uuid
and status before taking action.8. Security Considerations
.env
locally, system environment variables in production) and ensure.env
andprivate.key
are in.gitignore
.express-rate-limit
.9. Troubleshooting and Caveats
.env
.VONAGE_PRIVATE_KEY_PATH
in.env
points correctly to yourprivate.key
file and that the file exists and is readable.server.js
is running and listening on the correct port (3000).http://127.0.0.1:4040
by default) to see if requests are hitting ngrok but maybe not reaching your server.express.json()
middleware is correctly configured inserver.js
.delivered
status is best-effort based on carrier reporting.submitted
is generally very reliable.+
(e.g.,+14155552671
), Vonage APIs typically accept the format without the+
as well (e.g.,14155552671
). This guide uses the format without the+
in the.env
file and code examples for consistency.10. Deployment and Next Steps
.env
file. EnsureVONAGE_PRIVATE_KEY_PATH
points to the correct location of your key file on the server, or consider storing the key content directly in an environment variable (ensure proper handling of newlines if doing this).process.env.PORT
).message_uuid
,to
,from
,text
,timestamp
) and update their status based on webhook events.vonage.messages.send()
.