Frequently Asked Questions
Send SMS messages using Node.js, Express, and the Vonage Messages API by creating a POST request to the /send-sms endpoint with the recipient's number and the message text in the request body. The server-side code then uses the Vonage SDK to handle sending the SMS through the Vonage API.
The Vonage Messages API is a multi-channel communication platform for sending and receiving messages across various channels, including SMS. This tutorial focuses on using the API for sending and receiving text messages (SMS) within a Node.js application.
Setting up Vonage involves purchasing a virtual number, creating a Vonage application, and linking the number to your application. You will need to generate public and private keys, save the private key securely and enable the messages capability and configure webhook URLs for inbound messages and delivery statuses.
ngrok creates a secure tunnel to your local server, providing a temporary public HTTPS URL. This allows Vonage to deliver webhooks to your local development environment during testing, simulating how real-world webhooks function when deployed.
Vonage uses webhooks to send real-time updates to your server. Inbound SMS messages to your Vonage number trigger a webhook to the '/webhooks/inbound' endpoint. Delivery status updates for your sent SMS messages trigger a webhook to the '/webhooks/status' endpoint.
Receive incoming SMS messages sent to your Vonage virtual number by configuring a webhook URL in your Vonage application settings that points to the '/webhooks/inbound' endpoint of your Node.js application.
Delivery status updates are received via webhooks sent to the '/webhooks/status' endpoint of your server. The webhook request will include the message UUID, the status of the delivery (e.g., 'submitted', 'delivered', 'rejected'), and a timestamp.
The project utilizes several Node.js libraries: 'express' for the web framework, '@vonage/server-sdk' for interacting with the Vonage API, 'dotenv' for managing environment variables, and optionally 'jsonwebtoken' for webhook signature verification in a production environment.
You can install the necessary dependencies (Express, the Vonage Server SDK, and dotenv) by using either 'npm install express @vonage/server-sdk dotenv' or 'yarn add express @vonage/server-sdk dotenv' in your terminal within the project directory.
Safeguard the private key by never committing it to version control and securing file permissions. In production environments, utilize environment variables provided by your hosting platform to handle sensitive information like API keys.
Webhook signature verification, especially with JWT (JSON Web Tokens), is crucial in production for confirming the authenticity of incoming webhooks. This process ensures that the incoming requests originate from Vonage and haven't been tampered with.
Common errors include ngrok timing out, credentials not being set correctly in .env, webhook URLs being wrong, private keys being handled incorrectly, and servers not running.
Vonage expects a 2xx response from your webhook endpoint to acknowledge that your server received it. Without a 2xx response, the system may assume the webhook failed and retry the request, potentially causing duplicate messages or other issues.
Vonage SMS with Node.js: Delivery Status Webhooks & Callbacks Tutorial
Build a Node.js Express server that sends SMS messages, receives inbound SMS, and handles delivery status updates via webhooks using the Vonage Messages API. This guide covers project setup, implementation, security, and deployment.
What you'll build:
Technologies you'll use:
.envfile.System Architecture:
Prerequisites:
ngrok authtoken your-tokenfor stable URLs and longer sessions.1. Set Up the Project
Initialize your Node.js project and install dependencies.
Create project directory: Open your terminal and create a new directory for the project.
Initialize Node.js project: Create a
package.jsonfile.Install dependencies: Install Express, the Vonage SDK, and dotenv.
Create project structure: Create the main application file and environment variables file.
Configure
.gitignore: Prevent committing sensitive information and dependencies.Note: Add
private.keypreemptively to ensure this sensitive file is never accidentally committed to version control.Set up environment variables (
.env): Create a.envfile in the project root. You'll populate this with credentials from Vonage later.VONAGE_APPLICATION_ID: Identifies your specific Vonage application.VONAGE_PRIVATE_KEY_PATH: Local path to the private key file for authenticating API requests.VONAGE_NUMBER: Your Vonage virtual phone number for sending SMS.MY_NUMBER: Your personal mobile number for testing (use E.164 format).PORT: Port your local Express server listens on.2. Integrate with Vonage
Configure Vonage by creating an Application and linking a number to get credentials and webhook URLs.
Log in to Vonage Dashboard: Access your Vonage API Dashboard.
Purchase a virtual number: Navigate to
Numbers→Buy numbers. Find a number with SMS capabilities in your desired country and purchase it.Create a Vonage Application:
Applications→Create a new application.Generate public and private key. Save theprivate.keyfile immediately and place it in your project's root directory.Messagescapability.Inbound URLandStatus URL(e.g.,http://example.com/webhooks/inboundandhttp://example.com/webhooks/status). Set HTTP Method toPOSTfor both. You'll update these later with your ngrok URL.Get Application ID: Copy the
Application IDdisplayed after creation.Link your virtual number:
Linked numbers.Update
.envfile: Populate your.envfile with the Application ID and Vonage virtual number.Start ngrok: Open a new terminal window and run ngrok, pointing it to port 3000.
Copy the
ForwardingHTTPS URL (e.g.,https://randomstring.ngrok.io).Configure webhook URLs in Vonage Application:
Applications→ Your App Name →Edit).Messagescapability URLs:https://randomstring.ngrok.io/webhooks/inboundhttps://randomstring.ngrok.io/webhooks/statusPOSTfor both.Webhook URL purposes:
Inbound URL: Vonage sends data about incoming SMS messages (sent to your Vonage number) here.Status URL: Vonage sends delivery status updates (e.g.,submitted,delivered,rejected) for messages you send here.3. Implement Core Functionality (Express Server)
Write the Node.js code in
server.jsto handle sending, receiving, and status updates.Code explanation:
dotenv, importsexpressandVonage, initializes Express, and sets up middleware for parsing request bodies.Vonageinstance using theapplicationIdandprivateKeypath from.env. Includes error handling if the key file is missing or credentials are not set./send-sms(POST):to(recipient number) andtext(message content) in the JSON request body.!to || !text). Note: Production applications need more robust validation (see Section 6).vonage.messages.send()with appropriate parameters (message_type,to,from,channel,text).message_uuidupon successful submission to Vonage.try...catchfor robust error handling, logging errors, and returning appropriate HTTP status codes (400 for bad input, 500 or specific Vonage status for API errors)./webhooks/inbound(POST):Inbound URLconfigured in Vonage.VONAGE_NUMBER, Vonage makes a POST request here.from), recipient (to), message content (text), and the full request body. Note: Production applications should verify the webhook signature (see Section 6).200 OKstatus usingres.status(200).end(). If Vonage doesn't receive a 2xx response, it assumes the webhook failed and retries, potentially leading to duplicate processing./webhooks/status(POST):Status URLconfigured in Vonage.submitted,delivered,failed,rejected), Vonage makes a POST request here.message_uuid(linking it back to the sent message), thestatus, timestamp, any potential error details, and the full request body. Note: Production applications should verify the webhook signature (see Section 6).200 OKstatus to acknowledge receipt.4. Running and Testing the Application
Ensure ngrok is running: Keep the terminal window where you started
ngrok http 3000open. Confirm the HTTPS URL is correctly configured in your Vonage Application settings.Start the Node.js server: In the terminal window for your project directory (where
server.jsis), run:You should see output indicating the server is listening and the Vonage SDK initialized.
Test sending SMS: Open a new terminal window or use a tool like Postman or Insomnia to send a POST request to your
/send-smsendpoint. ReplaceYOUR_PERSONAL_MOBILE_NUMBERwith the actual value from your.envfile (MY_NUMBER).Using
curl:curl: You should get a JSON response like{"message":"SMS sent successfully","message_uuid":"some-uuid-string"}.server.js: You'll see logs for the/send-smsrequest and "Message sent successfully…".server.js: Soon after, you should see logs from/webhooks/statusshowing the status changing (e.g.,submitted, then potentiallydelivered). Check themessage_uuidto match the sent message.Test receiving inbound SMS:
VONAGE_NUMBER(the one configured in.env).server.js: You should see logs from/webhooks/inboundshowing the message details (From:,To:,Text:)./webhooks/inbound.Test delivery failure (optional): Try sending an SMS to an invalid or non-existent number via the
/send-smsendpoint. Observe the/webhooks/statuslogs in yourserver.jsterminal – you should receive statuses likefailedorrejectedwith corresponding error codes/reasons.5. Error Handling and Logging
/send-smsroute includestry...catchto handle errors during the Vonage API call. It attempts to parse and return specific error details from the Vonage response./inbound,/status) encounter an error processing the request before sending the200 OK, Vonage will retry. Implement robust internal error handling within these routes if you perform complex logic (e.g., database lookups).console.logandconsole.error. For production, this is insufficient. Implement a structured logging library likewinstonorpino. This allows for better log formatting (e.g., JSON), writing logs to files or external services, setting different log levels (debug, info, warn, error), and easier log analysis. This guide does not include the implementation of structured logging.2xxstatus code response from your webhook endpoints within a reasonable time (usually a few seconds) to consider the delivery successful. Design your webhook handlers to be fast and acknowledge receipt quickly, performing heavier processing asynchronously if needed (e.g., using a message queue).6. Security Considerations
.envfile or yourprivate.keyfile to source control. Use a.gitignorefile as shown. In production, use your hosting provider's mechanism for managing environment variables securely.private.keyfile like a password. Ensure its file permissions restrict access (e.g.,chmod 400 private.keyon Linux/macOS).jsonwebtokenin your Node.js app (npm install jsonwebtoken)./webhooks/inboundand/webhooks/statusroutes to verify theAuthorization: Bearer <token>header of incoming requests against your configured secret before processing the payload. This guide does not include the JWT verification implementation. Refer to the official Vonage documentation on "Signed Webhooks" for implementation details./send-smsendpoint currently only checks iftoandtextexist. This is insufficient for production. Add more robust validation:tonumber against the E.164 standard using a library likelibphonenumber-js(npm install libphonenumber-js).textcontent could potentially come from user input elsewhere in your system, sanitize it to prevent cross-site scripting (XSS) or other injection attacks, depending on how you use the text later. This guide does not include robust input validation implementation./send-smsendpoint (either accidental or malicious), implement rate limiting. Use middleware likeexpress-rate-limit(npm install express-rate-limit) to restrict the number of requests a user can make in a given time window. Check Vonage's own API rate limits as well. This guide does not include rate limiting implementation.7. Troubleshooting and Caveats
Inbound URLandStatus URL.Error initializing Vonage SDK: Private key file not found…: VerifyVONAGE_PRIVATE_KEY_PATHin.envis correct relative to where you runnode server.js, and the file exists.VONAGE_APPLICATION_IDis correct. Ensure theprivate.keyfile content hasn't been corrupted.Logs→API Logs(or similar section) for errors related to webhook delivery failures from Vonage's side.node server.js) and didn't crash. Check server logs for errors./webhooks/inbound,/webhooks/status) return a200 OKor204 No Contentstatus quickly. Check server logs for errors within these handlers. Failure to respond quickly or with a 2xx status will cause Vonage to retry.delivered) Not Received:deliveredstatus updates back to Vonage. You will usually receivesubmitted, butdeliveredis not guaranteed.Status URLis correctly configured and your/webhooks/statusendpoint is working and returning200 OK.15551234567– the SDK often handles adding the+if needed, but being explicit is safer) fortoandfromnumbers.8. Deployment Considerations
VONAGE_APPLICATION_ID,VONAGE_PRIVATE_KEY_PATH,VONAGE_NUMBER,PORT, etc.) securely using your hosting provider's tools (e.g., Heroku Config Vars, AWS Secrets Manager, .env files managed securely on the server). Do not include the.envfile in your deployment package/repository. Securely transfer or provide theprivate.keyfile to your production server and ensure theVONAGE_PRIVATE_KEY_PATHenvironment variable points to its location on the server.pm2to keep your Node.js application running reliably in production.pm2handles automatic restarts on crashes, manages logs, enables clustering for better performance, and more.9. Verification Checklist
Before considering this production-ready:
/send-smsendpoint?/send-smsrequest in the server console?/webhooks/statusupdate (at leastsubmitted) in the server console?/webhooks/inboundmessage in the server console?200 OKor204 No Contentquickly?.env,private.key) excluded from Git?This guide provides a solid foundation for sending, receiving, and tracking SMS messages using Node.js and Vonage. Enhance logging, error handling, and especially security (webhook verification, input validation, rate limiting) based on your specific production requirements. Refer to the official Vonage Messages API documentation for further details and advanced features.