Frequently Asked Questions
Integrate WhatsApp by using Vonage's Messages API and Node.js SDK within a Next.js application. Set up API routes in your Next.js app to handle incoming messages and send replies via webhooks, enabling two-way communication with users on WhatsApp.
The Vonage Messages API allows you to send and receive messages across various channels, including WhatsApp. It's the core service for integrating WhatsApp messaging into your application, enabling communication between your app and WhatsApp users.
ngrok creates a public tunnel to your local development server, essential for Vonage's webhooks to reach your Next.js app during development. This lets you test your WhatsApp integration locally before deploying it live.
Configure production webhooks after deploying your Next.js application. Replace the ngrok URL with your production URL (e.g. Vercel URL) in your Vonage application settings. This directs Vonage's messages to your live application.
Yes, Vonage provides a WhatsApp Sandbox for testing. This allows you to test your integration with allowlisted numbers and familiarize yourself with the API without incurring costs or using a live WhatsApp Business Account.
Create a new Next.js project, install necessary dependencies like '@vonage/server-sdk', '@vonage/messages', '@vonage/jwt', and 'dotenv'. Then, create API routes to manage WhatsApp interactions and configure environment variables with your Vonage credentials.
The Vonage Node SDK simplifies interaction with the Vonage APIs within your Next.js application. It handles authentication, message sending, and receiving status updates, making integration smoother than working with the API directly.
Secure your Vonage webhooks, particularly the status updates, by verifying JWT signatures using your `VONAGE_API_SIGNATURE_SECRET`. This ensures requests originate from Vonage, protecting against unauthorized access.
Use the `sendWhatsAppReply` function within your inbound message handler. This function leverages the Vonage Node SDK to send text messages to users on WhatsApp. Be sure to use the WhatsApp number linked to the Sandbox during testing and your WABA in production.
Store your Vonage API credentials (API key, secret, application ID, private key path, signature secret) in a `.env.local` file for local development, which is automatically excluded from version control. For production deployments, utilize platform-specific environment variables, keeping sensitive data safe.
You need Node.js 20+, npm or yarn, a Vonage API account with associated API keys and secrets, a Vonage application with a linked WhatsApp Sandbox number, ngrok for local testing, and a personal WhatsApp account for sandbox interaction.
During the sandbox testing phase, you must allowlist your personal WhatsApp number to send and receive messages with the Vonage Sandbox number. This restriction is in place for testing and security purposes.
A database is recommended for production Vonage WhatsApp integrations to store message logs, manage conversation state (especially for bots), maintain user data linked to WhatsApp numbers, and ensure reliable message tracking and status updates.
Common issues include webhooks not reaching your server, 401 errors due to incorrect signature secrets, and message sending failures due to credential issues or un-allowlisted numbers. Check logs, verify credentials, and ensure correct webhook URLs to diagnose and fix problems.
This guide provides a step-by-step walkthrough for integrating Vonage's Messages API to send and receive WhatsApp messages within a Next.js application. We'll build a simple Next.js app with API routes that handle incoming WhatsApp messages via Vonage webhooks and send replies back using the Vonage Node SDK.
This setup enables you to build applications that interact directly with users on WhatsApp, opening possibilities for customer support bots, notification systems, interactive services, and more, leveraging the familiar Next.js development environment.
Project Goals:
Technology Stack:
System Architecture:
Prerequisites:
1. Setting Up the Next.js Project
Let's start by creating a new Next.js application and installing the necessary dependencies.
Create a Next.js App: Open your terminal and run:
Follow the prompts. This guide uses the
pages/api
directory structure for API routes.Install Dependencies: Install the Vonage SDKs and
dotenv
for managing environment variables locally.@vonage/server-sdk
: Core SDK for authentication and client initialization.@vonage/messages
: Specifically for using the Messages API.@vonage/jwt
: For verifying webhook signatures (JWTs).dotenv
: To load environment variables from a.env.local
file during local development (Next.js has built-in support, but this ensures consistency).Configure Environment Variables: Create a file named
.env.local
in the root of your project. This file is gitignored by default in Next.js projects, keeping your secrets safe. Add the following variables:How to Obtain Each Value:
VONAGE_API_KEY
&VONAGE_API_SECRET
: Go to your Vonage API Dashboard. They are displayed prominently at the top.VONAGE_APPLICATION_ID
&VONAGE_PRIVATE_KEY
:http://localhost/inbound
for Inbound andhttp://localhost/status
for Status for now.private.key
file and save it in the root of your Next.js project. The public key is managed by Vonage.VONAGE_APPLICATION_ID
will be displayed on the application's page. Copy it.VONAGE_PRIVATE_KEY
in.env.local
, use the relative path from your project root to the downloaded key, e.g.,./private.key
.VONAGE_WHATSAPP_NUMBER
:14157386102
). Use this number.VONAGE_API_SIGNATURE_SECRET
:BASE_URL
: Set this to your local development URL (http://localhost:3000
) initially. We'll use ngrok to expose this publicly later. For deployment, this will be your production URL. This variable isn't used directly by the code but helps conceptualize the webhook URLs.Project Structure: We will place our API logic within the
pages/api/
directory. Let's create a subdirectory for Vonage webhooks:We'll also create a utility file for the Vonage client:
2. Implementing Core Functionality (API Routes)
Now, let's create the API routes to handle incoming messages and status updates from Vonage.
Initialize Vonage Client: Create a reusable Vonage client instance.
path.resolve
to ensure the path to the private key is correct, regardless of where the script is run from.apiHost
to the sandbox URL. Remember to remove this or change it for production.Create Inbound Message Handler: This API route will receive messages sent by users to your Vonage WhatsApp number.
vonage
client.POST
requests.from.number
) and the message content (message.content.text
).200 OK
is returned for ignored messages.sendWhatsAppReply
to send a ""Message received."" response.processedMessages
Set) with comments on its limitations and clearing mechanism (server restart).200 OK
to Vonage to acknowledge receipt. Errors return500
.Create Status Handler: This route receives status updates about messages you've sent (e.g., delivered, read, failed).
verifyVonageSignature
helper using@vonage/jwt
and yourVONAGE_API_SIGNATURE_SECRET
. This step is vital for security.200 OK
.3. Configuring Webhooks with ngrok
To test the integration locally, Vonage needs to be able to reach your development server. We'll use ngrok for this.
Start Your Next.js App:
Your app should be running, typically on
http://localhost:3000
.Start ngrok: Open a new terminal window and run ngrok, pointing it to your Next.js port (usually 3000):
Get Your Public URL: ngrok will display output similar to this:
Copy the
https://...
URL. This is your temporary public URL.Update Webhook URLs in Vonage:
<your-ngrok-url>/api/vonage/inbound
<your-ngrok-url>/api/vonage/status
<your-ngrok-url>/api/vonage/inbound
<your-ngrok-url>/api/vonage/status
Important: Ensure the paths
/api/vonage/inbound
and/api/vonage/status
match the location of your API route files within your Next.js project'spages/api/
directory.4. Testing the Integration
Send a WhatsApp Message: Using the personal WhatsApp account you allowlisted earlier, send any message (e.g., ""Hello"") to the Vonage WhatsApp Sandbox number.
Check Your Logs:
/api/vonage/inbound
route, indicating the message was received and a reply was attempted (e.g., ""Received text message..."", ""Attempting to send reply..."", ""Message sent successfully..."").POST
requests hitting your ngrok URL for/api/vonage/inbound
and likely/api/vonage/status
shortly after./api/vonage/status
showing the delivery status updates (e.g., ""Received status webhook..."", ""Status Update: UUID=..., Status=submitted..."", ""Status Update: UUID=..., Status=delivered..."").Check WhatsApp: You should receive the ""Message received."" reply on your personal WhatsApp account from the Sandbox number.
5. Error Handling and Logging Considerations
The provided code includes basic
try...catch
blocks andconsole.log
/console.error
. For production:Pino
orWinston
to output logs in JSON format. This makes them easier to parse and analyze in log management systems (e.g., Datadog, Logtail, AWS CloudWatch).error
object in status updates).Set
is only suitable for demos. Use a persistent store (like Redis or a database) checkingmessage_uuid
to reliably handle duplicate webhook deliveries in production.6. Database Integration (Conceptual)
While this basic example doesn't use a database, a real-world application likely would:
message_uuid
, sender/recipient, content, timestamp, and status.Example using Prisma (Conceptual):
Setup Prisma:
npm install prisma --save-dev
,npx prisma init
, configure your database URL in.env
.Define Schema:
Apply Schema:
npx prisma migrate dev
(ornpx prisma db push
for prototyping)Use in API Routes:
message_uuid
returned by Vonage when sending the outbound message.prisma.messageLog.update
(notupdateMany
) withwhere: { messageUuid: message_uuid }
to update the status of that specific outbound message log entry.7. Security Best Practices
/status
webhook usingverifySignature
and yourVONAGE_API_SIGNATURE_SECRET
. This prevents attackers from spoofing status updates./inbound
webhook doesn't use Vonage JWTs by default, consider adding your own security layer if the handled data is sensitive. Options include:.env.local
or yourprivate.key
file to source control. Use environment variables in your deployment environment (see Section 9).req.body
). Check expected data types, lengths, and formats. Libraries likezod
can help define schemas for robust validation.nextjs-rate-limiter
or platform features like Vercel's) to prevent abuse or accidental loops.8. Troubleshooting and Caveats
/api/vonage/...
) is configured correctly in both the Vonage Application and Sandbox settings. A typo is common.http://127.0.0.1:4040
) for request/response details and errors./status
: IncorrectVONAGE_API_SIGNATURE_SECRET
or issue with JWT verification logic. Double-check the secret in Vonage Settings -> API settings and your.env.local
/ deployment environment variables. Ensure the header format is correct (Bearer <token>
).VONAGE_API_KEY
,VONAGE_API_SECRET
,VONAGE_APPLICATION_ID
, andVONAGE_PRIVATE_KEY
path/content in.env.local
/ environment variables. Ensure the recipient number is correctly formatted (E.164
) and allowlisted in the Sandbox. Check Vonage Dashboard logs (Logs -> Messages API) for specific API errors. Ensure thevonageClient
initialized correctly (check startup logs).message_uuid
and a persistent store for production. The demoSet
is insufficient for reliable duplicate prevention.apiHost
sandbox override inlib/vonageClient.js
.9. Deployment (Example: Vercel)
.env.local
andprivate.key
are in.gitignore
) and push it to a Git provider (GitHub, GitLab, Bitbucket)..env.local
file (VONAGE_API_KEY
,VONAGE_API_SECRET
,VONAGE_APPLICATION_ID
,VONAGE_API_SIGNATURE_SECRET
,VONAGE_WHATSAPP_NUMBER
). Do not addVONAGE_PRIVATE_KEY
as a file path. Instead:private.key
file.VONAGE_PRIVATE_KEY_CONTENT
(or similar) and paste the multi-line key content exactly as its value.lib/vonageClient.js
to read the key content directly from this environment variable when deployed:https://your-app-name.vercel.app
). Update the Vonage Application and production Messages API webhooks (not the Sandbox ones, unless you intend to keep using it) to use this URL:https://your-app-name.vercel.app/api/vonage/inbound
https://your-app-name.vercel.app/api/vonage/status