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.
This guide provides a step-by-step walkthrough for integrating Vonage's Messages API to send and receive WhatsApp messages within a RedwoodJS application. We will build a simple application that can receive WhatsApp messages via a webhook and send replies back using the Vonage Node SDK.
By the end of this tutorial, you will have a RedwoodJS application capable of basic two-way WhatsApp communication, complete with setup instructions, code implementation, security considerations, deployment guidance, and troubleshooting tips.
Project Overview and Goals
What We're Building:
We will create a RedwoodJS application featuring:
Problem Solved: This guide enables developers to leverage the ubiquity of WhatsApp for customer communication, notifications, or simple bot interactions directly within their RedwoodJS applications, using Vonage as the communication provider.
Technologies Used:
System Architecture:
Prerequisites:
npm install -g @redwoodjs/cli
oryarn global add @redwoodjs/cli
).1. Setting up the RedwoodJS Project
Let's 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: We need the Vonage SDKs. Navigate to the
api
workspace and install:@vonage/server-sdk
: Core SDK for authentication and general API access.@vonage/messages
: Specific SDK for the Messages API.@vonage/jwt
: Used for verifying webhook signatures.Configure Environment Variables: RedwoodJS uses
.env
files for environment variables. Create a.env
file in the 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.key
file that downloads.private.key
file with a text editor and copy its entire content.VONAGE_PRIVATE_KEY_CONTENT
in your.env
file. Make sure to include the-----BEGIN PRIVATE KEY-----
and-----END PRIVATE KEY-----
lines and enclose the whole thing in double quotes.VONAGE_APPLICATION_ID
will 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, you might need to 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 whitelist your personal WhatsApp number here by sending the specified message from your phone to the sandbox number.Security Considerations:
.env
File: Add.env
to your.gitignore
file to prevent committing secrets. Redwood's default.gitignore
usually covers this, but double-check.VONAGE_PRIVATE_KEY_CONTENT
value 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_CONTENT
is strongly preferred, for local development only, you could save theprivate.key
file (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
PORT
in.env
).Ngrok will display a forwarding URL like
https://<unique_id>.ngrok.io
orhttps://<unique_id>.ngrok.app
. Keep this URL handy. Keep this terminal window running.Configure Vonage Webhooks: Now, 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 are interacting directly with the Messages API Sandbox environment (using the sandbox number, whitelisted 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)
We'll 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.ts
and add the following code:Vonage
client using environment variables, now directly usingVONAGE_PRIVATE_KEY_CONTENT
for theprivateKey
. The complex file reading logic is removed. Remember to manage theVONAGE_PRIVATE_KEY_CONTENT
securely, especially in production. The sandboxapiHost
is explicitly set; remove this line when deploying to production.sendWhatsAppMessage
: Takesto
andtext
, usesvonage.messages.send
withWhatsAppText
, logs the outcome, and logs the message to the database. Includes improved error logging.handleInboundWhatsAppMessage
: Logs the incoming message and triggerssendWhatsAppMessage
for 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-typescript
for 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
).handleInboundWhatsAppMessage
service function.200 OK
status to Vonage. Basic error handling returns appropriate status codes.Implement Status Webhook Function: Open
api/src/functions/whatsappStatus.js
(or.ts
) and add:verifySignature
and yourVONAGE_API_SIGNATURE_SECRET
. Do not skip this step.handleMessageStatusUpdate
service 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 types
Test: 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-sdk
and@vonage/messages
in 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
)..env
variable's purpose and origin is detailed in Section 1, Step 3.5. Error Handling, Logging, and Retry Mechanisms
pino
logger (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...catch
blocks are used in service functions (sendWhatsAppMessage
, database interactions) and webhook handlers.whatsappInbound
,whatsappStatus
) don't return a2xx
status 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).sendWhatsAppMessage
doesn't implement retries on failure. For production, consider adding retries for transient errors (like network issues or temporary Vonage unavailability).