Frequently Asked Questions
Receive SMS messages by configuring a Vonage virtual number to send webhooks to your RedwoodJS application. Set up a webhook endpoint in your RedwoodJS app using a serverless function and expose it to the internet using a tool like ngrok during development. This endpoint will receive inbound message data from Vonage whenever an SMS is sent to your virtual number. Make sure to verify Vonage's webhook signatures for security and store the message data using Prisma.
The Vonage Messages API provides a unified way to send and receive messages across various channels, including SMS, MMS, WhatsApp, and Facebook Messenger. It simplifies the process of integrating messaging into your application by handling the complexities of different platforms.
Vonage uses webhook signatures to ensure the authenticity and integrity of incoming webhook requests. This cryptographic signature, generated using a shared secret, allows your application to verify that the request originated from Vonage and hasn't been tampered with, enhancing security.
Use ngrok during local development to create a secure tunnel that exposes your locally running RedwoodJS server to the public internet. This allows Vonage to deliver webhooks to your application for testing even though it's not yet deployed to a production environment.
Yes, you can send and receive WhatsApp messages using RedwoodJS with the Vonage Messages API. After setting up your Vonage account and linking a WhatsApp-enabled number, you can use the Vonage Node.js Server SDK within your RedwoodJS services to send and receive messages via the API's unified endpoint.
Set up Vonage webhooks by creating a serverless function in your RedwoodJS application. This function will act as the webhook endpoint, receiving inbound and status update messages. Configure your Vonage application's inbound and status URLs to point to this function's publicly accessible URL, usually via ngrok during development.
Prisma serves as the Object-Relational Mapper (ORM) in your RedwoodJS application, facilitating interactions with your database. When integrated with Vonage, Prisma allows you to efficiently store details about incoming and outgoing messages, including sender, recipient, content, timestamps, and message status.
Validate Vonage webhook signatures by using the @vonage/server-sdk's Signature class and your Vonage webhook secret. Compare the signature in the 'X-Vonage-Signature' header with the one generated using your secret and the raw request body. This step is crucial for ensuring the request genuinely comes from Vonage.
Vonage sends status updates for each message, indicating delivery success, failure, or other events. Your RedwoodJS application should handle these status updates by implementing a webhook endpoint that receives these updates and logs the status. You should save these status updates to your database using a dedicated service function.
Handle Vonage API errors within your RedwoodJS services, specifically when making calls to the Vonage API using the SDK. Implement robust error handling using try-catch blocks to catch potential errors during sending messages or other API interactions. Log the error details and implement appropriate retry mechanisms or user notifications.
The RedwoodJS service responsible for sending Vonage messages should be named 'messages' and be located at 'api/src/services/messages/messages.ts'. This service should contain a function that utilizes the Vonage Node.js Server SDK to interact with the Vonage Messages API, allowing your application to send outbound messages.
Store Vonage messages by creating a 'Message' model in your Prisma schema ('api/db/schema.prisma'). Define fields to capture essential message details like ID, direction, channel, sender, recipient, content, status, timestamps, and potential error codes. Use RedwoodJS services to interact with Prisma and perform create, read, update, and delete operations on message records.
Test Vonage webhooks locally by using ngrok to expose your RedwoodJS development server. Configure ngrok to forward requests to your webhook endpoint. Update your Vonage application settings to use the ngrok URL as your webhook URL. Send a test message to your Vonage number and observe logs in ngrok, your RedwoodJS console, and your database to verify functionality.
Using TypeScript in your RedwoodJS project when integrating Vonage enhances type safety and code maintainability. RedwoodJS supports TypeScript out-of-the-box, allowing you to define types for message data and API responses, which helps catch errors during development and improves overall code quality.
This guide provides a comprehensive walkthrough for building a RedwoodJS application capable of receiving inbound SMS or WhatsApp messages via the Vonage Messages API and enabling two-way conversations. We will cover everything from initial project setup and Vonage configuration to handling webhooks securely, storing messages, sending replies, and deploying the application.
By the end of this tutorial, you will have a functional RedwoodJS application that can:
Target Audience: Developers familiar with JavaScript and Node.js. Prior experience with RedwoodJS is helpful but not strictly required, as we cover setup from scratch. Familiarity with basic API concepts and webhooks is assumed.
Technologies Used:
ngrok
: A tool for exposing local development servers to the internet (used for testing webhooks locally, not part of the deployed application stack).System Architecture:
Prerequisites:
npm install -g redwoodjs-cli
. Note: While the RedwoodJS CLI is often installed globally using npm_ project-level commands and dependency management within a RedwoodJS project typically use Yarn_ following standard RedwoodJS conventions.ngrok
: Download and install from ngrok.com. Authenticate your client if you need longer sessions.1. Setting up the RedwoodJS project
First, create a new RedwoodJS application. We'll use TypeScript for enhanced type safety, which RedwoodJS supports out of the box.
Create the Redwood App: Open your terminal and run:
This command scaffolds a new RedwoodJS project in a directory named
vonage-redwood
with TypeScript enabled.Navigate into the Project:
Initialize Environment Variables: RedwoodJS uses a
.env
file for environment variables. Create one in the project root:We will populate this file later with necessary Vonage credentials. Redwood automatically loads variables from
.env
intoprocess.env
.Install Vonage SDK: We need the Vonage Node.js Server SDK to interact with the API and validate webhooks. Install it in the
api
workspace:@vonage/server-sdk
: The main SDK for API calls.@vonage/jwt
: Required for generating JWTs if you use features like Secure Inbound Media or JWT authentication for API calls (though basic key/secret auth is often sufficient for sending messages).Verify Setup: Start the development server to ensure the basic Redwood app is working:
You should see output indicating both the frontend (web) and backend (api) servers are running, typically on
http://localhost:8910
andhttp://localhost:8911
respectively. Stop the server for now (Ctrl+C
).2. Configuring Vonage
Before writing code to handle messages, we need to configure Vonage to send webhook events to our application.
Log in to Vonage Dashboard: Access your Vonage API Dashboard.
Retrieve API Credentials:
.env
file:YOUR_API_KEY
andYOUR_API_SECRET
with your actual credentials)Create a Vonage Application: Vonage Applications group settings like webhook URLs and capabilities.
ngrok
..env
file:YOUR_SIGNATURE_SECRET
with the generated secret).env
file:YOUR_APPLICATION_ID
with your actual Application ID)private.key
file and save it securely (e.g., in your project root, ensuring it's added to.gitignore
). Add its path to.env
:Link Your Vonage Number:
.env
:YOUR_VONAGE_NUMBER
with your linked number)Configure Webhooks (Requires
ngrok
): We'll configure the actual webhook URLs in the ""Local Development & Testing"" section once we have our Redwood function endpoint and anngrok
tunnel running.3. Creating the database schema
We need a way to store the messages received and sent. Let's define a Prisma model.
Define the
Message
Model: Openapi/db/schema.prisma
and add the following model:vonageMessageId
: Crucial for correlating messages and status updates.direction
: To distinguish between incoming and outgoing messages.errorCode
,errorReason
: To store failure details from status webhooks.Apply Migrations: Run the Prisma migrate command to create/update the database schema and generate the Prisma client.
Follow the prompts (e.g., provide a name for the migration like "add message model"). This will create/update the
Message
table in your development database (SQLite by default, unless configured otherwise).4. Implementing the RedwoodJS webhook handler
This is the core component that receives data from Vonage. We'll create a RedwoodJS Function, which is a serverless function deployed alongside your API.
Generate the Function: Use the Redwood CLI to generate a new function. We'll call it
vonageWebhook
.This creates
api/src/functions/vonageWebhook.ts
. The--no-graphql
flag indicates it's a standard HTTP endpoint, not part of the GraphQL API.Implement the Handler Logic: Open
api/src/functions/vonageWebhook.ts
and replace its contents with the following:Explanation:
VONAGE_WEBHOOK_SECRET
(Signature Secret from the Vonage Application settings) and the@vonage/server-sdk
'sSignature
class. Important: The signature check requires the raw, unparsed request body string and the request headers.message_uuid
,status
,message.content.type
). This might need refinement based on the specific Vonage channels and events you handle.createMessage
,updateMessageStatus
) and sending replies (sendVonageMessage
) to Redwood Services (created next). This keeps the function focused on handling the HTTP request/response lifecycle.try...catch
blocks log errors using Redwood's built-inlogger
. In production, you'd want more robust error tracking. Error details from status webhooks are now passed to the service.200 OK
response within a short timeout (typically a few seconds) to acknowledge receipt. Failure to respond quickly can lead to Vonage retrying the webhook and eventually disabling it. Any time-consuming processing should ideally happen after sending the response.sendVonageMessage
service function.5. Implementing RedwoodJS services
Services encapsulate business logic, including database interactions and calls to external APIs like Vonage.
Generate the Service:
This creates
api/src/services/messages/messages.ts
and related test/scenario files.Implement Service Logic: Open
api/src/services/messages/messages.ts
and add the necessary functions:Explanation:
.env
. This should only happen once. Error handling is included in case credentials are missing or invalid.createMessage
: A straightforward function usingdb.message.create
to save message data.updateMessageStatus
: Usesdb.message.update
to find a message by its uniquevonageMessageId
and update itsstatus
,errorCode
, anderrorReason
. It includes basic handling for cases where the message might not be found (e.g., if the status webhook arrives before the inbound message webhook is fully processed). EnsureserrorCode
is stored as a string.sendVonageMessage
:vonage.messages.send()
which is the unified endpoint for various channels.message_type: "text"
,to
,from
(your Vonage number),text
, andchannel
.messageUuid
.outbound
record in the database immediately with status 'submitted'. The actual delivery status will arrive later via the Status webhook.6. Local development & testing with
ngrok
To test the webhook locally, we need to expose our Redwood development server to the public internet using
ngrok
.Start Redwood Dev Server: Open a terminal in your project root and run:
Note the API server port (usually
8911
).Start
ngrok
: Open a second terminal and runngrok
, pointing it to your Redwood API server's port:ngrok
will display forwarding URLs (e.g.,https://<random-subdomain>.ngrok-free.app
). Copy thehttps
URL.ngrok
HTTPS URL plus the path to your function, which is/api/vonageWebhook
.Update Vonage Webhook URLs:
ngrok
HTTPS URL including the path into both the Inbound URL and Status URL fields. The final URL should look like:https://<random-subdomain>.ngrok-free.app/api/vonageWebhook
.Send a Test Message:
Verify:
ngrok
Console: Check thengrok
terminal window. You should see aPOST /api/vonageWebhook
request with a200 OK
response.yarn rw dev
. You should see logs from thevonageWebhook
function:createMessage
service.createMessage
for the outbound record.Message
table (e.g., usingyarn rw prisma studio
). You should see a new record for the inbound message (and potentially an outbound one if reply is enabled).Troubleshooting
ngrok
:ngrok
URL in Vonage (HTTPS, correct path/api/vonageWebhook
).ngrok
is still running. Freengrok
sessions time out.ngrok
.logger.debug
) and compare them carefully with what Vonage expects. EnsureVONAGE_WEBHOOK_SECRET
is correct. Sometimes proxies (includingngrok
under certain configurations) can subtly alter headers or body encoding.7. Security considerations
VONAGE_WEBHOOK_SECRET
as shown in the function handler. Never disable this check in production..env
file and ensure it's in your.gitignore
. Use your deployment platform's secret management for production.8. Error handling and logging
logger
(import { logger } from 'src/lib/logger'
). Log key events (webhook received, signature verified, message processed/sent) and any errors. Use appropriate log levels (info
,warn
,error
,debug
).sendVonageMessage
) and log relevant details (often found inerror.response.data
orerror.message
).createMessage
,updateMessageStatus
). Log details and decide how to respond (e.g., retry, notify admin, ignore if non-critical like a duplicate status update).errorCode
anderrorReason
. Implement logic to handle specific error codes from Vonage if needed (e.g., number blocked, invalid number).async-retry
. However, be cautious not to block the webhook response. If sending fails, log it and potentially queue it for later retry via a background job system (like RedwoodJS Background Jobs).9. Deployment
Deploying a RedwoodJS application is well-documented. Here are the key steps related to Vonage integration:
Choose a Platform: Select a deployment provider that supports Node.js applications (e.g., Vercel, Netlify, Render, Fly.io, AWS Lambda). RedwoodJS has deployment guides for popular platforms.
Configure Environment Variables: Set the following environment variables securely in your deployment platform's settings:
DATABASE_URL
(pointing to your production database)VONAGE_API_KEY
VONAGE_API_SECRET
VONAGE_WEBHOOK_SECRET
VONAGE_APPLICATION_ID
VONAGE_NUMBER
VONAGE_PRIVATE_KEY_PATH
(if using JWT/Secure Media): For production, it's highly recommended to store the content of the private key directly in a secure environment variable (e.g.,VONAGE_PRIVATE_KEY_CONTENT
perhaps base64 encoded) instead of deploying the key file. This avoids file system complexities and enhances security. Adjust your SDK initialization logic (Section 5.2) to read the key content from the environment variable if the path variable isn't set. Using the file path might be simpler for local development but less ideal for production.SESSION_SECRET
if using auth). Check RedwoodJS deployment docs for specifics.