Frequently Asked Questions
Use the Vonage Messages API and a Next.js API route as a webhook endpoint. Set up your Vonage account, create a Next.js project, and implement the webhook handler to receive incoming SMS messages sent to your Vonage virtual number. The API route should parse the incoming JSON payload and log the message details for debugging and processing.
The Vonage Messages API allows you to send and receive messages across various channels, including SMS. This is useful for applications needing to interact with users via SMS for notifications, alerts, customer support, or two-factor authentication.
A 200 OK response is essential to acknowledge successful receipt of the SMS message by your webhook. Without it, Vonage will retry sending the webhook, potentially leading to duplicate processing. This acknowledgement ensures reliable message delivery and prevents unnecessary retries.
ngrok is crucial during local development to expose your Next.js development server to the internet, allowing Vonage to send webhooks to your local machine. It creates a public URL that tunnels requests to your local server, which is essential for testing your integration.
Yes, you can store received SMS messages and related data in a database. The article recommends Prisma as a suitable option with Next.js, guiding you through defining a schema, running migrations, and using Prisma Client to store message details like sender, recipient, and text content.
Integrate Vonage by obtaining API credentials from your Vonage dashboard, updating your .env.local file, and creating a Vonage Application. Link your virtual number to this application and configure its Inbound/Status URLs to point to your Next.js webhook endpoint, exposed via ngrok during development.
The private.key file is crucial for authenticating your Vonage application. It's generated when you create a new Vonage Application and must be securely stored and referenced in your .env.local file using the VONAGE_PRIVATE_KEY_PATH variable. Never commit this file to your code repository.
Implement a try...catch block in your API route handler to catch errors during webhook processing. Log errors thoroughly and return a 500 status code if processing fails. For production, structured logging and error tracking services are recommended.
Secure your webhook by validating inputs, verifying Vonage signatures using JWT, implementing rate limiting, and protecting environment variables. These measures prevent malicious attacks, abuse, and ensure only genuine Vonage requests are processed.
If your webhook isn't triggering, check if ngrok is running and the URLs in your Vonage application settings match. Ensure your Vonage number is linked, Messages API is the default setting, and no firewalls are blocking requests.
Next.js API routes act as webhook endpoints to receive incoming SMS messages from Vonage. These serverless functions handle the incoming requests, process the message data, and send the required 200 OK response to Vonage, acknowledging receipt.
While the article focuses on receiving messages, sending replies involves using the @vonage/server-sdk within your API route after receiving and processing an inbound message. Further guidance on sending messages can be found in the Vonage documentation and SDK examples.
Receive and respond to SMS messages seamlessly within your Next.js application using the Vonage Messages API. This comprehensive tutorial provides a complete walkthrough, from setting up your Vonage account and Next.js project to implementing webhook handlers, sending replies, and deploying a production-ready solution for inbound SMS messaging.
You'll build a Next.js application capable of receiving incoming SMS messages sent to a Vonage virtual number via webhooks. The application will log these messages, store them in a database, and demonstrate how to send replies for two-way SMS communication. This solves the common need for applications to interact with users via SMS for notifications, alerts, customer support, or two-factor authentication follow-ups.
Project Overview and Goals
What You'll Build:
@vonage/server-sdk.Technologies Used:
@vonage/server-sdk: The official Node.js library for interacting with Vonage APIs.ngrok: A tool to expose local development servers to the internet, essential for testing webhooks.System Architecture:
Prerequisites:
ngrok: Install it globally or usenpx. A free account is sufficient but has limitations: 2-hour session timeouts (requiring URL regeneration), 1GB bandwidth, and a browser warning page for HTML traffic. For production testing, consider paid plans or alternatives. ngrok Setup.Final Outcome:
By the end of this guide, you will have a functional Next.js application that reliably receives incoming SMS messages via Vonage webhooks and can be extended to send replies or perform other actions based on the message content.
How to Set Up a Next.js Project for Receiving SMS Webhooks
Initialize a new Next.js project and install the necessary dependencies to handle inbound SMS messages.
Create a Next.js App: Open your terminal and run the following command, replacing
vonage-nextjs-smswith your desired project name. Choose your preferred settings when prompted (TypeScript recommended, App Router used here but adaptable for Pages Router).Navigate to Project Directory:
Install Vonage SDK: We need the Vonage server SDK to interact with the Messages API. As of October 2025, @vonage/server-sdk v3.24.1 is the latest version, offering full promise-based APIs with TypeScript support for improved type safety and IDE integration.
or using yarn:
Note: The @vonage/server-sdk provides official support for Vonage APIs including SMS, Voice, Text-to-Speech, Numbers, Verify (2FA), and Messages API. The SDK handles authentication, request formatting, and error handling for all Vonage API interactions.
Set up Environment Variables: Sensitive credentials like API keys should never be hardcoded. Use environment variables instead. Create a file named
.env.localin the root of your project.Terminal:
Add the following variables to
.env.local. You'll populate these values in the "Integrating with Vonage" section..env.local:
Note on
VONAGE_PRIVATE_KEY_PATH: Using a file path is convenient for local development. However, for deployment (covered in Section 11), embedding the private key content directly into an environment variable (e.g.,VONAGE_PRIVATE_KEY_CONTENT) is often a more robust approach, especially in serverless environments.Important: Add
.env.localand your private key file (e.g.,private.key) to your.gitignorefile to prevent committing sensitive information..gitignore (ensure these lines exist):
Why
.env.local? Next.js automatically loads variables from this file intoprocess.envfor server-side code (like API routes), keeping your secrets secure and separate from your codebase.How to Create an Inbound SMS Webhook Handler in Next.js
Create a Next.js API route to act as the webhook endpoint Vonage will call when an SMS is received. This webhook handler will process incoming messages and return the required response.
Create the API Route File: Create the necessary directories and the API route file.
Using App Router (default for
create-next-app):Using Pages Router (if selected during setup):
Implement the Webhook Handler: Paste the following code into the
route.js(App Router) orinbound.js(Pages Router) file you created.app/api/webhooks/inbound/route.js (App Router):
pages/api/webhooks/inbound.js (Pages Router):
Why this code?
/api/webhooks/inbound.POSTrequests, which is how Vonage sends webhook data.request.json()for App Router,req.bodyfor Pages Router).200 OKresponse. This is vital to tell Vonage the message was received successfully and prevent retries.500status code.Note on Code Examples: For brevity, subsequent code modifications in this guide (e.g., adding logging, database integration) will primarily show the App Router version (
route.js). The core logic can be adapted to the Pages Router structure (inbound.js) usingreqandresobjects.How to Configure Vonage to Send Inbound SMS to Your Webhook
Configure Vonage to work with your Next.js application and route incoming SMS messages to your webhook endpoint.
Log in to Vonage: Access your Vonage API Dashboard.
Get API Credentials: On the main dashboard page, find your API key and API secret. Copy these values.
Update
.env.local: Paste your API key and secret into theVONAGE_API_KEYandVONAGE_API_SECRETvariables in your.env.localfile.Ensure Messages API is Default:
Create a Vonage Application:
private.keyfile. Save this file securely.private.keyfile into the root directory of your Next.js project. The path./private.keyin.env.localassumes it's in the root.ngrok. Leave them blank for now or use a placeholder likehttp://localhost.Update
.env.local: Paste the Application ID intoVONAGE_APPLICATION_IDin your.env.localfile.Link Your Vonage Number:
12015550123) into theVONAGE_NUMBERvariable in.env.local.TO_NUMBERif you plan to test sending messages.Expose Local Server with
ngrok:Start your Next.js development server (if not already running):
Open a new terminal window/tab in the same project directory.
Run
ngrokto expose your local port 3000 (default for Next.js dev):ngrokwill display output similar to this:Copy the HTTPS Forwarding URL (e.g.,
https://<random-string>.ngrok-free.app). Do not close this ngrok terminal.Update Vonage Application URLs:
ngrokHTTPS URL and append/api/webhooks/inbound. Example:https://<random-string>.ngrok-free.app/api/webhooks/inboundhttps://<random-string>.ngrok-free.app/api/webhooks/inbound(You can create a/api/webhooks/statusroute later if needed).Your Vonage application is now configured to send incoming SMS messages for your linked number to your local Next.js application via
ngrok.What Error Handling and Logging Should You Implement for SMS Webhooks?
Our basic webhook handler includes initial logging and error handling, but let's refine it for production use.
try...catchblock in the API route is the foundation. Ensure any errors encountered during your custom logic (database writes, external API calls) are caught and logged. Always aim to return a500status if processing fails internally, but only after logging the error details.console.logis suitable for development. For production, consider structured logging libraries likepinoorwinston. These enable:debug,info,warn,error.2xxresponse (ideally200 OK) within a certain timeout (usually a few seconds). Your webhook logic should be idempotent if possible – meaning receiving the same message multiple times doesn't cause duplicate actions or errors. Logging themessage_uuidhelps identify duplicate deliveries. If your processing takes time, consider immediately returning200 OKand then processing the message asynchronously (e.g., using a background job queue like BullMQ or Kue).Example using Pino (Basic Setup):
Install Pino:
npm install pinoUpdate API route (showing App Router example):
app/api/webhooks/inbound/route.js (App Router - Example):
How to Store Inbound SMS Messages in a Database with Prisma
If you need to store incoming messages or related data, you'll need a database. Prisma is a popular choice with Next.js, offering excellent TypeScript support and type-safe database queries. Prisma officially supports Next.js 15 and recommends version @prisma/client@5.12.0 or above for middleware and edge runtime compatibility.
Install Prisma:
Initialize Prisma:
This creates a
prismadirectory with aschema.prismafile and updates.env(or.env.local) withDATABASE_URL.Define Schema: Edit
prisma/schema.prismato define a model for SMS messages.prisma/schema.prisma:
Run Migrations: Set up your database connection string in
.env.local(DATABASE_URL). Then create and apply the migration.Use Prisma Client in API Route:
lib/prisma.js (Example Singleton):
app/api/webhooks/inbound/route.js (Update - App Router):
What Security Features Should You Add to SMS Webhook Endpoints?
Securing your webhook endpoint is critical for production deployments.
zodorjoican validate the incomingreq.bodystructure against a predefined schema.Vonage can sign webhook requests using JWT (JSON Web Tokens) with your Signature secret (found in API Settings). This verifies the request genuinely originated from Vonage.
The
@vonage/server-sdkincludes helpers for this. Implementing this adds a robust layer of security.Refer to the official Vonage documentation for Secure Webhooks and SDK examples for detailed implementation guidance specific to your framework setup.
Conceptual Example Snippet:
Note: Implementing signature verification requires careful handling of the raw request body and headers. Consult the
@vonage/server-sdkdocumentation or Vonage developer resources for the precise method. You'll need your Signature Secret from the Vonage Dashboard API Settings.rate-limiter-flexibleorupstash/ratelimitto implement custom limits..env.localor yourprivate.keyto Git.ngrokprovides this for free; production deployments on platforms like Vercel are HTTPS by default).How to Handle Special SMS Cases and Edge Scenarios
sms: { num_messages: '...' }), but typically you receive the full text in thetextfield.channelfield.timestamp) are typically in UTC (ISO 8601 format). Store dates in UTC in your database and convert to the user's local time zone only when displaying.What Performance Optimizations Should You Apply to SMS Webhooks?
For a simple webhook receiver, major optimizations are often unnecessary, but consider:
200 OKas quickly as possible. Offload time-consuming tasks (database writes, external API calls, complex logic) to background jobs/queues if they risk timing out the webhook request.messageUuid,fromNumber,receivedAt) if you store messages.fromNumber), cache this data (e.g., using Redis or an in-memory cache) to avoid repeated database hits.How to Monitor and Track SMS Webhook Performance
In production, visibility is key.
GEThandler in our API route provides a basic health check. Monitoring services can ping this endpoint to ensure the webhook is live.How to Troubleshoot Common Vonage SMS Webhook Issues
ngrokstill running? Has the URL expired (free tier URLs are temporary)?ngrokHTTPS URL +/api/webhooks/inbound?ngrokor Vonage?npm run devis running, or your production logging service) for detailed error messages immediately preceding the 5xx response.200 OKstatus code quickly enough or at all. Check logs for errors or timeouts. Ensureres.status(200).end()(Pages) orreturn new NextResponse(null, { status: 200 });(App) is reached successfully..env.local.npm run dev) after modifying.env.local..env.local.Frequently Asked Questions About Vonage SMS Webhooks with Next.js
How do you receive SMS messages in Next.js using Vonage?
To receive SMS messages in Next.js with Vonage, create a Next.js API route (e.g.,
/api/webhooks/inbound) that handles POST requests. Configure this endpoint URL in your Vonage Application settings as the Inbound URL. When someone sends an SMS to your Vonage number, Vonage sends a POST request to your webhook with the message data. Your API route must return a200 OKresponse to acknowledge receipt.What Node.js and Next.js versions are required for Vonage SMS webhooks?
You need Node.js 20.x or later. As of January 2025, Node.js 22 LTS (codenamed 'Jod', released October 29, 2024) is the current LTS version with support until April 2027. Node.js 18.x reaches end-of-life on April 30, 2025. This guide uses Next.js 15.x (latest: 15.2 as of February 2025) with App Router support, which is recommended for new projects and uses React Server Components.
What is the latest version of @vonage/server-sdk for receiving SMS?
As of October 2025, @vonage/server-sdk v3.24.1 is the latest version. It offers full promise-based APIs with TypeScript support for improved type safety and IDE integration. The SDK provides official support for Vonage APIs including SMS, Voice, Text-to-Speech, Numbers, Verify (2FA), and Messages API, handling authentication, request formatting, and error handling for all Vonage API interactions.
How do you secure Vonage SMS webhook endpoints in production?
Implement multiple security layers: verify Vonage JWT signatures using your Signature secret (found in API Settings), validate incoming payload structure with libraries like
zodorjoi, implement rate limiting using Next.js middleware or Vercel edge features, always use HTTPS for webhook URLs, store credentials in secure environment variables (never commit.env.localorprivate.keyto Git), and use secrets management solutions like Vercel Environment Variables or AWS Secrets Manager for production deployments.Can you use Prisma with Next.js 15 for storing inbound SMS messages?
Yes, Prisma officially supports Next.js 15 and recommends version @prisma/client@5.12.0 or above for middleware and edge runtime compatibility. Prisma offers excellent TypeScript support and type-safe database queries, making it ideal for storing incoming SMS messages, tracking delivery status, and managing conversation history. The integration handles database connection pooling and provides automatic query optimization.
What are the limitations of ngrok's free tier for webhook testing?
ngrok's free tier has several limitations: 2-hour session timeouts (requiring URL regeneration and Vonage configuration updates), 1GB bandwidth cap, browser warning pages for HTML traffic, and random, ephemeral URLs that change each session. For production testing or stable development URLs, consider paid ngrok plans or alternatives like Cloudflare Tunnel or Pinggy.
How does Vonage handle webhook retry logic for inbound SMS?
Vonage automatically retries sending webhooks if it doesn't receive a
2xxresponse (ideally200 OK) within a timeout period. Make your webhook logic idempotent – receiving the same message multiple times shouldn't cause duplicate actions or errors. Log themessage_uuidto identify duplicate deliveries. For time-consuming processing, immediately return200 OKand process messages asynchronously using background job queues like BullMQ or Redis Queue.What error handling should you implement for inbound SMS webhooks?
Implement comprehensive error handling: use
try...catchblocks to catch all errors, log errors with structured logging (Pino or Winston) includingmessage_uuidfor tracking, return500status codes only after logging errors, handle Prisma unique constraint violations (P2002) for duplicate messages, validate required fields exist before processing, and integrate error tracking services like Sentry or Bugsnag to capture and alert on production errors.How do you test Vonage SMS webhooks locally during development?
Use ngrok to expose your local Next.js development server (port 3000) to the internet. Run
ngrok http 3000to get an HTTPS URL, then configure this URL +/api/webhooks/inboundin your Vonage Application settings as the Inbound URL. Send a test SMS to your Vonage number and monitor your terminal logs. Remember to update the Vonage URLs each time you restart ngrok (free tier) or use a static domain (paid plan).What database schema should you use for storing Vonage inbound SMS messages?
Create a schema with essential fields:
id(primary key),messageUuid(unique, maps to Vonage'smessage_uuid),fromNumber,toNumber,text,channel(defaults to "sms"),receivedAt(timestamp),processedAt(nullable timestamp), and optionallyerrorMessageandretryCountfor error tracking. Index frequently queried columns likemessageUuid,fromNumber, andreceivedAtfor query performance. Store timestamps in UTC and convert to local timezone only for display.How do you implement two-way SMS messaging with Vonage and Next.js?
To implement two-way SMS messaging, first set up an inbound webhook to receive SMS messages as described in this guide. Then, use the Vonage Messages API SDK to send reply messages from your webhook handler. Extract the sender's number from
inboundSms.from, craft your reply message, and callvonage.messages.send()with the appropriate parameters. Store conversation history in a database to maintain context across multiple messages.What's the difference between Vonage SMS API and Messages API for webhooks?
The Messages API is the newer, unified API that supports multiple channels (SMS, WhatsApp, MMS, Viber, etc.) and provides a consistent webhook payload format across channels. The SMS API is the legacy API focused only on SMS. For new projects, Vonage recommends using the Messages API. Ensure "Messages API" is set as the default in your Vonage Dashboard API Settings to receive the correct webhook payload format.
How do you handle concurrent inbound SMS messages in Next.js?
Next.js API routes in serverless environments (like Vercel) automatically handle concurrent requests by spawning separate function instances. Each incoming webhook is processed independently. Ensure your database operations are atomic and use unique constraints on
message_uuidto prevent duplicate storage. For high-volume applications, consider implementing a message queue (Redis Queue, BullMQ) to manage processing order and prevent overwhelming downstream services.