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:
- RedwoodJS: A full-stack JavaScript/TypeScript framework for building modern web applications. We'll use its API-side functions to handle incoming webhooks.
- Amazon Pinpoint: The AWS service used to acquire and manage phone numbers capable of sending and receiving SMS messages. (Note: Some features related to SMS phone numbers were previously found under ""End User Messaging SMS"" in the AWS console, but are now integrated within the broader Pinpoint service.)
- AWS Simple Notification Service (SNS): A managed messaging service. Pinpoint will publish incoming SMS messages to an SNS topic, which then forwards them to our application.
- AWS Lambda: RedwoodJS API functions typically deploy as serverless functions (like AWS Lambda when using the Serverless Framework deploy target), which will execute our message handling logic.
- AWS IAM: Used to manage permissions between AWS services (Pinpoint -> SNS -> Lambda/API Gateway).
- Prisma: RedwoodJS's default ORM for database interaction (optional, but included for storing messages).
- (Optional) Serverless Framework: Used for deploying the RedwoodJS application to AWS.
System Architecture:
[User's Phone] --(SMS)--> [Amazon Pinpoint Phone Number]
|
'--(Publishes Message)--> [AWS SNS Topic]
|
'--(HTTPS POST Request)--> [RedwoodJS API Function (via API Gateway/Lambda)]
|
'--(Processes Message)--> [RedwoodJS Service Layer]
|
'--(Stores Message)--> [Database (e.g., PostgreSQL via Prisma)]
Prerequisites:
- An AWS account with permissions to manage Pinpoint, SNS, IAM, Lambda, and API Gateway.
- Node.js (LTS version recommended) and Yarn installed.
- A way to run RedwoodJS CLI commands (typically handled locally by creating a project with
yarn create redwood-app ...
, or you can usenpx redwood ...
). - AWS CLI installed and configured with appropriate credentials (
aws configure
). - Basic familiarity with RedwoodJS concepts (API functions, services, Prisma).
- A mobile phone capable of sending SMS messages for testing.
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:
yarn create redwood-app ./redwood-sns-inbound --typescript
-
Navigate to Project Directory:
cd redwood-sns-inbound
-
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.yarn rw prisma migrate dev --name initial-setup
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:
- Log in to your AWS Console.
- Use the search bar to find and navigate to ""Amazon Pinpoint"".
- In the Pinpoint console, navigate to SMS and voice (or similar section for phone number management). Note: If you search for ""End User Messaging SMS"", it might redirect you here.
- Ensure you are in the AWS Region where you want to operate. Two-way SMS availability varies by region and country. Check the SMS and MMS country capabilities and limitations documentation.
-
Request a Phone Number:
- In the navigation pane, under Configurations or Number management, find and click Phone numbers.
- Click Request phone number.
- Select the Country for the number.
- Under Capabilities, ensure SMS is selected.
- Choose the Number type (e.g., Long code, Toll-free). Long codes are often suitable for two-way interaction. Note: Sender IDs do not support two-way SMS.
- Click Next.
- Review the request and click Request. Provisioning might take a few minutes.
-
Enable Two-Way SMS and Configure SNS Destination:
- Once the number is provisioned and listed on the Phone numbers page, click on the number.
- Go to the Two-way SMS tab (or similar configuration section).
- Click Edit settings.
- Check the box Enable two-way message.
- For Destination type, select Amazon SNS.
- For Amazon SNS, select New Amazon SNS topic. AWS will create a topic specifically for this number. This simplifies initial permission setup.
- Alternatively, if you have an existing SNS topic, select Existing Amazon SNS topic and choose it from the dropdown. You will then need to manage IAM roles or SNS topic policies manually (see AWS docs). Using a New topic is recommended for this guide.
- AWS will typically handle the necessary permissions (
Two-way channel role
) automatically when creating a new topic. - Click Save changes.
-
Note Down Key Information:
- Phone Number: The number you acquired (e.g.,
+12065550100
). - SNS Topic ARN: After saving, find the ARN of the newly created or selected SNS topic. You can find this by navigating to the SNS service in the AWS Console, clicking ""Topics"", and finding the topic associated with your number (it might have a name related to Pinpoint or the number). It will look something like:
arn:aws:sns:us-east-1:123456789012:pinpoint-sms-voice-v2-sms-xxxxxxxx
.
- Phone Number: The number you acquired (e.g.,
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:
- HTTPS Endpoint: Our RedwoodJS function will expose an HTTPS URL.
- Subscription Confirmation: When we add the HTTPS subscription later, SNS will send a
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. - Raw Message Delivery: For standard validation using libraries like
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:
yarn rw g function inboundSms --typescript
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.
yarn workspace api add sns-validator
-
Implement the Handler Logic (
api/src/functions/inboundSms.ts
):// api/src/functions/inboundSms.ts import type { APIGatewayEvent, Context } from 'aws-lambda' import { logger } from 'src/lib/logger' import { db } from 'src/lib/db' // If storing messages import MessageValidator from 'sns-validator' import https from 'https' const validator = new MessageValidator() /** * The handler function is invoked by AWS Lambda. * * @param event The Lambda event input * @param context The Lambda context input (Unused) */ export const handler = async (event: APIGatewayEvent, _context: Context) => { logger.info('Inbound SMS function invoked') let requestBody: any // 1. Parse the request body // API Gateway might base64 encode the body try { if (event.isBase64Encoded && event.body) { requestBody = JSON.parse(Buffer.from(event.body, 'base64').toString('utf-8')) } else if (event.body) { requestBody = JSON.parse(event.body) } else { logger.error('Request body is missing or empty') return { statusCode: 400, body: 'Bad Request: Missing body' } } logger.debug({ custom: requestBody }, 'Parsed SNS request body') } catch (error) { logger.error({ error }, 'Failed to parse request body') return { statusCode: 400, body: 'Bad Request: Invalid JSON' } } // 2. Validate the SNS message signature try { const message = await new Promise<any>((resolve, reject) => { // Pass the parsed SNS message (the standard SNS wrapper JSON) to the validator validator.validate(requestBody, (err, message) => { if (err) { logger.error({ error: err }, 'SNS message validation failed') reject(err) } else { logger.info('SNS message signature validated successfully') resolve(message) // message here is the validated SNS message object } }) }) // 3. Handle different SNS message types const messageType = message.Type // Type is part of the SNS wrapper if (messageType === 'SubscriptionConfirmation') { logger.info( `Received SNS SubscriptionConfirmation. Confirming subscription...` ) // Confirm the subscription by visiting the SubscribeURL (part of SNS wrapper) await new Promise<void>((resolve, reject) => { const req = https.get(message.SubscribeURL, (res) => { logger.info( `Subscription confirmation request sent. Status: ${res.statusCode}` ) res.on('data', () => {}) // Consume response data res.on('end', () => resolve()) }) req.on('error', (e) => { logger.error( { error: e }, 'Error confirming SNS subscription' ) reject(e) }) req.end() }) return { statusCode: 200, headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ message: 'SNS Subscription Confirmed' }), } } else if (messageType === 'Notification') { logger.info('Received SNS Notification (SMS Message)') // Because Raw Message Delivery is DISABLED, the actual Pinpoint SMS payload // is JSON stringified within the 'Message' field of the SNS wrapper. const smsPayload = JSON.parse(message.Message) logger.info({ custom: smsPayload }, 'Parsed SMS Payload from SNS Message field') const messageBody = smsPayload.messageBody const originationNumber = smsPayload.originationNumber // User's phone number const destinationNumber = smsPayload.destinationNumber // Your Pinpoint number // --- Your Business Logic Here --- // Example: Store the message in the database try { const storedMessage = await db.inboundMessage.create({ data: { body: messageBody, fromNumber: originationNumber, toNumber: destinationNumber, providerMessageId: smsPayload.messageId, // Optional: Store provider ID from Pinpoint payload // Use the timestamp from the SNS wrapper (when SNS received it) receivedAt: new Date(message.Timestamp), }, }) logger.info( { custom: storedMessage }, 'Successfully stored inbound message' ) } catch (dbError) { logger.error({ error: dbError }, 'Failed to store message in DB') // Decide if this should be a 500 error to potentially trigger SNS retries // return { statusCode: 500, body: 'Internal Server Error: Database operation failed' } } // --- End Business Logic --- // Return 200 OK quickly to SNS to acknowledge receipt return { statusCode: 200, headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ message: 'SMS Received' }), } } else if (messageType === 'UnsubscribeConfirmation') { logger.warn({ custom: message }, 'Received UnsubscribeConfirmation from SNS') // Optional: Handle logic if your endpoint gets unsubscribed return { statusCode: 200, body: 'Unsubscribe Noted' } } else { logger.warn(`Received unknown SNS message type: ${messageType}`) return { statusCode: 400, body: 'Bad Request: Unknown message type' } } } catch (validationError) { logger.error({ error: validationError }, 'SNS Validation Promise Error') // Don't provide detailed error info back to potentially malicious caller return { statusCode: 403, body: 'Forbidden: Invalid signature' } } }
Explanation:
- Parse Body: The request body from SNS (via API Gateway) is parsed from JSON. It handles potential base64 encoding.
- Validate Signature:
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. - Handle Message Type:
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.
- Business Logic: The placeholder shows where you'd add your application-specific logic, like storing the message using the Prisma service (
db
). - Return 200 OK: It's crucial to return a
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.// schema.prisma datasource db { provider = "sqlite" // Or "postgresql" for production url = env("DATABASE_URL") } generator client { provider = "prisma-client-js" } model InboundMessage { id String @id @default(cuid()) body String fromNumber String toNumber String providerMessageId String? // Optional: Store the AWS message ID from Pinpoint payload receivedAt DateTime // Timestamp from SNS when it received the message createdAt DateTime @default(now()) updatedAt DateTime @updatedAt @@index([fromNumber]) @@index([toNumber]) @@index([receivedAt]) }
-
Run Migration: Apply the schema changes to your database and generate the updated Prisma client.
yarn rw prisma migrate dev --name add-inbound-message
-
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.# .env (for local development, DO NOT commit) # DATABASE_URL=""file:./dev.db"" # Or your PostgreSQL URL for local dev # AWS Credentials (only needed if not using ~/.aws/credentials or IAM roles) # AWS_ACCESS_KEY_ID=""YOUR_AWS_ACCESS_KEY_ID"" # AWS_SECRET_ACCESS_KEY=""YOUR_AWS_SECRET_ACCESS_KEY"" AWS_REGION=""us-east-1"" # Replace with your AWS region # SNS Topic ARN for inbound messages SNS_TOPIC_ARN=""arn:aws:sns:us-east-1:123456789012:pinpoint-sms-voice-v2-sms-xxxxxxxx"" # Replace with your ARN
-
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.# .env.production (for production builds/deploys, DO NOT commit) DATABASE_URL=""postgresql://user:password@host:port/database?schema=public"" # Replace with your production DB URL AWS_REGION=""us-east-1"" # Replace with your AWS region SNS_TOPIC_ARN=""arn:aws:sns:us-east-1:123456789012:pinpoint-sms-voice-v2-sms-xxxxxxxx"" # Replace with your ARN # Add any other production-specific env vars
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:
yarn rw setup deploy serverless
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.
yarn rw deploy serverless --first-run
- Follow the prompts. It will deploy the API, detect the API URL, ask to add
API_URL
to.env.production
, and then deploy the web side. Ensure you say Yes to adding theAPI_URL
. - Note the API Function URL: The deployment output (or the AWS API Gateway console) will show the URL for your API functions. The specific URL for the inbound SMS handler will be like:
https://<your-api-gateway-id>.execute-api.<your-region>.amazonaws.com/inboundSms
. Copy this URL.
- Follow the prompts. It will deploy the API, detect the API URL, ask to add
-
Subsequent Deploys: For future updates after code changes:
yarn rw deploy serverless
8. Connecting SNS to the Deployed Function
Now, link the SNS topic to your live RedwoodJS function endpoint.
- Navigate to SNS Topic: Go back to the AWS Console -> SNS -> Topics -> Select the topic associated with your Pinpoint number.
- Create Subscription:
- Under the Subscriptions tab, click Create subscription.
- Topic ARN: Should be pre-filled.
- Protocol: Select HTTPS.
- Endpoint: Paste the API Function URL you copied after deployment (e.g.,
https://<your-api-gateway-id>.execute-api.<your-region>.amazonaws.com/inboundSms
). - Enable raw message delivery: Leave this box unchecked (disabled). This ensures SNS sends the standard wrapper JSON containing validation fields, which our function and the
sns-validator
library expect. - Click Create subscription.
- Confirm Subscription:
- The subscription status will initially be ""Pending confirmation"".
- SNS will immediately send a
SubscriptionConfirmation
POST request to your endpoint. - Your deployed
inboundSms
function should receive this request, log it, extract theSubscribeURL
, and make a GET request to it. - Refresh the SNS Subscriptions page after a few seconds. The status should change to Confirmed.
- Troubleshooting: If it stays pending, check the CloudWatch Logs for your
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.
- Send SMS: Using your mobile phone, send an SMS message (e.g., "Hello Redwood!") to the AWS Pinpoint phone number you acquired.
- Check CloudWatch Logs:
- Navigate to AWS Console -> CloudWatch -> Log groups.
- Find the log group for your Lambda function (usually named something like
/aws/lambda/redwood-sns-inbound-dev-inboundSms
or similar, depending on your stage/service name inserverless.yml
). - Open the latest log stream. You should see logs indicating:
- Function invocation.
- Successful SNS signature validation.
- Receipt of an SNS
Notification
. - The parsed SMS payload (
messageBody
,originationNumber
, etc.) extracted from themessage.Message
field. - Successful database insertion log (if configured).
- A
200 OK
status code being returned.
- Check Database (Optional):
If you stored the message, verify it's in the database.
- Locally (if testing against local DB):
yarn rw prisma studio
- Production: Connect to your production database using a tool like
psql
, pgAdmin, TablePlus, etc., and query theInboundMessage
table.
- Locally (if testing against local DB):
- Send Test Failure: Try sending invalid JSON to your endpoint (using
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:
- Pinpoint number acquired and Two-Way SMS enabled, pointing to the correct SNS Topic.
- SNS Topic exists.
- RedwoodJS
inboundSms
function deployed successfully. - SNS Subscription created with HTTPS protocol, correct endpoint URL, and "Raw message delivery" disabled.
- SNS Subscription status is "Confirmed".
- Sending an SMS to the Pinpoint number triggers the
inboundSms
Lambda function (check CloudWatch). - Lambda function successfully validates the SNS signature (check CloudWatch).
- Lambda function correctly parses the SMS message content from the nested
Message
field (check CloudWatch). - Lambda function returns a
200 OK
status code (check CloudWatch). - (Optional) Message details are correctly stored in the database.
10. Error Handling & Logging
- Current Implementation: The provided function includes basic
try...catch
blocks and uses Redwood'slogger
(logger.info
,logger.error
,logger.debug
). Errors during parsing, validation, or database operations are caught and logged. - CloudWatch: AWS Lambda automatically integrates with CloudWatch Logs. This is your primary tool for debugging function execution. Configure CloudWatch Alarms based on error logs or metrics (e.g.,
Errors
,Throttles
,Duration
) for proactive monitoring. - SNS Delivery Status: Configure delivery status logging in SNS to log to CloudWatch Logs. This helps diagnose if SNS is having trouble delivering messages to your endpoint before they even reach your function (e.g., endpoint down, HTTPS errors, non-200 responses). You can set this up in the SNS Topic's properties under ""Delivery status logging"".
- SNS Retries: SNS has built-in retry policies for HTTPS endpoints if it doesn't receive a
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. - Dead-Letter Queues (DLQs): Configure a Dead-Letter Queue (an SQS queue) on the SNS subscription. If SNS fails to deliver the message to your endpoint after all retries, it can send the failed message to the DLQ for later inspection and manual reprocessing. This prevents message loss. You can configure this in the SNS Subscription's ""Redrive policy (dead-letter queue)"" settings.
11. Security Considerations
- SNS Signature Validation: Absolutely critical. The
sns-validator
library handles this. Never disable this check. It prevents attackers from spoofing requests to your endpoint. - HTTPS: Always use HTTPS for your SNS subscription endpoint. API Gateway and Lambda provide this by default.
- Input Sanitization: While the immediate input is from AWS, if you further process the
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. - Least Privilege: Ensure the IAM role used by your Lambda function has only the necessary permissions (e.g., CloudWatch Logs access, database access if needed). The Serverless Framework typically creates a role with basic execution permissions. You may need to attach policies for database access or other AWS services.
- Rate Limiting: While less common for direct SNS pushes (as SNS controls the push rate), if you expose this functionality differently or anticipate very high volume, consider implementing rate limiting at the API Gateway level.
- Environment Variables: Never expose AWS keys or database credentials in your frontend code or commit them to Git. Use
.env
and secure environment variable management in your deployment environment.
12. Troubleshooting and Caveats
-
Messages Not Arriving:
- Check Pinpoint: Is the number correctly configured for two-way SMS? Is the destination the correct SNS Topic ARN?
- Check SNS Topic: Does it exist? Are there any access policy restrictions?
- Check SNS Subscription: Is it Confirmed? Is the Endpoint URL exactly correct? Is Raw Message Delivery correctly disabled?
- Check CloudWatch Logs (Lambda): Is the function even being invoked? Are there errors immediately upon invocation (e.g.,
module not found
, IAM permission errors, JSON parsing errors)? - Check CloudWatch Logs (SNS Delivery Status): If configured, do these show delivery failures to your endpoint (e.g.,
4xx
or5xx
HTTP errors)? - API Gateway Logs: Enable execution logging in API Gateway for more detailed request/response info.
- Region Mismatch: Ensure Pinpoint number, SNS topic, and Lambda function are in the same or compatible AWS regions.
-
SNS Signature Validation Fails:
- Clock Skew: Ensure the server running your Lambda function has reasonably accurate time. While this is a possible cause for signature validation issues, it's unlikely on standard AWS Lambda as AWS manages the time synchronization.
- Incorrect Parsing/Handling: Ensure you are passing the raw, unmodified JSON object received from SNS (after potential base64 decoding) directly to the
validator.validate
function. Double-check that raw message delivery is indeed disabled in the SNS subscription. - Library Issues: Ensure
sns-validator
is installed correctly in theapi
workspace and deployed with your function.
-
Subscription Stuck in ""Pending Confirmation"":
- Function Error: The function failed to process the
SubscriptionConfirmation
request (check logs for errors). Verify the code correctly identifies theSubscriptionConfirmation
type and makes the GET request to theSubscribeURL
. - Network/Firewall: Ensure AWS SNS can reach your HTTPS endpoint (usually not an issue with standard Lambda/API Gateway setups).
- Timeout: The function took too long to respond or make the GET request to the
SubscribeURL
. Lambda functions have execution time limits. - Manual Confirmation: As a last resort, copy the
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.
- Function Error: The function failed to process the
-
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:
- Send Outbound SMS: Use the AWS SDK for JavaScript v3 (
@aws-sdk/client-pinpoint
) within a RedwoodJS service or function to send replies or initiate outbound messages via Pinpoint. - Build a UI: Create RedwoodJS pages/cells to display received messages or provide an interface for sending replies.