Frequently Asked Questions
Set up a Vonage application, enable the Messages API, and configure the Status URL to point to your Fastify webhook endpoint (e.g., 'https://your-app.com/webhooks/status'). Use ngrok for local development to expose your server publicly. Ensure the Messages API is the default in your Vonage settings for correct webhook handling. Finally, link your Vonage number to the application to receive delivery receipts.
The Vonage Messages API status webhook sends a JSON payload to your specified endpoint. This payload includes details such as 'message_uuid', 'to', 'from', 'timestamp', 'status', 'usage', 'client_ref', and 'error' (if any). Each field provides information about the delivery status of your sent message, including success, failure reasons, and cost information.
Vonage retries sending the status webhook if it doesn't receive a 2xx HTTP response (like 200 OK) from your server within a certain timeframe. This ensures your application receives crucial delivery updates even if there are temporary network issues or server downtime. It's essential to always reply with 200 OK, even if processing the status update fails internally. Handle such failures asynchronously after acknowledging the webhook receipt.
Use the Messages API when you need unified messaging capabilities across different channels (SMS, WhatsApp, Viber, etc.) or require the latest features and status reporting. The Messages API provides a more flexible and robust platform, while the SMS API is the older, simpler version primarily for basic SMS functionalities. The tutorial specifically uses the Messages API and its associated webhooks.
Always respond with a 200 OK status to Vonage, even if your internal processing encounters errors. Log the error details for debugging, and implement asynchronous mechanisms (like queues) to retry processing the failed status updates later. This prevents Vonage from continuously retrying the webhook delivery and allows you to manage failures gracefully.
Ngrok creates a secure tunnel that exposes your locally running Fastify server to the public internet. This is necessary for Vonage to deliver webhooks to your development environment, as your local machine typically doesn't have a publicly accessible IP address or HTTPS setup.
Use the Vonage Node.js SDK (`@vonage/server-sdk`) with your API credentials and call `vonage.messages.send()`. Provide the recipient's number, your Vonage virtual number, and the message text. The example code includes a '/send-test-sms' route that demonstrates this functionality using environment variables for configuration. You can access this route to trigger a test SMS easily.
A Vonage Application ID is a unique identifier for your application within the Vonage platform. It's created when you set up an application in the Vonage API Dashboard. You'll need this ID, along with your private key, to authenticate with the Vonage APIs, including the Messages API used for sending SMS and receiving status updates. The private key is downloaded when creating the application.
Yes, you can use any available port. Update the `PORT` environment variable and the ngrok command accordingly (e.g., `ngrok http 8080`). Also, ensure your Fastify server listens on the correct port and that the Vonage Status URL is updated to reflect the new port and ngrok URL if used locally.
While Vonage doesn't offer built-in signature verification for status webhooks like it does for inbound messages, you can improve security through obscurity. Use a long, random, hard-to-guess path for your webhook endpoint (e.g., `/webhooks/status/xyz123`). While not foolproof, this makes accidental discovery or simple scans less likely. It's crucial to secure your API credentials and private key.
Common reasons include: ngrok not running, incorrect Status URL in the Vonage Application settings, firewalls blocking incoming connections, Vonage number not linked to the application, or using the legacy SMS API instead of the Messages API, which results in a different webhook format. Check logs for clues or consult Vonage documentation.
This guide provides a step-by-step walkthrough for building a Node.js application using the Fastify framework to receive real-time delivery status updates for SMS messages sent via the Vonage Messages API. Knowing the final delivery status is crucial for understanding message reachability and ensuring reliable communication.
We will cover setting up the project, configuring Vonage, implementing the webhook handler in Fastify, sending a test message, and verifying the status updates. We'll also touch upon essential aspects like error handling, security, and deployment.
Project Overview and Goals
Goal: To create a reliable webhook endpoint using Fastify that listens for and processes SMS delivery status updates sent by the Vonage Messages API.
Problem Solved: When you send an SMS message using an API, the initial success response only confirms that the message was accepted by the platform (Vonage) for sending. It doesn't guarantee delivery to the recipient's handset. This application solves that by providing real-time feedback from the carrier network about the message's final status (e.g., delivered, failed, rejected).
Technologies Used:
@vonage/server-sdk
: The official Vonage Node.js SDK for interacting with the Vonage APIs.ngrok
(for local development): A tool to expose local servers to the public internet, necessary for Vonage webhooks to reach your development machine.dotenv
: A module to load environment variables from a.env
file intoprocess.env
.System Architecture:
Outcome: By the end of this guide, you will have a running Fastify application capable of:
POST
requests from Vonage on a specific webhook endpoint (/webhooks/status
).Prerequisites:
node -v
.npm -v
oryarn -v
.ngrok
: Installed and authenticated (a free account is sufficient). Download from ngrok.com. Note:ngrok
provides a temporary public URL for local development. For production, you will need a stable, permanent public URL for your server.1. Setting up the Project
Let's initialize our Node.js project and install the necessary dependencies.
Create Project Directory: Open your terminal 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.(Alternatively, use
yarn init -y
if you prefer yarn)Install Dependencies: We need Fastify, the Vonage SDK, and
dotenv
for managing environment variables. We also install@fastify/formbody
as good practice, although Messages API status webhooks typically use JSON.(Alternatively, use
yarn add fastify @vonage/server-sdk dotenv @fastify/formbody
)Create Project Files: Create the main application file and files for environment variables and git ignore rules.
Configure
.gitignore
: Prevent sensitive files and unnecessary directories from being committed to version control. Add the following to your.gitignore
file:Set Up Environment Variables (
.env
): Create a file named.env
in the root of your project. This file will store your sensitive credentials and configuration. Never commit this file to Git.VONAGE_API_KEY
&VONAGE_API_SECRET
: Found at the top of your Vonage API Dashboard.VONAGE_APPLICATION_ID
&VONAGE_PRIVATE_KEY_PATH
: Obtained in the next section when creating a Vonage Application. Theprivate.key
file will be downloaded. Important: Ideally, store this file outside your project directory for better security (e.g., in~/.vonage/private.key
) and update theVONAGE_PRIVATE_KEY_PATH
in your.env
file accordingly. Storing it in the project root is possible but less secure, even with.gitignore
.VONAGE_NUMBER
: The virtual phone number you purchased in the Vonage Dashboard under 'Numbers'.YOUR_PHONE_NUMBER
: Your actual mobile number to receive test messages.PORT
: The port your Fastify server will run on locally (e.g.,3000
).2. Configuring Vonage for Messages API and Webhooks
To receive delivery status updates, you need a Vonage Application configured correctly for the Messages API.
Ensure Messages API is Default:
SMS API
, switch it to Messages API.Create a Vonage Application:
Fastify SMS Status App
).private.key
file. Save this file securely according to the recommendation in the previous section (ideally outside the project folder) and note its path for the.env
file. Vonage does not store this private key..env
file asVONAGE_APPLICATION_ID
.ngrok
in the next step. Leave them blank for now, but keep this page open or be ready to edit the application later.Expose Local Server with
ngrok
:ngrok
to forward traffic to the port your Fastify app will run on (defined asPORT
in.env
, default3000
).ngrok
will display output including aForwarding
URL usinghttps
. Copy thehttps
URL (e.g.,https://random-subdomain.ngrok-free.app
). This is your public URL for local testing.Configure Webhook URLs in Vonage Application:
ngrok
https
URL into the Status URL field and append/webhooks/status
. Example:https://random-subdomain.ngrok-free.app/webhooks/status
/webhooks/inbound
(for receiving messages, not covered in detail here). Example:https://random-subdomain.ngrok-free.app/webhooks/inbound
Link Your Vonage Number:
VONAGE_NUMBER
in your.env
).Your Vonage account and application are now configured to send SMS status updates to your
ngrok
URL, which forwards them to your local machine.3. Implementing the Fastify Webhook Handler
Now, let's write the Fastify code to receive and process these status updates.
Edit your
index.js
file with the following code:Code Explanation:
dotenv
,fastify
,@fastify/formbody
,@vonage/server-sdk
).logger: true
).VONAGE_APPLICATION_ID
) and Private Key path (VONAGE_PRIVATE_KEY_PATH
) from.env
. This authentication method is standard for the Messages API./webhooks/status
):POST
handler matching the URL configured in the Vonage Application.request.body
) for debugging. Fastify automatically parsesJSON
payloads.@fastify/formbody
is registered to handle form-encoded data if needed, although status webhooks useJSON
.message_uuid
,status
)..number
access forto
andfrom
, as the format can vary slightly.TODO
placeholder where you would add your application-specific logic (database updates, etc.).200 OK
response back to Vonage. This is critical to prevent Vonage from retrying the webhook delivery./send-test-sms
):GET
endpoint for convenience. Accessing this URL triggers the sending of an SMS message using the credentials from.env
.vonage.messages.send()
specifyingchannel: 'sms'
,message_type: 'text'
, and the requiredto
,from
, andtext
.message_uuid
returned by Vonage upon successful submission.async
function. Usesfastify.listen
withhost: '0.0.0.0'
to make the server accessible externally (necessary forngrok
and deployments).start
function to launch the application.4. Verification and Testing
Let's run the application and test the workflow.
Ensure
ngrok
is Running: Verify that yourngrok http 3000
process is still active in its terminal window and that thehttps
Forwarding URL matches the one configured in your Vonage Application's Status URL.Start the Fastify Server: In your primary terminal window (in the
fastify-vonage-status
directory), run:You should see log output indicating the server is listening on port
3000
.Send a Test SMS: Open your web browser or use a tool like
curl
to access the test endpoint:message_uuid
.YOUR_PHONE_NUMBER
.Observe the Status Webhook:
node index.js
). You should see new log entries starting withStatus Webhook Received. Payload:
.status
field (e.g.,submitted
,delivered
,accepted
). The final status is usuallydelivered
.message_uuid
in the webhook payload matches the one logged when you sent the SMS.Example Vonage Status Payload (logged by
fastify.log.info(request.body)
):(Note: You will also see surrounding log lines from Fastify/Pino showing log level, time, etc., but the above JSON is the core
request.body
content)Check
ngrok
Interface (Optional): Openhttp://localhost:4040
(or the address shown in thengrok
terminal) in your browser. This web interface shows requests forwarded byngrok
. You can inspect the exactPOST
request sent by Vonage to/webhooks/status
and the200 OK
response sent by your Fastify app.If you see the status webhook logs in your Fastify terminal, congratulations! You have successfully implemented SMS delivery status handling.
5. Error Handling and Logging
logger: true
). For production, you might configure log levels (level: 'info'
) and potentially transport logs to a dedicated logging service./send-test-sms
route includes atry...catch
block to handle errors during the sending process (e.g., invalid credentials, network issues).message_uuid
,status
). Robust error handling would involve more thorough validation (e.g., using JSON Schema validation with Fastify) depending on how critical the data is.2xx
response (like our200 OK
). Ensure your handler always returns200 OK
quickly, even if processing fails internally (log the error and return 200). Handle the processing failure asynchronously if needed.6. Troubleshooting and Caveats
ngrok
is running and thehttps
URL is correct in the Vonage Application Status URL setting.3000
).ngrok
is forwarding to.SMS API
setting results in a different webhook format and configuration method (via the main Settings page, not the Application).VONAGE_APPLICATION_ID
andVONAGE_PRIVATE_KEY_PATH
in your.env
are correct and the private key file exists at that path and is readable by the application.application/json
. Fastify handles this automatically. If you suspect issues, logrequest.headers['content-type']
.submitted
oraccepted
.fastify-rate-limit
to prevent abuse.7. Security Considerations
/webhooks/status/a7f3b9z2k1x0
). While not true security (security through obscurity), it makes accidental discovery or simple scans less likely. Update this path in both your Fastify route and the Vonage Application settings.VONAGE_API_KEY
,VONAGE_API_SECRET
,VONAGE_APPLICATION_ID
,VONAGE_PRIVATE_KEY_PATH
) are kept highly secure..env
for local development only. In production, use secure secret management solutions provided by your hosting platform (e.g., AWS Secrets Manager, Google Secret Manager, Heroku Config Vars, Docker secrets).8. Deployment
ngrok
with a permanent public URL for your deployed application (e.g., from Heroku, Render, AWS EC2 with a domain, etc.).https://your-app-domain.com/webhooks/status
). Remember to use your secure, hard-to-guess path if implemented.VONAGE_API_KEY
,VONAGE_API_SECRET
,VONAGE_APPLICATION_ID
,VONAGE_PRIVATE_KEY_PATH
, etc.) securely using your deployment platform's tools. Do not commit your.env
file orprivate.key
directly into your repository if it's public. Consider storing the private key content securely as an environment variable itself, or using a secure file storage mechanism accessible to your production environment.pm2
in production to handle Node.js application lifecycle (restarts, clustering).Conclusion
You have now successfully built a Node.js application using Fastify to receive and log SMS delivery status updates from the Vonage Messages API. This provides crucial visibility into message deliverability, enabling you to build more robust and reliable communication features.
From here, you can extend the application by:
/webhooks/inbound
endpoint to receive SMS replies.Remember to consult the official Vonage Messages API documentation for detailed information on status codes and payload formats.