Frequently Asked Questions
You can send SMS messages with RedwoodJS by integrating the MessageBird SMS API. Create a RedwoodJS service and a GraphQL mutation to programmatically send messages, leveraging Redwood's full-stack capabilities and MessageBird's reliable platform. This is ideal for sending transactional notifications like OTPs and alerts.
The RedwoodJS MessageBird integration allows you to send SMS messages directly from your RedwoodJS application backend. It uses the MessageBird Node.js SDK and environment variables for API key management. This enables sending transactional SMS notifications like one-time passwords (OTPs) and alerts directly from your web application.
MessageBird offers a reliable and developer-friendly SMS API, and RedwoodJS provides a robust full-stack framework with GraphQL, services, and deployment options. Combining these technologies simplifies sending transactional SMS notifications from your application backend.
First, install the MessageBird Node.js SDK using yarn workspace api add messagebird
. Then, set your MessageBird Live API Access Key in a .env
file at your project's root, ensuring this file is in .gitignore
. Remember to configure the same environment variable in your hosting provider's settings during deployment.
Use the RedwoodJS CLI command yarn rw g service sms
to generate the necessary files: sms.ts
, sms.scenarios.ts
, and sms.test.ts
. Implement the SMS sending logic within the generated sms.ts
file, utilizing the MessageBird SDK and environment variables.
Use a try-catch block within your RedwoodJS service function and check for errors in the MessageBird SDK callback. Map known MessageBird error codes to RedwoodJS's UserInputError for clearer GraphQL error responses. For unexpected errors, throw a generic Error or a FatalServerError for logging and handling in the client.
GraphQL acts as the API layer in RedwoodJS. Define your sendSms mutation in the SDL (schema definition language) specifying the input parameters and return type. RedwoodJS will automatically map this mutation to your SMS service function. Be sure to protect your mutation with appropriate authorization like @requireAuth.
Use the MessageBird Test API key during initial development to verify integration without sending real SMS or incurring costs. Switch to the Live API key when testing with real phone numbers and in production to send actual messages.
Store your MessageBird API keys securely in environment variables, specifically within a .env
file in your project's root directory during development. Add this file to your .gitignore
to prevent accidental commits. When deploying, set the same environment variable in your hosting provider's settings.
MessageBird automatically splits long messages exceeding the standard SMS limit (160 characters for GSM, 70 for Unicode). The service includes a length warning. Always use E.164 formatting for recipient numbers to ensure international compatibility.
Yes, MessageBird supports sending to multiple recipients (up to 50) in a single API call. Modify your RedwoodJS service to accept an array of recipients for the messagebird.messages.create method. This is more efficient than sending many individual API calls.
Monitor SMS logs, delivery rates, and costs through the MessageBird Dashboard. Leverage RedwoodJS's logging capabilities for monitoring application-side behavior and integrate with error tracking services for monitoring application health.
Refer to the MessageBird API documentation and error codes. Common issues include authentication failures (check API key), invalid recipient or originator formats (check E.164 format), and insufficient balance. Consult RedwoodJS logs and MessageBird's dashboard for detailed error information.
Robust input validation, especially for phone numbers, is essential to prevent errors, ensure deliverability, and avoid unnecessary costs. Use a dedicated library like libphonenumber-js for comprehensive validation.
Use background jobs for non-time-critical SMS messages, such as bulk notifications or scheduled messages, to avoid blocking main web requests. Implement a queue system to manage these jobs and handle retries for transient errors.
Send SMS with MessageBird in RedwoodJS: Complete Integration Guide
Learn how to integrate MessageBird's SMS API into your RedwoodJS application using GraphQL and the service layer. This comprehensive guide walks you through building SMS functionality with proper E.164 phone validation, error handling, and production-ready architecture.
You'll implement a complete SMS service using RedwoodJS's backend architecture—perfect for sending OTP codes, transactional alerts, appointment reminders, and user notifications through MessageBird's reliable delivery platform.
Why RedwoodJS for SMS Integration?
RedwoodJS provides an opinionated full-stack architecture that simplifies SMS integration:
.env
support for secure API key storage and configuration across development, staging, and production environments<!-- DEPTH: Section lacks concrete examples showing RedwoodJS advantages vs. alternatives (Priority: Medium) --> <!-- EXPAND: Could benefit from comparison table of RedwoodJS vs Express/NestJS for SMS integration (Type: Enhancement) -->
Prerequisites
Before you begin this integration, ensure you have the following:
yarn create redwoodjs-app my-app
.<!-- GAP: Missing explanation of MessageBird pricing structure and SMS costs (Type: Critical) --> <!-- GAP: No mention of MessageBird account verification requirements or setup time (Type: Substantive) -->
MessageBird SDK Version Note: This guide uses
messagebird
SDK v4.0.1 (the official Node.js SDK last updated in 2022). While the package is 3+ years old, it remains stable and functional for SMS operations. MessageBird has not deprecated this SDK, and it's still actively used in production environments. However, be aware that maintenance updates are infrequent.<!-- DEPTH: SDK version note lacks migration path if SDK becomes deprecated (Priority: Medium) --> <!-- GAP: Missing alternative SDK options or REST API fallback approach (Type: Substantive) -->
1. Project Setup
Let's start by creating a new RedwoodJS project and installing the necessary dependencies.
Create RedwoodJS Project: Open your terminal and run:
Navigate to Project Directory:
Install MessageBird SDK: Add the official MessageBird Node.js SDK to the API side of your project:
This command specifically installs the package within the
api
workspace, where our backend logic resides.<!-- DEPTH: Installation lacks verification step to confirm SDK installed correctly (Priority: High) --> <!-- GAP: No troubleshooting for common installation issues (yarn workspace errors) (Type: Substantive) -->
Create a
.env
file in the root of your project:Add your MessageBird Live API Access Key to the
.env
file. You can find this key in your MessageBird Dashboard under Developers -> API access.Replace
YOUR_LIVE_ACCESS_KEY
with your actual key.Important: Ensure
.env
is listed in your project's root.gitignore
file (RedwoodJS includes this by default) to prevent accidentally committing your secret key.Test vs. Live Keys: MessageBird provides both Live and Test API keys.
<!-- DEPTH: Test key explanation lacks specific examples of what test API returns (Priority: Medium) --> <!-- GAP: Missing guidance on when to switch from test to live key in development workflow (Type: Substantive) -->
MESSAGEBIRD_ACCESS_KEY
) in your hosting provider's settings.This completes the basic project setup and configuration.
2. Implementing Core SMS Sending Functionality
RedwoodJS uses a service layer (
api/src/services
) for business logic. We'll create ansms
service to handle interactions with the MessageBird API.Generate the SMS Service: Use the RedwoodJS CLI generator:
This creates:
api/src/services/sms/sms.ts
: The service file where our logic will live.api/src/services/sms/sms.scenarios.ts
: For defining seed data for tests.api/src/services/sms/sms.test.ts
: The unit test file.Implement the Sending Logic: Open
api/src/services/sms/sms.ts
and replace its contents with the following:Explanation:
initClient
frommessagebird
and necessary types.logger
for structured logging andUserInputError
for standard GraphQL errors.SendSmsInput
,SmsSendSuccessResponse
) for better type safety and code clarity.process.env.MESSAGEBIRD_ACCESS_KEY
and initialize the client. We now check for the key inside thesendSms
function to provide a better error if it's missing during an actual attempt.sendSms
function accepts an object withoriginator
,recipient
, andbody
.libphonenumber-js
is recommended for production.params
object required bymessagebird.messages.create
. Note thatrecipients
must be an array.messagebird.messages.create
method is asynchronous and uses a callback pattern. We wrap it in aPromise
for cleanerasync/await
syntax.err
exists, we log the detailed error and reject the promise with aUserInputError
, providing a more user-friendly message where possible by inspectingerr.errors
. MessageBird error codes (like2
for auth or21
for bad request) can be used for more specific feedback. Unexpected API response structures are handled with a genericError
.try...catch
handles any unexpected errors during the promise execution or validation.<!-- GAP: Missing comprehensive list of all MessageBird error codes and their meanings (Type: Critical) --> <!-- DEPTH: Error handling lacks examples of retry-worthy vs non-retry-worthy errors (Priority: High) --> <!-- GAP: No discussion of handling rate limit errors (code 429) specifically (Type: Substantive) --> <!-- EXPAND: Could add flowchart showing error handling decision tree (Type: Enhancement) -->
3. Building the API Layer (GraphQL Mutation)
RedwoodJS automatically maps service functions to GraphQL resolvers. We need to define the GraphQL schema (SDL) for our
sendSms
mutation.Generate the SDL: Use the RedwoodJS CLI generator:
This creates
api/src/graphql/sms.sdl.ts
.Define the Mutation Schema: Open
api/src/graphql/sms.sdl.ts
and replace its contents with the following:Explanation:
input SendSmsInput
type mirroring the structure expected by our service function.type SmsSendResponse
for the data returned by the mutation upon successful initiation, including success status, the MessageBird message ID, and the initial status.error: String
field has been removed. GraphQL standard practice is to handle errors through the top-levelerrors
array in the response. RedwoodJS automatically populates this when a service function throws anError
(especiallyUserInputError
). The client should check for the presence of thiserrors
array.sendSms
mutation within theMutation
type. It accepts theSendSmsInput
and returnsSmsSendResponse
on success.@skipAuth
: For simplicity in this guide, we're skipping authentication. In a real application, you MUST protect this mutation using@requireAuth
or similar directives to ensure only authorized users/systems can send SMS.<!-- GAP: Missing explanation of what @skipAuth vs @requireAuth actually does in RedwoodJS (Type: Critical) --> <!-- DEPTH: SDL section lacks examples of implementing role-based permissions (admin only SMS) (Priority: High) --> <!-- GAP: No discussion of GraphQL subscription pattern for real-time delivery status (Type: Enhancement) -->
RedwoodJS automatically connects this SDL definition to the
sendSms
function inapi/src/services/sms/sms.ts
based on naming conventions.4. Integrating with MessageBird (API Keys Recap)
While covered in setup, this section recaps the key aspects of MessageBird API key usage:
Obtain API Key:
Secure Storage & Purpose:
MESSAGEBIRD_ACCESS_KEY
environment variable (in.env
locally) is used by thesms
service (process.env.MESSAGEBIRD_ACCESS_KEY
) to authenticate requests.Environment Handling:
.env
file is used during development (yarn rw dev
).MESSAGEBIRD_ACCESS_KEY
) in your hosting provider's settings (e.g., Vercel, Netlify Environment Variables). Do not commit your.env
file.<!-- DEPTH: API key section lacks guidance on key rotation best practices (Priority: Medium) --> <!-- GAP: Missing explanation of IP whitelisting and other MessageBird security features (Type: Substantive) -->
5. Error Handling, Logging, and Retries
Our service implementation includes basic error handling and logging.
UserInputError
for clearer feedback via GraphQL (returned in theerrors
array).try...catch
and typically throw a genericError
or potentially Redwood'sFatalServerError
.UserInputError
for invalid input or predictable API issues (bad number, auth fail).logger
(import { logger } from 'src/lib/logger'
).logger.info
: Log successful attempts and outcomes, including the MessageBird message ID and status. Include key parameters like recipient/originator for context (avoid logging sensitive body content unless necessary and compliant).logger.error
: Log detailed error objects (err
from MessageBird,error
from catch blocks) to aid debugging. Include context like input parameters where safe.<!-- GAP: Missing concrete code examples for implementing background job queue with RedwoodJS (Type: Substantive) --> <!-- DEPTH: Retry section lacks discussion of idempotency keys and how to implement them (Priority: High) --> <!-- GAP: No guidance on exponential backoff algorithms or libraries (Type: Substantive) -->
6. Database Schema and Data Layer (Optional)
For this basic guide focused purely on sending an SMS, a database schema isn't strictly required. However, in a production application, you would likely want to log SMS sending attempts and their outcomes.
Potential Schema (Example using Prisma):
Implementation:
schema.prisma
.yarn rw prisma migrate dev
to apply changes.sendSms
service function:SmsLog
entry with status 'attempted'.messageBirdId
.errorMessage
.This database logging is omitted from the main code for simplicity but is a recommended practice.
<!-- GAP: Missing complete code example showing database integration in sendSms function (Type: Substantive) --> <!-- DEPTH: Database section lacks discussion of data retention policies and GDPR compliance (Priority: Medium) --> <!-- GAP: No explanation of setting up MessageBird webhooks for delivery reports (Type: Critical) -->
7. Security Features
Protecting your SMS sending functionality is crucial.
@skipAuth
with@requireAuth
(or role-based directives) on thesendSms
mutation inapi/src/graphql/sms.sdl.ts
. This ensures only logged-in/authorized users or systems can trigger the SMS send. Refer to RedwoodJS Authentication documentation.libphonenumber-js
for robust phone number validation and formatting.body
.originator
against allowed values (your purchased numbers or registered alphanumeric IDs)..env
and never committing the file or exposing the key in frontend code.sendSms
mutation. Options:rate-limiter-flexible
with Redis or an in-memory store.sendSms
service (e.g., querySmsLog
timestamps per user/recipient).<!-- GAP: Missing step-by-step guide for implementing libphonenumber-js validation (Type: Critical) --> <!-- DEPTH: Rate limiting section lacks concrete code examples using rate-limiter-flexible (Priority: High) --> <!-- GAP: No discussion of CAPTCHA or human verification to prevent bot abuse (Type: Substantive) --> <!-- GAP: Missing explanation of two-factor authentication for admin SMS operations (Type: Enhancement) -->
8. Handling Special Cases
+14155552671
) as the originator.+
followed by country code and number, no spaces/dashes). Our basic validation hints at this. Use robust validation (e.g.,libphonenumber-js
).<!-- DEPTH: Character encoding section lacks examples of how to detect encoding type before sending (Priority: Medium) --> <!-- GAP: Missing table showing character limits for different languages/scripts (Type: Enhancement) --> <!-- GAP: No code example for implementing opt-out list checking (Type: Substantive) --> <!-- GAP: Missing explanation of TCPA compliance requirements for US businesses (Type: Critical) -->
9. Performance Optimizations
For single transactional SMS, application performance is usually not the bottleneck.
recipients
array. Modify the service if batch sending is needed. Avoid many sequential individual API calls.<!-- GAP: Missing benchmarking data showing typical latency for MessageBird API calls (Type: Substantive) --> <!-- DEPTH: Bulk sending section lacks code example for sending to multiple recipients (Priority: High) --> <!-- GAP: No discussion of connection pooling or keep-alive for HTTP requests (Type: Enhancement) -->
10. Monitoring, Observability, and Analytics
/graphql/health
endpoint or create custom checks.<!-- GAP: Missing specific integration guide for Sentry with RedwoodJS (Type: Substantive) --> <!-- DEPTH: Health checks section lacks example of custom health check implementation (Priority: Medium) --> <!-- GAP: No discussion of alerting thresholds for SMS failures or cost overruns (Type: Substantive) -->
11. Troubleshooting and Caveats
Authentication failed
(Code 2): CheckMESSAGEBIRD_ACCESS_KEY
.recipient is invalid
/originator is invalid
(Code 21): Check E.164 format for recipient; check originator validity (VMN format or registered Alphanumeric ID per country rules).No balance
(Code 9): Add MessageBird credits.Message body is empty
: Ensurebody
is provided.401 Unauthorized
: API key issue.400 Bad Request
: Invalid parameters; check MessageBird error details in logs.sent
) doesn't guarantee final delivery. Use MessageBird webhooks for DLRs (delivered
,failed
).<!-- GAP: Missing table with complete list of MessageBird error codes and resolutions (Type: Critical) --> <!-- DEPTH: DLR caveat lacks explanation of typical delay between 'sent' and 'delivered' status (Priority: Medium) --> <!-- GAP: No discussion of MessageBird's specific rate limit values (requests per second/minute) (Type: Substantive) -->
12. Deployment and CI/CD
MESSAGEBIRD_ACCESS_KEY
with your Live key in your hosting provider's environment variable settings. Ensure it's available to the API service at runtime (and potentially build time).yarn rw deploy vercel
).MESSAGEBIRD_ACCESS_KEY
secret. Include tests (yarn rw test api
).<!-- GAP: Missing complete GitHub Actions workflow example for RedwoodJS deployment (Type: Substantive) --> <!-- DEPTH: Deployment section lacks discussion of staging environment setup (Priority: High) --> <!-- GAP: No explanation of blue-green deployment strategy for zero-downtime updates (Type: Enhancement) --> <!-- GAP: Missing smoke test procedures to verify SMS functionality after deployment (Type: Substantive) -->
13. Verification and Testing
Run
yarn rw dev
.Use the GraphQL playground (
http://localhost:8911/graphql
) to execute thesendSms
mutation:Replace placeholders. Check the GraphQL response (expect data, not errors). Check API logs. Check the phone (if using Live key). Check MessageBird Dashboard Log.
<!-- DEPTH: Testing section lacks explanation of what to look for in MessageBird Dashboard (Priority: Medium) --> <!-- GAP: Missing guidance on testing with international numbers from different countries (Type: Substantive) -->
Automated Testing (Unit/Integration):
api/src/services/sms/sms.test.ts
.<!-- GAP: Missing test cases for MessageBird API error scenarios (auth failure, rate limits) (Type: Critical) --> <!-- DEPTH: Testing section lacks integration test example hitting real test API (Priority: High) --> <!-- GAP: No discussion of test coverage requirements or tools (Istanbul/nyc) (Type: Substantive) -->
How the RedwoodJS SMS Integration Works
Let's break down the key components:
GraphQL SDL (Schema Definition Language)
The GraphQL SDL (Schema Definition Language) defines the structure of our GraphQL API. In this case, we have a
sendSms
mutation that accepts aSendSmsInput
and returns aSmsSendResponse
.<!-- DEPTH: SDL explanation lacks discussion of GraphQL introspection and schema documentation (Priority: Low) -->
Service Implementation
The service implementation in
api/src/services/sms/sms.ts
is where the actual MessageBird API calls are made. It validates input, constructs the request, and handles the response from the MessageBird API.E.164 Phone Number Format
MessageBird requires international phone numbers in E.164 format:
+[country code][subscriber number]
without spaces or special characters.E.164 Format Rules:
+
followed by 1-3 digit country code (e.g.,+1
for USA/Canada,+44
for UK)+
sign+14155552671
(US),+442071234567
(UK),+8613800138000
(China)Our service validates E.164 format using regex:
/^\+[1-9]\d{1,14}$/
to catch malformed numbers before making expensive API calls.<!-- DEPTH: E.164 section lacks discussion of edge cases (Caribbean numbers, special codes) (Priority: Medium) --> <!-- GAP: Missing examples of common formatting mistakes and how to fix them (Type: Substantive) -->
SMS Character Limits and Encoding
Understanding SMS character limits prevents message truncation and unexpected costs:
MessageBird automatically handles message segmentation. If your message exceeds these limits, it will be split into multiple segments, each billed separately. Plan your message content accordingly.
Common Character Limit Scenarios:
<!-- GAP: Missing code example for calculating SMS parts before sending (Type: Substantive) --> <!-- DEPTH: Encoding section lacks explanation of how to force specific encoding (Priority: Low) -->
Deploying Your RedwoodJS SMS Integration to Production
When deploying your SMS integration to production:
Environment Variables
Ensure your MessageBird API key is securely stored in your production environment. Use RedwoodJS's
.env
file for development and configure your hosting provider's environment variables for production.<!-- DEPTH: Environment variables section lacks discussion of secrets management services (AWS Secrets Manager, HashiCorp Vault) (Priority: Medium) -->
Error Handling and Logging
Implement robust error handling and logging to monitor SMS delivery and troubleshoot issues. Use RedwoodJS's
logger
for structured logging and integrate with monitoring tools like Sentry for error tracking.Rate Limiting and Cost Management
SMS providers charge per message sent. Protect your application from abuse and unexpected costs:
express-rate-limit
or implement custom rate limiting in your GraphQL context to restrict SMS sends per user/IPsendSms
mutation using RedwoodJS's@requireAuth
directive to prevent anonymous abuse<!-- GAP: Missing code example for implementing per-user SMS quota tracking (Type: Critical) --> <!-- DEPTH: Cost management lacks specific pricing examples from MessageBird (Priority: Medium) -->
Version Compatibility
<!-- GAP: Missing upgrade guide for migrating from older RedwoodJS versions (Type: Substantive) -->
Troubleshooting MessageBird SMS Integration Issues
"SMS Service is not configured"
Cause: The
MESSAGEBIRD_ACCESS_KEY
environment variable is missing or not loaded.Solution:
.env
containsMESSAGEBIRD_ACCESS_KEY=your_live_or_test_key_here
yarn rw dev
) to reload environment variables.env
is in your project root (same directory asredwood.toml
)"Recipient phone number must be in E.164 format"
Cause: The phone number doesn't match the E.164 format requirements.
Solution:
+
followed by the country code+1 (415) 555-2671
→+14155552671
libphonenumber-js
for automatic formatting and validation"MessageBird authentication failed"
Cause: Invalid or expired API access key.
Solution:
.env
file:MESSAGEBIRD_ACCESS_KEY=sk_live_...
(no quotes needed)"Invalid recipient number or originator format"
Cause: The recipient phone number is invalid for the destination country, or the originator is not properly registered.
Solution:
<!-- GAP: Missing troubleshooting section for webhook delivery issues (Type: Substantive) --> <!-- GAP: No discussion of debugging with MessageBird's test mode vs live mode differences (Type: Medium) -->
Frequently Asked Questions
How do I send SMS messages from a RedwoodJS application?
Install the MessageBird SDK (
yarn workspace api add messagebird
), create a GraphQL SDL schema defining asendSms
mutation, and implement a service inapi/src/services/sms/sms.ts
that calls MessageBird's API. Use RedwoodJS environment variables to store your MessageBird API key securely.What phone number format does MessageBird require?
MessageBird requires E.164 international format:
+[country code][subscriber number]
with no spaces or special characters. Examples:+14155552671
(US),+442071234567
(UK). Validate using the regex pattern/^\+[1-9]\d{1,14}$/
.How do I handle MessageBird API errors in RedwoodJS?
Wrap MessageBird API calls in try-catch blocks or Promise rejection handlers. Map MessageBird error codes (like code 2 for authentication failures, code 21 for invalid numbers) to user-friendly error messages using RedwoodJS's
UserInputError
orForbiddenError
classes.Can I use MessageBird test keys in RedwoodJS development?
Yes. MessageBird provides test API keys (prefix
test_
) that simulate SMS sending without actually delivering messages or charging your account. SetMESSAGEBIRD_ACCESS_KEY=test_...
in your.env
file for development and testing.How do I prevent SMS abuse in my RedwoodJS application?
Implement rate limiting using middleware, require user authentication with RedwoodJS's
@requireAuth
directive, enforce per-user daily SMS caps by tracking sends in your Prisma database, and monitor MessageBird's dashboard for unusual activity.What's the difference between RedwoodJS services and GraphQL resolvers?
RedwoodJS services contain business logic and external API integrations (like MessageBird calls), while GraphQL resolvers are thin layers that call service functions. This separation keeps your code testable and maintainable—services can be reused outside GraphQL contexts.
How do I send SMS to multiple recipients in RedwoodJS?
Modify your GraphQL schema to accept an array of recipients, then loop through them in your service, calling
messagebird.messages.create()
for each. For bulk sending, consider using MessageBird's batch API or implementing a background job queue (like RedwoodJS jobs with Prisma) to avoid GraphQL timeouts.<!-- GAP: FAQ missing question about estimated delivery time for SMS (Type: Medium) --> <!-- GAP: No FAQ about handling international SMS and associated costs (Type: Substantive) -->
Does RedwoodJS support SMS delivery status callbacks from MessageBird?
Yes. Create a webhook endpoint in
api/src/functions/
(serverless function) to receive MessageBird delivery status callbacks. Parse the webhook payload, update your database via Prisma, and optionally trigger frontend notifications through GraphQL subscriptions or polling.<!-- GAP: Missing step-by-step guide for creating webhook endpoint in RedwoodJS (Type: Critical) -->
Next Steps
Now that you have a working SMS integration in RedwoodJS using MessageBird, you can:
<!-- DEPTH: Next steps section lacks specific learning resources or related tutorials (Priority: Low) --> <!-- EXPAND: Could add links to related MessageBird features (voice, WhatsApp) (Type: Enhancement) -->