Frequently Asked Questions
You can send SMS messages by creating a RedwoodJS service that uses the Vonage Node.js SDK. This service interacts with the Vonage Messages API to send messages programmatically, ideal for notifications or marketing campaigns within your RedwoodJS application.
The Vonage Messages API is a unified API that allows developers to send and receive messages across multiple channels, including SMS. This guide focuses on using the API for SMS communication within a RedwoodJS application.
RedwoodJS uses GraphQL for its API layer to provide a structured and efficient way to communicate between the front-end and back-end. This facilitates data fetching and mutations, like sending an SMS message, using a strongly typed schema.
ngrok is essential during local development with Vonage webhooks. Because your local RedwoodJS server isn't publicly accessible, ngrok creates a secure tunnel to expose it, allowing Vonage to send webhook data to your application for testing incoming SMS messages.
Yes, a free ngrok account is sufficient for development and testing purposes. It provides the necessary functionality to create a temporary public URL for your local server, enabling Vonage webhook integration.
You can receive SMS messages by setting up a webhook handler in your RedwoodJS application. Vonage will send incoming message data to this webhook, which you can then process and store using a RedwoodJS function and Prisma.
A Vonage Application ID is a unique identifier for your Vonage application settings and configurations. It groups your Vonage numbers and API settings, enabling you to manage your SMS integrations effectively. You need this to initialize the Vonage Node.js SDK.
You need Node.js version 20 or higher for this integration. The recommendation is to use NVM (Node Version Manager) to effectively manage and switch between Node.js versions as needed for different projects.
SMS message logs are stored using Prisma, RedwoodJS's default ORM. You define a schema in schema.prisma to structure your data and then use Prisma Client in your service and serverless functions to interact with the database.
While not explicitly covered in this guide, securing webhooks is crucial in production. Consider verifying the webhook signature using the Vonage SDK to ensure requests are genuinely from Vonage and haven't been tampered with. Never expose your webhook secrets publicly.
Setting the Default SMS API to "Messages API" in your Vonage Dashboard is crucial for correct integration with the '@vonage/server-sdk'. It ensures that incoming SMS messages are routed through the correct API and are processed as expected by your RedwoodJS application.
RedwoodJS uses .env files for managing environment variables, including sensitive API keys. Add your .env file and your private.key to your .gitignore file to prevent accidentally committing these credentials to your repository.
You'll need Node.js 20+, Yarn Classic (v1.x), a Vonage API account (with API Key and Secret), a Vonage virtual number, and ngrok for local testing.
The private.key file contains your Vonage Application's private key, crucial for authenticating your application with the Vonage API securely. Save this file securely and never expose it publicly or commit it to version control.
Developer Guide: Implementing Vonage SMS in RedwoodJS with Node.js
Build SMS marketing campaigns and two-way messaging in your RedwoodJS application using the Vonage Messages API. Send outbound SMS messages for notifications or marketing campaigns and receive inbound messages via webhooks, leveraging RedwoodJS's full-stack architecture.
Complete this guide to build a RedwoodJS application that:
Use this setup for alerts, two-factor authentication, marketing campaigns, customer support conversations, and user engagement.
Prerequisites:
node -v). Use nvm to manage Node versions.yarn -v).Project Overview and Goals
Build a RedwoodJS application with these SMS components:
Technologies:
@vonage/server-sdk– Official Vonage Node.js SDK for API interactionsSystem Architecture:
How Do You Set Up a RedwoodJS Project for Vonage SMS?
Create a new RedwoodJS project and configure the necessary Vonage components.
1.1 Create RedwoodJS App:
Open your terminal and run the Create Redwood App command. Use TypeScript (default) and initialize a git repository.
1.2 Environment Variables Setup:
Store API keys and sensitive information securely using
.envfiles.Create a
.envfile in the root of your project:Add these environment variables to your
.envfile (you'll populate these values in the next steps):Add
.envandprivate.keyto your.gitignorefile to prevent committing secrets. The default RedwoodJS.gitignorealready includes.env, but verify and addprivate.key.1.3 Vonage Account Setup:
.envfile.14155551212) intoVONAGE_VIRTUAL_NUMBERin your.envfile.@vonage/server-sdkto function correctly. Save the changes.1.4 Create Vonage Application:
Vonage Applications group your numbers and configurations together.
private.keyfile that downloads. Save it in your RedwoodJS project root (or updateVONAGE_PRIVATE_KEY_PATHin.envif you save it elsewhere).https://example.com/webhooks/inboundhttps://example.com/webhooks/statusVONAGE_APPLICATION_IDin your.envfile.1.5 Install Vonage SDK:
Install the Vonage Node.js SDK in the
apiworkspace.How Do You Implement SMS Sending with Vonage in RedwoodJS?
Create a RedwoodJS service to handle sending SMS messages via Vonage.
2.1 Create SMS Service:
Generate the service files using the RedwoodJS CLI.
This creates
api/src/services/sms/sms.tsand related test/scenario files.2.2 Configure Vonage Client:
Initialize the Vonage client centrally using a utility file for better code organization and health monitoring.
Create
api/src/lib/vonage.ts:VONAGE_PRIVATE_KEY_CONTENTif available, falling back toVONAGE_PRIVATE_KEY_PATH. RedwoodJS's Pino logger provides structured logging.2.3 Implement
sendSmsFunction:Edit the generated service file (
api/src/services/sms/sms.ts) to add the sending logic.sendmethod, and handles errors usingtry...catch. It returns a structured response indicating success or failure. Logging provides process visibility.How Do You Build a GraphQL Mutation for SMS in RedwoodJS?
Expose your
sendSmsservice function through a GraphQL mutation.3.1 Define GraphQL Schema (SDL):
Edit the schema definition file
api/src/graphql/sms.sdl.ts.SmsResponse: Specifies the fields returned by the mutation.Mutation: Defines available mutations.sendSmstakestoandtextas non-nullable String arguments and returns anSmsResponse.@skipAuth: Development only. Disables authentication. Replace with@requireAuthin production to ensure only authenticated users trigger the mutation.3.2 Test the Mutation:
Start the development server:
Open your browser to the RedwoodJS GraphQL Playground:
http://localhost:8911/graphql.Enter this mutation in the left panel (replace
YOUR_REAL_PHONE_NUMBERwith your actual phone number in E.164 format):Click the "Play" button.
You should receive an SMS on your phone, and the GraphQL response should look like:
If you get
success: false, check theerrormessage and review the terminal output whereyarn rw devis running for logs fromapi/src/services/sms/sms.ts. Common issues include incorrect API credentials, wrong phone number formats, or the private key file not being found.3.3
curlExample:Test the GraphQL endpoint using
curl:Replace
YOUR_REAL_PHONE_NUMBERaccordingly.How Do You Receive SMS Messages via Webhooks in RedwoodJS?
Configure Vonage to send incoming SMS messages to your application via webhooks.
4.1 Expose Localhost with ngrok:
Vonage can't reach your local RedwoodJS app directly. Create a secure tunnel using
ngrok.Stop
yarn rw devif running (Ctrl+C).Start
ngrokto forward to Redwood's API port (8911):Copy the HTTPS "Forwarding" URL from ngrok's output (e.g.,
https://<unique-id>.ngrok-free.app).4.2 Update Vonage Application Webhook URLs:
YOUR_NGROK_HTTPS_URL/webhooks/inboundYOUR_NGROK_HTTPS_URL/webhooks/statusYOUR_NGROK_HTTPS_URLwith your ngrok URL).POST.4.3 Create RedwoodJS Webhook Handler:
Generate a RedwoodJS function for webhook handling:
This creates
api/src/functions/vonageWebhook.ts.4.4 Implement Webhook Logic:
Modify
api/src/functions/vonageWebhook.tsto handle incoming messages and status updates, supporting both JSON and form-urlencoded payloads.parseRequestBodyhelper handles bothapplication/jsonandapplication/x-www-form-urlencodedcontent types for robustness. The code usesevent.pathto determine whether it's an inbound message or status update, parses the payload, logs relevant information, and returns a200 OKstatus promptly to acknowledge receipt. Error handling logs issues without causing Vonage to retry endlessly.4.5 Test Receiving SMS:
ngrokis running and pointing to port 8911.yarn rw dev.yarn rw dev. You should see log entries fromapi/src/functions/vonageWebhook.tsindicating an "inbound SMS" was received, with details like sender number (msisdn) and message text. Check for parsing warnings or errors.http://127.0.0.1:4040), including theContent-Typeheader Vonage sent.How Do You Implement Error Handling and Logging for SMS?
Error Handling Strategy:
sendSmsservicetry...catchblocks catch Vonage SDK errors{ success: false, error: '...' }objecttry...catchwith graceful degradation200 OKto Vonage while logging errors internallyLogging Approach:
RedwoodJS's Pino logger (
src/lib/logger) tracks key events:For production, configure log levels and integrate with monitoring services (Datadog, Logflare, CloudWatch).
Retry Mechanisms:
sendSmsdoesn't implement retries. For critical messages, wrap thevonage.messages.sendcall in a retry loop with exponential backoff using libraries likeasync-retryorp-retryfor transient network or API errors.200 OKwithin a few seconds. The handler returns 200 quickly, even if background processing fails, to prevent unnecessary retries.Testing Error Scenarios:
Force an error by providing an invalid
tonumber format or temporarily changing the API key in.envto something invalid. Trigger thesendSmsmutation and observe the logged error and{ success: false, ... }response.How Do You Create a Database Schema for SMS Logging?
Log sent and received messages to the database using Prisma.
6.1 Define Prisma Schema:
Edit
api/db/schema.prismaand add aSmsLogmodel.vonageIdis unique to prevent duplicate entries from retried webhooks, using CUID as a fallback if the Vonage ID isn't obtained.6.2 Create and Run Migration:
Apply the schema changes to your database.
6.3 Update Service and Webhook to Log Data:
Modify the
sendSmsservice and thevonageWebhookfunction to interact with the database. Add thecuidpackage if needed:yarn workspace api add cuid.api/src/services/sms/sms.ts(sendSms):api/src/functions/vonageWebhook.ts(handler):Database integration: The
sendSmsservice logs each attempt to theSmsLogtable, recording initial submission or failure. ThevonageWebhookhandler logs incoming messages (INBOUND) and updates outbound message statuses based on status webhooks. The code usesupdatefor status changes andcreatefor inbound messages with duplicate checking to handle message states correctly, including Vonage retries.Frequently Asked Questions About Vonage SMS in RedwoodJS
What Node.js version does RedwoodJS require for Vonage integration?
RedwoodJS requires Node.js version 20 or higher as of 2025. Check your version with
node -vand use nvm (Node Version Manager) to switch versions if needed. Vonage's@vonage/server-sdkworks seamlessly with Node.js 20 LTS. Avoid Node.js 21+ for production deployments – it may cause compatibility issues with deployment targets like AWS Lambda.How do I get Vonage API credentials for RedwoodJS?
Log into the Vonage API Dashboard and locate your API Key and Secret on the main page. Create a new Application under "Applications" > "Create a new application", enable the Messages capability, and generate a private key file. Download the
private.keyfile immediately and store it in your project root. Copy the Application ID into your.envfile. Purchase an SMS-capable virtual number from "Numbers" > "Buy numbers" and link it to your application.What is E.164 phone number format and why does Vonage require it?
E.164 is the ITU-T international telephone numbering standard ensuring globally unique phone numbers. The format starts with a + sign, followed by the country code (1-3 digits) and subscriber number, with a maximum of 15 digits total (e.g., +14155551234). Vonage requires E.164 format to eliminate routing ambiguity across international SMS networks. Use the regex pattern
/^\+?[1-9]\d{1,14}$/for basic validation, or implementlibphonenumber-jsfor production-grade validation.How do I secure Vonage webhooks in RedwoodJS?
Secure Vonage webhooks in RedwoodJS functions by:
Authorizationheader using Vonage's JWT verificationWhat are SMS character limits with Vonage Messages API?
SMS messages use two encoding types:
Messages exceeding these limits split into multiple segments automatically, with each segment consuming additional credits. Special characters like
| ^ € { } [ ] ~ \require escape codes in GSM-7, consuming two character positions each.How do I implement SMS marketing campaigns with rate limiting in RedwoodJS?
Create a batch processing service that:
p-retryorasync-retryto handle Vonage API rate limits (typically 10-20 messages per second)Always comply with TCPA (US), GDPR (Europe), and local SMS marketing regulations requiring user opt-in.
Can I send bulk SMS messages to multiple recipients with this RedwoodJS setup?
Yes, extend the
sendSmsservice to accept an array of recipients and implement batch processing with rate limiting. Create a GraphQL mutation that queues messages in your database, then use RedwoodJS background jobs (via@redwoodjs/jobs) to process the queue asynchronously. This prevents timeout issues with large campaigns. Monitor Vonage API rate limits and implement exponential backoff for failed messages. Track campaign progress using Prisma database queries and provide real-time updates via GraphQL subscriptions.How do I handle SMS delivery failures and retries in production?
Vonage sends delivery status updates to your status webhook endpoint. Implement this workflow:
SmsLogdatabase record with status (DELIVERED, FAILED, etc.)What security best practices should I follow for Vonage credentials in RedwoodJS?
Follow these security practices:
.envorprivate.keyfiles – add to.gitignorechmod 600 private.key)VONAGE_PRIVATE_KEY_CONTENTenvironment variable to avoid file system dependencies