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:
- Sending an SMS Message: Programmatically send an SMS message to a specified phone number using the Vonage Messages API.
- Receiving Delivery Status Updates: Set up a webhook endpoint to receive real-time status updates (e.g.,
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:
- Node.js: A JavaScript runtime environment for building server-side applications.
- Express: A minimal and flexible Node.js web application framework used to create the webhook endpoint.
- Vonage Messages API: A unified API for sending messages across various channels, including SMS. We'll use it for its robustness and multi-channel capabilities.
@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:
+-----------------+ +---------------------+ +-----------------+
| Your Node.js App|----->| Vonage Messages API |----->| Carrier Network |-----> User's Phone
| (Express Server)| | (sends SMS) | | |
| - Send Script | +---------------------+ +-------+---------+
| - Webhook Ep. |<-----+ (status update) (delivery report) |
+-----------------+ | |
^ | |
| +------------------------------------+
| (ngrok tunnel for local dev)
+-------+---------+
| ngrok Service |
+-----------------+
(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:
- Sending an SMS message via a simple script.
- Running an Express server with a webhook endpoint (
/webhooks/status
). - Receiving and logging delivery status updates sent by Vonage to your webhook.
Prerequisites:
- Node.js and npm: Installed on your system (LTS version recommended). Download Node.js
- Vonage API Account: Sign up for a free account. Vonage Signup
- You'll need your API Key_ API Secret.
- You'll need to create a Vonage Application and get its Application ID and generate/download a Private Key.
- You need at least one Vonage virtual phone number capable of sending SMS.
ngrok
: Installed and authenticated. Download ngrok (A free account is sufficient).- A personal phone number to receive test SMS messages.
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.
mkdir vonage-sms-status-guide cd vonage-sms-status-guide
-
Initialize Node.js Project: Initialize npm to create a
package.json
file.npm init -y
-
Install Dependencies: We need
express
for the web server_@vonage/server-sdk
to interact with the Vonage API_ anddotenv
to manage environment variables.npm install express @vonage/server-sdk dotenv
-
Create Project Structure: Create the necessary files and directories.
touch index.js send-sms.js .env .gitignore
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.# .gitignore node_modules/ .env private.key # Or your actual private key filename
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.# .env VONAGE_API_KEY=YOUR_VONAGE_API_KEY VONAGE_API_SECRET=YOUR_VONAGE_API_SECRET VONAGE_APPLICATION_ID=YOUR_VONAGE_APPLICATION_ID VONAGE_PRIVATE_KEY_PATH=./private.key # Ensure this matches the actual path and filename of your downloaded private key VONAGE_NUMBER=YOUR_VONAGE_VIRTUAL_NUMBER # Add the recipient number for testing the send script TO_NUMBER=YOUR_PERSONAL_PHONE_NUMBER
- Replace
YOUR_PERSONAL_PHONE_NUMBER
with your actual mobile number in E.164 format (e.g._14155552671
). - We will obtain the other values in the next section.
- Replace
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.
- Navigate to Account Settings in the left sidebar.
- Scroll down to the API Settings section.
- Under Default SMS Setting_ select Messages API.
- Click Save changes.
- Why? Vonage has legacy APIs. Selecting Messages API ensures consistency in sending behavior and webhook formats used in this guide.
-
Create a Vonage Application: The Messages API requires an application context for authentication using a private key.
- Navigate to Applications in the left sidebar.
- Click + Create a new application.
- Give your application a name (e.g._
SMS Status Guide App
). - Click Generate public and private key. This will automatically download the
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. - Security Note: Placing the key in the project root is shown for development simplicity. For production_ store keys securely outside your codebase (e.g._ using secrets management tools) and ensure strict file permissions.
- Enable the Messages capability.
- You will see fields for Status URL and Inbound URL. We will fill these later when we have our
ngrok
URL. For now_ you can leave them blank or enter temporary placeholders likehttp://example.com/status
. - Click Generate new application.
- You will be taken to the application details page. Copy the Application ID and paste it into your
.env
file forVONAGE_APPLICATION_ID
.
-
Link Your Vonage Number: You need to link your Vonage virtual number to the application you just created.
- On the application details page_ scroll down to the Link virtual numbers section.
- Find your Vonage number in the list and click the Link button next to it.
- Copy your Vonage virtual number (in E.164 format) and paste it into your
.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:// send-sms.js require('dotenv').config(); // Load environment variables from .env file const { Vonage } = require('@vonage/server-sdk'); const { Auth } = require('@vonage/auth'); // --- Configuration --- const VONAGE_API_KEY = process.env.VONAGE_API_KEY; const VONAGE_API_SECRET = process.env.VONAGE_API_SECRET; const VONAGE_APPLICATION_ID = process.env.VONAGE_APPLICATION_ID; const VONAGE_PRIVATE_KEY_PATH = process.env.VONAGE_PRIVATE_KEY_PATH; const VONAGE_NUMBER = process.env.VONAGE_NUMBER; const TO_NUMBER = process.env.TO_NUMBER; // Recipient number from .env // Input validation basic check if (!VONAGE_API_KEY || !VONAGE_API_SECRET || !VONAGE_APPLICATION_ID || !VONAGE_PRIVATE_KEY_PATH || !VONAGE_NUMBER || !TO_NUMBER) { console.error("Error: Missing required environment variables. Please check your .env file."); process.exit(1); // Exit if configuration is missing } // --- Initialize Vonage --- // Use Application ID and Private Key for authentication with Messages API const credentials = new Auth({ apiKey: VONAGE_API_KEY_ apiSecret: VONAGE_API_SECRET_ applicationId: VONAGE_APPLICATION_ID_ privateKey: VONAGE_PRIVATE_KEY_PATH_ }); const options = {}; // Optional: Add any client options here if needed const vonage = new Vonage(credentials_ options); // --- Send SMS Function --- async function sendSms(textMessage) { console.log(`Attempting to send SMS from ${VONAGE_NUMBER} to ${TO_NUMBER}`); try { const resp = await vonage.messages.send({ message_type: "text"_ text: textMessage_ to: TO_NUMBER_ from: VONAGE_NUMBER_ channel: "sms" }); console.log(`SMS submitted successfully! Message UUID: ${resp.messageUuid}`); return resp.messageUuid; // Return the ID for potential tracking } catch (err) { console.error("Error sending SMS:"); // Log the detailed error response if available if (err.response && err.response.data) { console.error(JSON.stringify(err.response.data_ null_ 2)); } else { console.error(err); } throw err; // Re-throw the error for upstream handling if needed } } // --- Execute Sending --- // Immediately invoke the function when the script is run (async () => { const messageContent = `Hello from Vonage! Sent at: ${new Date().toLocaleTimeString()}`; try { await sendSms(messageContent); console.log("Script finished."); } catch (error) { console.error("Script failed to send SMS."); process.exit(1); // Exit with error code if sending failed } })(); // IIFE (Immediately Invoked Function Expression) to run async code
-
Code Explanation:
require('dotenv').config()
: Loads variables from the.env
file intoprocess.env
.- Configuration: Retrieves necessary credentials and numbers from
process.env
. Includes basic validation. - Initialize Vonage:
- We use
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.
- We use
sendSms
Function:- An
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.
- Success: Logs the
messageUuid
, which is crucial for correlating status updates. - Error Handling: Uses a
try...catch
block to catch errors during the API call. It logs detailed error information if available in the Vonage response (err.response.data
).
- An
- Execute Sending: An IIFE is used to run the
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.
node send-sms.js
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:// index.js require('dotenv').config(); // Load environment variables first const express = require('express'); const app = express(); const PORT = process.env.PORT || 3000; // Use environment port or default to 3000 // --- Middleware --- // Vonage sends webhooks typically as JSON app.use(express.json()); // Optional: Handle URL-encoded data if needed, though status webhooks are usually JSON app.use(express.urlencoded({ extended: true })); // --- Webhook Endpoint for Delivery Status --- // Vonage will POST status updates to this route app.post('/webhooks/status', (req, res) => { const statusUpdate = req.body; console.log(""--- Received Status Update ---""); // Log the entire payload for inspection console.log(JSON.stringify(statusUpdate, null, 2)); // Example: Extract key information const { message_uuid, status, timestamp, to, from, error } = statusUpdate; console.log(`Status for message ${message_uuid}: ${status}`); if (timestamp) console.log(`Timestamp: ${timestamp}`); if (to) console.log(`To: ${to}`); if (from) console.log(`From: ${from}`); // Handle specific statuses (example) if (status === 'delivered') { console.log(""Message successfully delivered!""); // IMPLEMENTATION POINT: Update your application state (e.g., database) } else if (status === 'failed' || status === 'rejected') { console.error(`Message delivery failed or rejected.`); if (error) { console.error(`Reason: Code ${error.code} - ${error.reason}`); } // IMPLEMENTATION POINT: Trigger alerts or retry logic if applicable } else { console.log(`Received status: ${status}`); } // --- IMPORTANT: Respond to Vonage --- // Always send a 2xx status code quickly to acknowledge receipt. // Failure to do so will cause Vonage to retry the webhook delivery. res.status(200).send('OK'); // Alternatively use res.status(204).send(); for 'No Content' response }); // --- Basic Health Check Endpoint --- app.get('/health', (req, res) => { res.status(200).json({ status: 'UP', timestamp: new Date().toISOString() }); }); // --- Start Server --- app.listen(PORT, () => { console.log(`Server listening on port ${PORT}`); console.log(`Webhook endpoint available at /webhooks/status`); console.log(`Health check available at /health`); console.log(""Waiting for status updates from Vonage...""); });
-
Code Explanation:
- Initialization: Sets up Express and defines the port.
- Middleware:
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):- This is the route Vonage will send status updates to.
req.body
: Contains the JSON payload from Vonage.- Logging: Logs the entire payload and key fields like
message_uuid
,status
,timestamp
. This is crucial for debugging. - Status Handling: Includes example
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. - Response (
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.- Server Start: Starts the Express server listening on the specified port.
ngrok
5. Running Locally and Testing with 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:
node index.js
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).ngrok http 3000
-
Get
ngrok
URL:ngrok
will display output similar to this:Session Status online Account Your Name (Plan: Free) Version x.x.x Region United States (us-cal-1) Web Interface http://127.0.0.1:4040 Forwarding https://<random-string>.ngrok-free.app -> http://localhost:3000 Connections ttl opn rt1 rt5 p50 p90 0 0 0.00 0.00 0.00 0.00
Copy the
https://<random-string>.ngrok-free.app
URL. This is your public webhook URL. -
Update Vonage Application Status URL:
- Go back to your Vonage Application settings in the dashboard.
- Find the application you created earlier (
SMS Status Guide App
). - Click the Edit button.
- In the Capabilities section, find the Messages capability.
- Paste your full
ngrok
URL into the Status URL field, appending/webhooks/status
. It should look like:https://<random-string>.ngrok-free.app/webhooks/status
- (Optional but recommended): You can also set the Inbound URL to
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
). - Scroll down and click Save changes.
-
Verification: Send a Test SMS:
-
Go back to the terminal where your
node index.js
server is not running. -
Run the send script again:
node send-sms.js
-
Note the
messageUuid
logged by the script.
-
-
Observe Webhook:
- Watch the terminal where your
node index.js
server is running. - Within a few seconds to minutes (depending on the carrier), you should see the "--- Received Status Update ---" log message, followed by the JSON payload from Vonage.
- Verify that the
message_uuid
in the webhook payload matches the one logged bysend-sms.js
. - Check the
status
field (e.g.,submitted
,delivered
,failed
). You might receive multiple updates for a single message as it progresses.
- Watch the terminal where your
-
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:
- Consistent Error Handling: Use a dedicated error handling middleware in Express for cleaner error management. Catch errors in async route handlers and pass them to the middleware using
next(err)
. - Robust Logging: Replace
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. - Webhook Retries: Vonage automatically retries webhook delivery if it doesn't receive a
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). - Idempotency: Design your webhook handler to be idempotent. If Vonage retries a webhook (e.g., due to a temporary network issue), your handler might receive the same status update multiple times. Use the
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:
- Webhook Signature Verification (Highly Recommended): Vonage can sign webhook requests allowing you to verify they originated from Vonage.
- Check Vonage Docs: Consult the latest Vonage Messages API documentation for details on enabling and verifying signed webhooks (often using HMAC-SHA256 with your API Secret or a dedicated signing secret). The
@vonage/server-sdk
might offer helper functions for this. - Implementation: If available, use the SDK or manually implement signature verification before processing the
req.body
. Reject requests with invalid signatures immediately.
- Check Vonage Docs: Consult the latest Vonage Messages API documentation for details on enabling and verifying signed webhooks (often using HMAC-SHA256 with your API Secret or a dedicated signing secret). The
- HTTPS:
ngrok
provides HTTPS URLs, and your production deployment must use HTTPS to protect data in transit. - IP Allowlisting: As an additional layer (or alternative if signature verification isn't feasible), configure your firewall or load balancer to only allow requests to your webhook endpoint from Vonage's known IP address ranges. Vonage publishes these ranges – ensure you keep the list updated.
- Input Sanitization: Although the data comes from Vonage, sanitize any data from the webhook before using it in database queries or other sensitive operations to prevent potential injection attacks if the data format unexpectedly changes.
- Rate Limiting: Implement rate limiting on your webhook endpoint (e.g., using
express-rate-limit
) to prevent potential abuse or denial-of-service if your endpoint is exposed accidentally. - Environment Variables: Never hardcode credentials. Use environment variables managed securely in your deployment environment.
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):
CREATE TABLE sms_messages ( message_uuid VARCHAR(255) PRIMARY KEY, -- Vonage Message UUID vonage_number VARCHAR(20) NOT NULL, recipient_number VARCHAR(20) NOT NULL, message_content TEXT, submitted_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP, last_status VARCHAR(50), last_status_timestamp TIMESTAMPTZ, final_status VARCHAR(50), -- 'delivered', 'failed', 'expired', etc. error_code VARCHAR(50), error_reason TEXT, created_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP, updated_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP ); CREATE TABLE sms_status_updates ( id SERIAL PRIMARY KEY, message_uuid VARCHAR(255) REFERENCES sms_messages(message_uuid), status VARCHAR(50) NOT NULL, status_timestamp TIMESTAMPTZ NOT NULL, raw_payload JSONB, -- Store the full webhook payload received_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP );
-
Implementation:
- Use an ORM like Prisma or Sequelize to manage the schema and interactions.
- When sending (
send-sms.js
): Insert a new record intosms_messages
with themessage_uuid
and initial details. - In the webhook handler (
index.js
):- Find the corresponding record in
sms_messages
usingmessage_uuid
. - Insert a new record into
sms_status_updates
. - Update the
last_status
,last_status_timestamp
, and potentiallyfinal_status
,error_code
,error_reason
in thesms_messages
table.
- Find the corresponding record in
9. Special Cases and Handling
- Status Codes: Familiarize yourself with Vonage's delivery status codes (
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 Concatenation: Long SMS messages are split into multiple parts but share the same
message_uuid
. Your status updates might reflect individual parts or the message as a whole depending on the carrier and Vonage processing. - Carrier Delays: Delivery receipts can be delayed or, in some rare cases (specific countries/carriers), not supported or provided. Your application should handle potential timeouts or lack of a final 'delivered' status.
- Timestamp Timezones: Webhook timestamps (
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 Checks: The
/health
endpoint is a basic start. Production systems often require more detailed checks (e.g., database connectivity). - Metrics: Track key metrics: SMS sent count, delivery success rate (delivered / (delivered + failed + expired)), failure counts by error code, webhook processing latency. Use libraries like
prom-client
to expose metrics for Prometheus/Grafana. - Error Tracking: Integrate with error tracking services like Sentry or Bugsnag to capture and alert on exceptions in both the sending script and the webhook handler.
- Logging Aggregation: Use a log aggregation platform (ELK stack, Datadog Logs, Grafana Loki) to centralize logs for easier searching and analysis.
11. Troubleshooting and Caveats
ngrok
Issues:- Ensure
ngrok
is running and the correct URL (HTTPS) is configured in the Vonage dashboard Status URL. - Free
ngrok
accounts have limitations (e.g., URLs expire). Restartngrok
and update the Vonage dashboard if needed. - Firewalls might block
ngrok
.
- Ensure
- Vonage Configuration Errors:
- Incorrect API Credentials/App ID/Private Key: Double-check
.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. - Messages API Not Default: Verify the account setting for Default SMS Setting.
- Number Not Linked: Ensure the Vonage number is linked to the correct application.
- Incorrect Status URL: Verify the URL format (
https://..../webhooks/status
) in the Vonage application settings.
- Incorrect API Credentials/App ID/Private Key: Double-check
- Code Errors:
- Check server logs (
node index.js
output) for errors during webhook processing. - Check send script logs (
node send-sms.js
output) for API errors during sending. - Ensure
dotenv
is loading variables correctly (console.log(process.env.VONAGE_API_KEY)
early in the script to test).
- Check server logs (
- No Webhooks Received:
- Verify the SMS was actually sent successfully (check
send-sms.js
log formessageUuid
). - Check the Vonage dashboard for API logs or error reports related to webhook delivery failures.
- Confirm
ngrok
is running and accessible. - Wait sufficient time – carrier delivery reports can take time.
- Verify the SMS was actually sent successfully (check
- Delivery Failures (
failed
/rejected
status):- Check the
error.code
anderror.reason
in the webhook payload. - Consult Vonage documentation for the meaning of specific error codes. Common reasons include invalid recipient number format, blocked number, carrier restrictions, insufficient account funds.
- Check the
- API vs. Delivery: Remember that a successful API response from
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)
- Environment Variables: In production, manage
.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. - Deployment:
- PaaS (Heroku, Render, etc.): Configure Procfile (
web: node index.js
), push code, set environment variables via the dashboard/CLI. - Docker: Create a
Dockerfile
to containerize the application. Manage theprivate.key
securely (e.g., mount as a volume or use Docker secrets). - Server: Deploy code, install dependencies, manage environment variables, use a process manager like PM2 to keep the server running.
- PaaS (Heroku, Render, etc.): Configure Procfile (
- CI/CD Pipeline (e.g., GitHub Actions, GitLab CI):
- Lint & Format: Check code style.
- Test: Run unit and integration tests.
- Build (if needed): e.g., Build Docker image.
- Deploy: Push code/image to the hosting environment. Manage secrets carefully during deployment.
- Webhook URL in Production: Use your application's public domain name instead of the
ngrok
URL in the Vonage Application Status URL settings. Ensure it's HTTPS. - Private Key Handling: The private key file needs to be securely transferred to the production environment and referenced by the
VONAGE_PRIVATE_KEY_PATH
environment variable. Do not store it in version control.