Frequently Asked Questions
You can send SMS messages within a RedwoodJS application by creating a serverless function that integrates with the Twilio Programmable Messaging API. This function will handle the logic for sending messages using your Twilio credentials and the recipient's phone number.
Twilio Programmable Messaging is a cloud communications platform that allows developers to send and receive SMS, MMS, and WhatsApp messages programmatically. It provides a simple REST API and client libraries for various programming languages, including Node.js, which is used in RedwoodJS.
RedwoodJS uses serverless functions for SMS because they provide a scalable and cost-effective way to handle backend logic without managing servers. This is ideal for tasks like sending SMS messages, which are often triggered by user actions or scheduled events.
A message queue like BullMQ is recommended for high-volume SMS sending or when implementing retry mechanisms to handle temporary failures. It helps prevent API gateway timeouts by offloading the sending process to a background worker.
You should store your Twilio Account SID, Auth Token, and Twilio phone number as environment variables in a `.env` file in the root of your RedwoodJS project. This file is automatically excluded from version control via `.gitignore` for security.
The API endpoint for sending SMS is `/api/sendSms`. It accepts `POST` requests with a JSON body containing the recipient's phone number (`to`) in E.164 format and the message content (`body`).
The provided code example includes a `try...catch` block within the `sendSms` function's handler. This catches errors during the Twilio API call, logs them using Redwood's logger, and returns a JSON error response with an appropriate HTTP status code and details about the error, if available from Twilio.
The recipient's phone number (`to`) must be in E.164 format. This is an international standard and includes a plus sign (+) followed by the country code and phone number, without any spaces or dashes (e.g., +15551234567).
Yes, you can test the `sendSms` function locally by running `yarn rw dev` to start the development server and then using `curl` or a tool like Postman to send `POST` requests to the `/api/sendSms` endpoint with test data.
Common Twilio errors include 20003 (invalid credentials), 21608 (unverified recipient number for trial accounts), 21212 (invalid "from" number), 21211 (invalid "to" number), and 20429/HTTP 429 (rate limits exceeded). Always consult the Twilio error documentation for detailed explanations and troubleshooting.
Logs are available in your RedwoodJS development console when running `yarn rw dev`, within your hosting provider’s logging service in production, and in the Twilio Console under "Monitor" -> "Logs" -> "Messaging". Twilio logs provide detailed information on message status and delivery.
Critically, the example `sendSms` function is insecure without authentication. In production, you *must* secure it using RedwoodJS's authentication features (`yarn rw setup auth`) and the `@requireAuth` directive or by checking `isAuthenticated` / `currentUser` in your function handler.
For high-volume SMS, use a message queue (like BullMQ with Redis) to handle sending asynchronously and implement retry mechanisms. Consider using Twilio Messaging Services to improve deliverability and manage opt-outs, and distribute sending across multiple Twilio numbers if necessary.
Sending SMS with Twilio in RedwoodJS: A Developer Guide
This guide provides a step-by-step walkthrough for integrating Twilio's Programmable Messaging API into a RedwoodJS application to send basic SMS messages using a Node.js backend function. We'll cover everything from project setup and configuration to implementation, error handling, testing, and deployment considerations.
By the end of this guide, you will have a secure RedwoodJS function capable of accepting a phone number and message body, and using Twilio to send an SMS message to that number. This functionality is crucial for applications needing to send notifications, alerts, verification codes, or other transactional messages programmatically.
Project Overview and Goals
Goal: To build a RedwoodJS API function that sends an SMS message via the Twilio API.
Problem Solved: Enables programmatic SMS communication directly from your RedwoodJS backend, facilitating features like user notifications, appointment reminders, or two-factor authentication prompts.
Technologies:
System Architecture:
sendSms
in this guide) receives the request (containing recipient number and message body).Prerequisites:
npm install --global yarn
).Final Outcome: A RedwoodJS project with a functional
/api/sendSms
endpoint that securely sends SMS messages using Twilio.1. Setting up the RedwoodJS Project
Let's start by creating a new RedwoodJS project and installing the necessary dependencies.
Create a New RedwoodJS App: Open your terminal and run:
Follow the prompts (you can choose JavaScript or TypeScript - this guide uses JavaScript examples, but the concepts are identical).
Navigate to Project Directory:
Install Twilio Node.js Helper Library: RedwoodJS uses Yarn workspaces. We need to install the Twilio library specifically in the
api
workspace.This command adds the
twilio
package to theapi/package.json
file and installs it.Configure Environment Variables: Sensitive credentials like API keys should never be hardcoded. RedwoodJS uses
.env
files for environment variables..env
file in the root of your project (redwood-twilio-sms/.env
)..env
file:Obtaining Credentials:
TWILIO_ACCOUNT_SID
andTWILIO_AUTH_TOKEN
: Find these on your main Twilio Console dashboard (https://www.twilio.com/console).TWILIO_PHONE_NUMBER
: This is the SMS-enabled Twilio phone number you purchased. Find it under ""Phone Numbers"" > ""Manage"" > ""Active numbers"" in your Twilio Console. Ensure it's in E.164 format (e.g.,+15551234567
).Security: Ensure your
.env
file is listed in your.gitignore
file (RedwoodJS includes this by default) to prevent accidentally committing secrets.2. Implementing Core Functionality: The SMS Sending Function
We'll create a RedwoodJS API function to handle the SMS sending logic.
Generate the API Function: Use the RedwoodJS CLI to scaffold a new function:
This creates the file
api/src/functions/sendSms.js
(or.ts
) with some boilerplate code.Implement the Sending Logic: Replace the contents of
api/src/functions/sendSms.js
with the following code:Code Explanation:
logger
for logging and thetwilio
library.process.env
and initialize the Twilio client. Crucially, we check if the environment variables exist before initializing.handler
).POST
requests.event
and validates the presence and basic format of theto
phone number (must start with+
) and thebody
.client.messages.create
with thebody
,from
(your Twilio number), andto
parameters. This is an asynchronous operation, so we useawait
.200 OK
status with the message SID and status.try...catch
block handles potential errors during the API call (e.g., invalid credentials, network issues, Twilio errors). It logs the error and returns an appropriate error status code (using Twilio's status if available, otherwise 500) and a JSON error message, potentially including Twilio-specific error codes (error.code
) and documentation links (error.moreInfo
) for easier debugging.3. Building the API Layer
The RedwoodJS function is our API layer for this specific task.
Endpoint:
/api/sendSms
Method:
POST
Request Body (JSON):
Success Response (JSON - 200 OK):
Error Response (JSON - 4xx/5xx):
Testing with
curl
: Make sure your RedwoodJS development server is running (yarn rw dev
). Open a new terminal window and run:+1YOUR_VERIFIED_PHONE_NUMBER
with your actual mobile number (which must be verified in Twilio if using a trial account).yarn rw dev
for logs.4. Integrating with Twilio
This was covered in steps 1 (installation, environment variables) and 2 (client initialization, API call).
Key Configuration Points:
TWILIO_ACCOUNT_SID
: Your unique account identifier. Found on the Twilio Console dashboard. Purpose: Identifies your account to Twilio. Format:ACxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
.TWILIO_AUTH_TOKEN
: Your secret API key. Found on the Twilio Console dashboard. Treat this like a password. Purpose: Authenticates your API requests. Format: Alphanumeric string.TWILIO_PHONE_NUMBER
: The Twilio number messages will be sent from. Found in the Phone Numbers section of the Twilio Console. Purpose: Sets thefrom
number for outgoing SMS. Format: E.164 (+1...
).Dashboard Navigation:
5. Error Handling, Logging, and Retry Mechanisms
try...catch
block inapi/src/functions/sendSms.js
. It catches errors from theclient.messages.create
call, logs them using Redwood's logger, and returns structured JSON error responses with appropriate HTTP status codes. It includes Twilio-specific error details when available (error.code
,error.moreInfo
).logger
(api/src/lib/logger.js
) is used.logger.info
: Logs successful operations and key steps.logger.error
: Logs exceptions and failure conditions.logger.warn
: Logs non-critical issues like invalid input.yarn rw dev
is running. In production deployments, logs are typically routed to your hosting provider's logging service (e.g., Vercel Logs, Netlify Functions Logs).bullmq
and Redis) to handle sending and retries more robustly, preventing HTTP request timeouts for long-running processes. This is beyond the scope of this basic guide.Testing Error Scenarios:
TWILIO_AUTH_TOKEN
in.env
to an incorrect value, restartyarn rw dev
, and send acurl
request. Expect a 401 or similar error.to
Number: Send acurl
request with an improperly formattedto
number (e.g.,5551234
,+1
). Expect a 400 error from our validation. Send a validly formatted but non-existent number – expect an error from Twilio (potentially logged, response might vary).curl
request with""body"": """"
. Expect a 400 error from our validation.6. Database Schema and Data Layer
Not Applicable: This specific function does not require database interaction. It receives data via the API request and interacts directly with the external Twilio service. If you needed to store message history, associate messages with users, or manage opt-outs, you would define Prisma schemas in
api/db/schema.prisma
, generate migrations (yarn rw prisma migrate dev
), and use Redwood's services (yarn rw g service ...
) to interact with the database before or after calling the Twilio API.7. Security Features
api/src/functions/sendSms.js
function includes basic validation for theto
andbody
parameters to prevent malformed requests or trivial injection attempts (though Twilio's API handles its own sanitization). More robust validation (e.g., usingyup
orzod
) is recommended for complex inputs.TWILIO_ACCOUNT_SID
,TWILIO_AUTH_TOKEN
) are stored securely in environment variables (.env
) and are not checked into version control (.gitignore
). In production, these are configured via the hosting provider's environment variable settings./api/sendSms
) can potentially call it.yarn rw setup auth ...
) and add the@requireAuth
directive or checkisAuthenticated
/currentUser
within thehandler
function to ensure only authorized users or services can trigger SMS sending. It is critical to understand that the function as presented without authentication is insecure and unsuitable for production environments. See RedwoodJS Auth Docs.429 Too Many Requests
errors (Twilio error code 20429).8. Handling Special Cases
to
number is always in E.164 format (+
followed by country code and number, no spaces or dashes). The validation enforces the leading+
, but more comprehensive E.164 validation libraries exist if needed.body
is sent as-is. If you need to send messages in different languages, your application logic (potentially in a RedwoodJS service calling this function) would need to determine the correct language and provide the translatedbody
text.body
you provide. Twilio handles the encoding details.mediaUrl
parameter to theclient.messages.create
call, pointing to a publicly accessible URL of the media file. MMS is typically only supported in the US and Canada.9. Performance Optimizations
client.messages.create
call is asynchronous (await
), preventing the Node.js event loop from being blocked during the API request.from
number. You pass themessagingServiceSid
instead offrom
toclient.messages.create
.10. Monitoring, Observability, and Analytics
queued
,sent
,delivered
,undelivered
,failed
), error codes, message segments, and cost. This is invaluable for debugging delivery issues./api/health
) that returns200 OK
to ensure the API side is generally responsive.sendSms
function.11. Troubleshooting and Caveats
yarn rw dev
is running. This often shows immediate errors from your function code (like parsing errors, invalid input, or exceptions before the Twilio call is even made).TWILIO_ACCOUNT_SID
andTWILIO_AUTH_TOKEN
in your.env
file and ensure they match the Twilio Console. Restartyarn rw dev
after changes.From
Number (Twilio Error 21212): EnsureTWILIO_PHONE_NUMBER
in.env
is a valid Twilio number associated with your account and enabled for SMS.To
Number (Twilio Error 21211): Ensure theto
number provided in the request body is a valid phone number in E.164 format. Check Twilio logs for details if the format is correct but delivery fails..env
Not Loaded: Ensure the.env
file is in the project root andyarn rw dev
was restarted after creating/modifying it. Check that the environment variables are correctly named.@requireAuth
), this endpoint is open. Secure it before deploying to production.curl
command or frontend request sends a valid JSON body with the correctContent-Type: application/json
header.12. Deployment and CI/CD
TWILIO_ACCOUNT_SID
,TWILIO_AUTH_TOKEN
, andTWILIO_PHONE_NUMBER
environment variables within your hosting provider's settings dashboard (e.g., Vercel Environment Variables, Netlify Build environment variables). Do not commit your.env
file.yarn install
), potentially run tests (yarn rw test
), build the app (yarn rw build
), and deploy (vercel deploy --prod
,netlify deploy --prod
, etc.).13. Verification and Testing
Manual Verification:
yarn rw dev
.curl
(as shown in Section 3) or a tool like Postman/Insomnia to send aPOST
request tohttp://localhost:8910/api/sendSms
with a valid JSON body.curl
/tool response for a200 OK
status and JSON body with""success"": true
.yarn rw dev
console output for logs.Automated Testing (Jest): RedwoodJS uses Jest for testing. Let's write a basic test for our function.
api/src/functions/sendSms.test.js
:jest.mock('twilio', ...)
to replace the actual Twilio library with a mock.client.messages.create
function, allowing us to control its return value (mockResolvedValue
) or make it throw an error (mockRejectedValue
).src/lib/logger
to avoid log output during tests.process.env
variables needed by the function within the test suite usingbeforeAll
and restore them withafterAll
.it(...)
block tests a specific scenario: wrong HTTP method, invalid input, successful call, and failed API call.mockHttpEvent
from@redwoodjs/testing/api
to simulate the event object passed to the handler.statusCode
andbody
of the response.twilio().messages.create
function was called with the correct arguments.