Frequently Asked Questions
You can receive SMS messages in your RedwoodJS application by integrating with Amazon Pinpoint and AWS SNS. Pinpoint provides the phone number, and SNS forwards incoming messages to your RedwoodJS API function as HTTPS POST requests. This allows two-way SMS communication within your application.
Amazon Pinpoint is used to acquire and manage the phone number that can send and receive SMS messages. It integrates with SNS to forward incoming messages to your RedwoodJS application, enabling two-way SMS communication.
AWS SNS is used with Amazon Pinpoint because Pinpoint publishes incoming SMS messages to an SNS topic. The SNS topic then acts as a distribution hub, securely forwarding the message to your RedwoodJS application via an HTTPS POST request to your designated API function.
You should *disable* Raw Message Delivery in your SNS subscription settings. When disabled, you receive the standard SNS message wrapper, which includes important metadata and security information needed for validation with the `sns-validator` library. Enabling it sends only the Pinpoint payload, breaking compatibility with standard validation methods.
Yes, you can store received SMS messages in a database. The provided code example demonstrates how to use Prisma, RedwoodJS's ORM, to define a database schema, create a migration, and store message details like body, sender/receiver numbers, and timestamps in a database like PostgreSQL or SQLite.
Two-way SMS is enabled within the Amazon Pinpoint console. After acquiring a phone number, navigate to its settings, go to the Two-Way SMS tab, enable two-way messaging, and select a new or existing SNS topic as the message destination. This configures Pinpoint to forward incoming messages to SNS, which then forwards to your application.
RedwoodJS API functions, including the SMS webhook handler, typically deploy as AWS Lambda functions when using the Serverless Framework. Lambda executes the function code in a serverless environment whenever a message is received from SNS, triggering the message processing logic.
Use the `sns-validator` library. It verifies the digital signature attached to incoming SNS messages, ensuring they originated from AWS and haven't been tampered with. The code provides an example of how to validate within your RedwoodJS function handler before processing the message content.
When you first subscribe your RedwoodJS endpoint to the SNS topic, SNS sends a 'SubscriptionConfirmation' message. Your function must handle this by extracting the 'SubscribeURL' from the message and making an HTTPS GET request to that URL. This confirms to SNS that your endpoint is valid and ready to receive notifications.
If messages aren't arriving, check your Pinpoint and SNS configurations in the AWS Console. Ensure the Pinpoint number is properly configured for two-way SMS, and that the SNS topic exists. Double-check that the subscription status is 'Confirmed', the endpoint URL is absolutely correct, and 'Raw Message Delivery' is *disabled*. Verify the subscription is connected to the intended RedwoodJS endpoint and look for any errors by checking your function's CloudWatch logs.
SNS signature validation failures are often due to incorrect handling of the incoming JSON, attempting to validate only the Pinpoint payload, or having accidentally enabled raw message delivery on the SNS subscription. Ensure you're passing the full SNS message object to the `sns-validator`, the message hasn't been modified, and raw message delivery is disabled. In rare cases, clock skew on the server running your function could also be a factor.
A pending SNS subscription confirmation usually means your RedwoodJS function failed to process the initial 'SubscriptionConfirmation' message from SNS. Check your function's CloudWatch logs for errors. Verify your function can reach the 'SubscribeURL', and that the function is correctly configured to handle this specific message type (by making the confirmation GET request).
Logs for your RedwoodJS SNS integration are primarily found in AWS CloudWatch. Look for the log group associated with your deployed Lambda function. API Gateway logs can also provide valuable information on the incoming request and the response your function returns.
Crucially, always validate the SNS message signature using a library like `sns-validator`. Never disable this. Always use HTTPS. Sanitize any user-provided data within the message body. Follow the principle of least privilege by granting your Lambda function only the necessary IAM permissions. Consider rate limiting at the API Gateway level if you anticipate high volumes or different exposure methods, and never commit AWS keys or database credentials to version control.
This guide provides a complete walkthrough for setting up and handling inbound SMS messages within your RedwoodJS application using Amazon Pinpoint and AWS Simple Notification Service (SNS). By following these steps, you can enable two-way communication, allowing your application to receive and process SMS messages sent by users to your designated AWS phone number.
Project Goal: To build a system where a RedwoodJS application can reliably receive SMS messages sent to an AWS-provisioned phone number, process them, and optionally store them in a database.
Problem Solved: Enables applications to react to user-initiated SMS, opening possibilities for interactive SMS bots, customer support via text, notification responses, data collection, and more, without needing to poll an external service.
Technologies Used:
System Architecture:
Prerequisites:
yarn create redwood-app ...
, or you can usenpx redwood ...
).aws configure
).Final Outcome: A deployed RedwoodJS application with an API endpoint that securely receives SMS messages forwarded by AWS SNS, verifies their authenticity, parses the content, and stores them in a database.
1. Setting up the RedwoodJS Project
First, create a new RedwoodJS application.
Create Redwood App: Open your terminal and run:
Navigate to Project Directory:
Initialize Database (Optional but Recommended): If you plan to store messages, set up Prisma and your database. This example uses SQLite for simplicity during development, but you should configure PostgreSQL or another production database for deployment. The default
schema.prisma
includes a SQLite provider.This command creates the initial database file and generates the Prisma client.
This establishes the basic RedwoodJS project structure. We'll add specific files and configurations as needed.
2. AWS Setup: Acquiring a Phone Number & Enabling Two-Way SMS
You need a dedicated phone number within AWS that supports two-way SMS. This is managed through Amazon Pinpoint.
Navigate to Amazon Pinpoint:
Request a Phone Number:
Enable Two-Way SMS and Configure SNS Destination:
Two-way channel role
) automatically when creating a new topic.Note Down Key Information:
+12065550100
).arn:aws:sns:us-east-1:123456789012:pinpoint-sms-voice-v2-sms-xxxxxxxx
.You now have a phone number configured to send incoming SMS messages to an SNS topic.
3. AWS Setup: Preparing SNS for HTTPS Subscription
While Pinpoint configures the SNS topic to receive messages, we need to configure the subscription later to send these messages to our RedwoodJS HTTPS endpoint. We don't create the subscription yet (as our endpoint isn't deployed), but keep these points in mind:
SubscriptionConfirmation
POST request to our endpoint. Our code must handle this request by retrieving theSubscribeURL
from the request body and making a GET request to that URL.sns-validator
, you should disable "Raw message delivery" when creating the subscription later. When disabled (the default), SNS wraps the original Pinpoint message payload within its own standard JSON structure, which includes the necessary fields (SigningCertURL
,Signature
, etc.) for the validator library to work correctly. If raw delivery were enabled, SNS would send only the Pinpoint payload directly in the HTTP request body, skipping the SNS wrapper and breaking standard validation methods.4. Implementing the RedwoodJS Webhook Handler
Now, let's create the RedwoodJS API function that will receive notifications from SNS.
Generate the API Function:
This creates
api/src/functions/inboundSms.ts
.Install SNS Message Validator: We need a library to securely verify that incoming requests genuinely originate from AWS SNS.
Implement the Handler Logic (
api/src/functions/inboundSms.ts
):Explanation:
sns-validator
is used. It takes the parsed JSON object (the SNS wrapper). It fetches the AWS public certificate based on theSigningCertURL
found within the SNS message body JSON and verifies theSignature
against the canonical representation of the message. This is critical for security to ensure the request came from AWS SNS and hasn't been tampered with.SubscriptionConfirmation
: When you first link SNS to this endpoint, it sends this type. The code extracts theSubscribeURL
from the SNS message body and makes an HTTPS GET request to it, confirming to SNS that your endpoint is valid and ready.Notification
: This is the actual SMS message notification. Because Raw Message Delivery is disabled, the code parses theMessage
field within the SNS JSON (which itself contains a JSON string representing the Pinpoint payload) to get details likemessageBody
,originationNumber
, anddestinationNumber
. Themessage.Timestamp
from the SNS wrapper indicates when SNS received the message.UnsubscribeConfirmation
: Handles cases where the subscription might be removed.db
).200 OK
status code quickly, especially forNotification
types, to signal to SNS that the message was received successfully. Failure to do so might cause SNS to retry delivery.5. Database Integration (Optional)
If you want to store the incoming messages:
Define Prisma Schema (
schema.prisma
): Add a model to store the message details.Run Migration: Apply the schema changes to your database and generate the updated Prisma client.
Create Prisma Service (Implicit): Redwood's
db
object imported in the function (import { db } from 'src/lib/db'
) allows direct interaction with theInboundMessage
model, effectively acting as the service layer for this simple case. The function code already includes thedb.inboundMessage.create()
call. For more complex logic, you could generate a dedicated service:yarn rw g service inboundMessage
.6. Securely Handling Configuration
Store sensitive information and environment-specific settings using environment variables.
Update
.env
: Add the AWS credentials and region (if not already configured globally via AWS CLI profiles) and the SNS Topic ARN you noted earlier.Update
.env.production
: When deploying, you'll need a separate.env.production
file (which is not committed to Git) or configure environment variables directly in your hosting environment (e.g., Serverless Dashboard parameters, AWS Lambda environment variables). EnsureSNS_TOPIC_ARN
and the productionDATABASE_URL
are set there.Security Note: Never commit files containing secrets (
.env
,.env.production
) to your version control system. Redwood's default.gitignore
should already include these.7. Deployment
Deploy your RedwoodJS application so the
inboundSms
function has a live HTTPS endpoint. This guide uses the Serverless Framework integration.Setup Serverless Deploy:
This adds necessary configuration files (
serverless.yml
inapi
andweb
) and dependencies.Configure Environment Variables for Deployment: If using Serverless Framework Dashboard for CI/CD or managing secrets, you might need to update
api/serverless.yml
to reference variables stored there (e.g., using${param:VAR_NAME}
). For manual deploys from your machine, ensure.env.production
has the required variables (DATABASE_URL
,SNS_TOPIC_ARN
,AWS_REGION
).First Deploy: The first deploy sets up the infrastructure, including the API Gateway endpoint for your function.
API_URL
to.env.production
, and then deploy the web side. Ensure you say Yes to adding theAPI_URL
.https://<your-api-gateway-id>.execute-api.<your-region>.amazonaws.com/inboundSms
. Copy this URL.Subsequent Deploys: For future updates after code changes:
8. Connecting SNS to the Deployed Function
Now, link the SNS topic to your live RedwoodJS function endpoint.
https://<your-api-gateway-id>.execute-api.<your-region>.amazonaws.com/inboundSms
).sns-validator
library expect.SubscriptionConfirmation
POST request to your endpoint.inboundSms
function should receive this request, log it, extract theSubscribeURL
, and make a GET request to it.inboundSms
Lambda function. Look for theSubscriptionConfirmation
message and any errors during the confirmation process. Ensure the function logic correctly handles this message type and successfully makes the GET request to theSubscribeURL
. You might need to manually copy theSubscribeURL
from the logs and paste it into your browser to confirm if the function failed.9. Verification and Testing
Time to test the end-to-end flow.
/aws/lambda/redwood-sns-inbound-dev-inboundSms
or similar, depending on your stage/service name inserverless.yml
).Notification
.messageBody
,originationNumber
, etc.) extracted from themessage.Message
field.200 OK
status code being returned.yarn rw prisma studio
psql
, pgAdmin, TablePlus, etc., and query theInboundMessage
table.curl
or Postman) to ensure error handling works. Test sending a request without a valid SNS signature (if possible, though harder to spoof) to verify the validator rejects it (it should return 403 Forbidden).Verification Checklist:
inboundSms
function deployed successfully.inboundSms
Lambda function (check CloudWatch).Message
field (check CloudWatch).200 OK
status code (check CloudWatch).10. Error Handling & Logging
try...catch
blocks and uses Redwood'slogger
(logger.info
,logger.error
,logger.debug
). Errors during parsing, validation, or database operations are caught and logged.Errors
,Throttles
,Duration
) for proactive monitoring.200 OK
response. Be mindful that your function might be invoked multiple times for the same message if processing fails or times out. Design your logic to be idempotent (safe to run multiple times with the same input) if necessary, perhaps by checking if a message with the sameproviderMessageId
already exists in your database before inserting.11. Security Considerations
sns-validator
library handles this. Never disable this check. It prevents attackers from spoofing requests to your endpoint.messageBody
(e.g., display it in a web UI, use it in commands), sanitize it appropriately to prevent cross-site scripting (XSS) or other injection attacks..env
and secure environment variable management in your deployment environment.12. Troubleshooting and Caveats
Messages Not Arriving:
module not found
, IAM permission errors, JSON parsing errors)?4xx
or5xx
HTTP errors)?SNS Signature Validation Fails:
validator.validate
function. Double-check that raw message delivery is indeed disabled in the SNS subscription.sns-validator
is installed correctly in theapi
workspace and deployed with your function.Subscription Stuck in ""Pending Confirmation"":
SubscriptionConfirmation
request (check logs for errors). Verify the code correctly identifies theSubscriptionConfirmation
type and makes the GET request to theSubscribeURL
.SubscribeURL
. Lambda functions have execution time limits.SubscribeURL
from the CloudWatch logs (it should be logged when theSubscriptionConfirmation
message is received) and paste it into a browser to manually confirm the subscription.AWS Service Limits: Be aware of potential limits for SNS message throughput, Lambda concurrent executions, etc., though standard SMS volumes are usually well within limits.
Pinpoint Number Capabilities: Not all number types or regions support two-way SMS. Verify compatibility.
Message Encoding: SMS messages might contain non-standard characters. Ensure your database and processing logic handle UTF-8 correctly. The Pinpoint payload usually indicates the encoding.
Delays: SMS delivery is not always instantaneous. Expect potential minor delays through the Pinpoint -> SNS -> Lambda chain.
13. Conclusion & Next Steps
You have successfully configured your RedwoodJS application to receive and process inbound SMS messages using Amazon Pinpoint and SNS. This setup provides a robust and scalable way to handle two-way SMS communication.
Next Steps & Enhancements:
@aws-sdk/client-pinpoint
) within a RedwoodJS service or function to send replies or initiate outbound messages via Pinpoint.