Frequently Asked Questions
Use the Vonage Messages API and Node.js SDK within a RedwoodJS service. Create a service function that initializes the Vonage client with your API credentials and uses the vonage.messages.send method with a WhatsAppText object to send messages.
The Vonage Messages API Sandbox is a testing environment provided by Vonage that allows developers to experiment with WhatsApp integration without a dedicated WhatsApp Business Account. It provides a sandbox number and allows you to whitelist personal WhatsApp numbers for testing.
RedwoodJS uses environment variables (.env files) to store sensitive information like API keys and secrets. This approach keeps credentials out of your codebase, improving security and portability across different environments.
The apiHost pointing to the sandbox should be removed from your Vonage client configuration when you deploy your RedwoodJS application to production and are ready to use a live WhatsApp Business Account and number.
While Vonage's primary interaction is through webhooks, you can create GraphQL mutations to trigger outbound WhatsApp messages manually from your RedwoodJS frontend. Define a mutation in your schema, implement a corresponding service function, and call sendWhatsAppMessage within it.
Configure webhook URLs in both your Vonage application settings and the Messages API Sandbox. Use your Ngrok URL combined with the Redwood function paths (e.g., YOUR_NGROK_URL/.redwood/functions/whatsappInbound). This allows Vonage to send incoming messages and status updates to your Redwood application.
Ngrok creates a public URL that tunnels to your local development server, which is essential for Vonage to send webhooks to your RedwoodJS application during development. Vonage webhooks require a publicly accessible URL to reach your local machine.
Create a Redwood function (whatsappStatus) to handle status update webhooks. Verify the JWT signature for security, parse the message status, and update your database accordingly using the handleMessageStatusUpdate service function.
You need Node.js 18+, Yarn, the RedwoodJS CLI, a Vonage API account (with API Key and Secret), Ngrok, a WhatsApp account for testing, basic Git knowledge, and a compatible operating system (macOS, Windows with WSL, or Linux).
Store Vonage credentials (including the private key content) as environment variables in a .env file. Ensure this file is added to your .gitignore. For production, use secure secret management provided by your hosting platform (like Render Environment Variables).
Create a Redwood function (whatsappInbound) as an API endpoint to handle incoming WhatsApp messages. This function will receive message data via webhooks from the Vonage Messages API after you've configured the webhook URL in your Vonage application settings.
RedwoodJS Services encapsulate the core logic for interacting with external APIs like Vonage. They provide a structured way to organize your Vonage API calls, handle authentication, send messages, and process incoming webhooks.
Navigate to the 'api' workspace in your RedwoodJS project and run yarn add @vonage/server-sdk @vonage/messages @vonage/jwt. These packages provide the necessary tools to interact with the Vonage APIs.
Common errors include incorrect environment variable setup, webhook URL misconfiguration, JWT signature verification failures, and issues with parsing JSON payloads. The guide provides troubleshooting tips and error handling suggestions for each step.
Build Vonage WhatsApp Integration with RedwoodJS & Node.js
Integrate Vonage's Messages API to send and receive WhatsApp messages within your RedwoodJS application. You'll build a complete solution with webhook handling, JWT security, Prisma database logging, and automated message replies using RedwoodJS Functions and Services.
By the end of this tutorial, you'll have a production-ready RedwoodJS application capable of two-way WhatsApp communication, complete with security best practices, deployment guidance, and troubleshooting strategies.
Project Overview and Goals
What You'll Build:
Create a RedwoodJS application featuring:
Problem Solved: This guide enables you to leverage WhatsApp's ubiquity for customer communication, notifications, or bot interactions directly within your RedwoodJS applications, using Vonage as the communication provider.
Technologies Used:
System Architecture:
Prerequisites:
npm install -g @redwoodjs/clioryarn global add @redwoodjs/cli).1. Setting up the RedwoodJS Project
Create a new RedwoodJS project and configure it for Vonage integration.
Create RedwoodJS App: Open your terminal and run:
Choose TypeScript when prompted for the best development experience.
Install Dependencies: Install the Vonage SDKs. Navigate to the
apiworkspace:@vonage/server-sdk: Core SDK for authentication and general API access@vonage/messages: Specific SDK for the Messages API@vonage/jwt: Verifies webhook signaturesConfigure Environment Variables: RedwoodJS uses
.envfiles for environment variables. Create a.envfile in your project root:How to Obtain These Values:
VONAGE_API_KEY&VONAGE_API_SECRET: Found on the main page of your Vonage API Dashboard after logging in.VONAGE_APPLICATION_ID&VONAGE_PRIVATE_KEY_CONTENT:private.keyfile that downloads.private.keyfile with a text editor and copy its entire content.VONAGE_PRIVATE_KEY_CONTENTin your.envfile. Make sure to include the-----BEGIN PRIVATE KEY-----and-----END PRIVATE KEY-----lines and enclose the whole thing in double quotes.VONAGE_APPLICATION_IDwill be displayed for your new application. Copy it.VONAGE_API_SIGNATURE_SECRET: Go to the Vonage Dashboard → Settings. Find your API key and click Edit. Your signature secret is listed there. If none exists_ generate one.VONAGE_WHATSAPP_NUMBER: Go to Messages API Sandbox in the Vonage Dashboard. The sandbox number is displayed prominently (often14157386102). You'll also need to allowlist your personal WhatsApp number here by sending the specified message from your phone to the sandbox number.Security Considerations:
.envFile: Add.envto your.gitignorefile to prevent committing secrets. Redwood's default.gitignoreusually covers this_ but double-check.VONAGE_PRIVATE_KEY_CONTENTvalue as highly sensitive. Do not commit it to version control. Use platform-specific secret management (like Render Environment Variables_ GitHub Secrets_ etc.) for production deployments.VONAGE_PRIVATE_KEY_CONTENTis strongly preferred_ for local development only_ you could save theprivate.keyfile (e.g._ in the project root) and set an environment variable likeVONAGE_PRIVATE_KEY_PATH="./private.key". You would then need to modify the service code (Section 2) to read the file usingfs.readFileSync. This approach is less secure_ less portable_ and generally not suitable for serverless/containerized deployments. Ensure the key file is also in.gitignore.Start Ngrok: Vonage needs a publicly accessible URL to send webhooks. Ngrok creates a secure tunnel to your local machine. The RedwoodJS API server runs on port 8911 by default (defined by
PORTin.env).Ngrok displays a forwarding URL like
https://<unique_id>.ngrok.ioorhttps://<unique_id>.ngrok.app. Keep this URL handy. Keep this terminal window running.Configure Vonage Webhooks: Tell Vonage where to send incoming messages and status updates.
Application Webhooks: Go back to your application settings in the Vonage Dashboard (Applications → Your App → Edit).
YOUR_NGROK_URL/.redwood/functions/whatsappInbound(e.g.,https://xyz.ngrok.app/.redwood/functions/whatsappInbound)YOUR_NGROK_URL/.redwood/functions/whatsappStatus(e.g.,https://xyz.ngrok.app/.redwood/functions/whatsappStatus)Sandbox Webhooks: Go to the Messages API Sandbox page.
Why configure both? The Sandbox Webhooks are used specifically when you interact directly with the Messages API Sandbox environment (using the sandbox number, allowlisted numbers, etc.). The Application Webhooks are tied to your specific Vonage Application (identified by the
VONAGE_APPLICATION_ID). These become relevant when you move beyond the sandbox, potentially using a purchased WhatsApp number linked to that application or utilizing other application-specific features. For initial sandbox testing, configuring both ensures messages sent via the sandbox trigger your endpoints correctly.Why
/.redwood/functions/? This is the default path RedwoodJS exposes its API functions under during development and typically in serverless deployments.2. Implementing Core Functionality (API Side)
Create Redwood Functions to handle the webhooks and a Service to manage Vonage interactions.
Create Redwood Service for Vonage: Services encapsulate business logic. Generate a service:
This creates
api/src/services/vonage/vonage.ts(and test files).Implement Vonage Service Logic: Open
api/src/services/vonage/vonage.tsand add the following code:Vonageclient using environment variables, now directly usingVONAGE_PRIVATE_KEY_CONTENTfor theprivateKey. The complex file reading logic is removed. Remember to manage theVONAGE_PRIVATE_KEY_CONTENTsecurely, especially in production. The sandboxapiHostis explicitly set; remove this line when deploying to production.sendWhatsAppMessage: Takestoandtext, usesvonage.messages.sendwithWhatsAppText, logs the outcome, and logs the message to the database. Includes improved error logging.handleInboundWhatsAppMessage: Logs the incoming message and triggerssendWhatsAppMessagefor a reply.handleMessageStatusUpdate: Logs the status update and attempts to update the corresponding message record in the database, including error details if present.logMessage: A helper to encapsulate database logging logic, now withstatusDetails.Create Webhook Functions: Generate the functions to handle HTTP requests from Vonage:
--no-typescriptfor simplicity here, but feel free to use TypeScript.Implement Inbound Webhook Function: Open
api/src/functions/whatsappInbound.js(or.ts) and add:from.number), message text (message.content.text), and message ID (message_uuid).handleInboundWhatsAppMessageservice function.200 OKstatus to Vonage. Basic error handling returns appropriate status codes.Implement Status Webhook Function: Open
api/src/functions/whatsappStatus.js(or.ts) and add:verifySignatureand yourVONAGE_API_SIGNATURE_SECRET. Do not skip this step.handleMessageStatusUpdateservice function.200 OK.3. Building a complete API layer
RedwoodJS handles the API layer primarily through GraphQL. While our core interaction uses webhook Functions (plain HTTP endpoints), you could expose functionality via GraphQL if needed.
Example GraphQL Mutation (Conceptual):
Define Schema: Add to
api/src/graphql/vonage.sdl.ts:Implement Service Function: Add a wrapper in
api/src/services/vonage/vonage.ts:Generate Types:
yarn rw g typesTest: Use the Redwood GraphQL playground (
yarn rw dev, navigate to/graphql) to call the mutation (requires authentication setup via@requireAuth).This section is optional for the basic webhook setup but shows how to integrate with Redwood's standard API pattern if needed.
4. Integrating with Vonage (Summary)
This was covered extensively during setup and implementation. Key points:
.env(use proper secret management like platform environment variables or a secrets manager in production).@vonage/server-sdkand@vonage/messagesin the service layer (api/src/services/vonage/vonage.ts), configured with credentials (reading private key content from env var) and the sandboxapiHost(which should be removed for production)./.redwood/functions/whatsappInbound,/.redwood/functions/whatsappStatus)..envvariable's purpose and origin is detailed in Section 1, Step 3.5. Error Handling, Logging, and Retry Mechanisms
pinologger (api/src/lib/logger.ts) is used throughout the service and function code (logger.info,logger.error,logger.warn,logger.debug). SDK logs are also piped to Redwood's logger. Check your console output during development. Configure production log levels and potentially ship logs to a logging service.try...catchblocks are used in service functions (sendWhatsAppMessage, database interactions) and webhook handlers.whatsappInbound,whatsappStatus) don't return a2xxstatus code promptly (within a few seconds). Ensure your functions respond quickly. If processing takes longer, acknowledge the webhook immediately (return 200 OK) and handle the processing asynchronously (e.g., using Redwood experimental background jobs or a dedicated queue).sendWhatsAppMessagedoesn't implement retries on failure. For production, consider adding retries for transient errors (like network issues or temporary Vonage unavailability).