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
This guide provides a step-by-step walkthrough for integrating Vonage SMS functionality into your RedwoodJS application. You'll learn how to send outbound SMS messages (ideal for notifications or marketing campaigns) and receive inbound SMS messages via webhooks, leveraging the power of RedwoodJS's full-stack architecture and the Vonage Messages API.
By the end of this guide, you will have a RedwoodJS application capable of:
This setup solves the common need for applications to communicate with users via SMS for alerts, verification, or engagement, providing a robust and scalable solution.
Prerequisites:
node -v
). We recommend using nvm to manage Node versions.yarn -v
).Project Overview and Goals
We will build a RedwoodJS application with basic SMS functionality:
Technologies:
@vonage/server-sdk
: The official Vonage Node.js SDK for interacting with the API.System Architecture:
1. Setting up the Project
Let's 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. We'll use TypeScript (default) and initialize a git repository.
1.2 Environment Variables Setup:
Securely storing API keys and sensitive information is crucial. RedwoodJS uses
.env
files for this.Create a
.env
file in the root of your project:Add the following environment variables to your
.env
file. We'll get these values in the next steps.Important: Add
.env
andprivate.key
to your.gitignore
file to prevent committing secrets. The default RedwoodJS.gitignore
should already include.env
, but double-check and addprivate.key
.1.3 Vonage Account Setup:
.env
file.14155551212
) intoVONAGE_VIRTUAL_NUMBER
in your.env
file.@vonage/server-sdk
features correctly. Save the changes.1.4 Create Vonage Application:
Vonage Applications group your numbers and configurations.
private.key
file that downloads. Save it in the root of your RedwoodJS project (or updateVONAGE_PRIVATE_KEY_PATH
in.env
if you save it elsewhere, or useVONAGE_PRIVATE_KEY_CONTENT
).https://example.com/webhooks/inbound
andhttps://example.com/webhooks/status
). We will update these later with our ngrok URL during development.https://example.com/webhooks/inbound
https://example.com/webhooks/status
VONAGE_APPLICATION_ID
in your.env
file.1.5 Install Vonage SDK:
Install the Vonage Node.js SDK specifically in the
api
workspace.2. Implementing Core Functionality (Sending SMS)
We'll create a RedwoodJS service to handle sending SMS messages via Vonage.
2.1 Create SMS Service:
Use the RedwoodJS CLI to generate the service files.
This creates
api/src/services/sms/sms.ts
and related test/scenario files.2.2 Configure Vonage Client:
It's good practice to initialize the Vonage client centrally. We can create a utility file for this.
Create
api/src/lib/vonage.ts
:VONAGE_PRIVATE_KEY_CONTENT
if available, falling back to the path specified inVONAGE_PRIVATE_KEY_PATH
. Redwood's logger provides structured logging.2.3 Implement
sendSms
Function:Now, edit the generated service file (
api/src/services/sms/sms.ts
) to add the sending logic.send
method, and handles potential errors usingtry...catch
. It returns a structured response indicating success or failure. Logging provides visibility into the process.3. Building the API Layer (GraphQL Mutation)
RedwoodJS uses GraphQL for its API. Let's define a mutation to expose our
sendSms
service function.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 the available mutations.sendSms
takesto
andtext
as non-nullable String arguments and returns anSmsResponse
.@skipAuth
: For development only. This disables authentication. In a real application, you would replace this with@requireAuth
to ensure only logged-in users can trigger the mutation, implementing RedwoodJS Authentication.3.2 Test the Mutation:
Start the development server:
Open your browser to the RedwoodJS GraphQL Playground:
http://localhost:8911/graphql
.In the left panel, enter the following mutation (replace
`YOUR_REAL_PHONE_NUMBER`
with 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 theerror
message and review the terminal output whereyarn rw dev
is 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/read correctly.3.3
curl
Example:You can also test the GraphQL endpoint using
curl
:Replace
`YOUR_REAL_PHONE_NUMBER`
accordingly.4. Integrating Third-Party Services (Receiving SMS via Webhooks)
To receive incoming SMS messages, Vonage needs to send data to a URL in our application (a webhook).
4.1 Expose Localhost with ngrok:
Since your RedwoodJS app is running locally, Vonage can't reach it directly. We use
ngrok
to create a secure tunnel.If
yarn rw dev
is running, stop it (Ctrl+C).Start
ngrok
to forward to Redwood's API port (usually 8911):ngrok
will display a public ""Forwarding"" URL (e.g.,https://<unique-id>.ngrok-free.app
). Copy the HTTPS version of this URL.4.2 Update Vonage Application Webhook URLs:
YOUR_NGROK_HTTPS_URL/webhooks/inbound
YOUR_NGROK_HTTPS_URL/webhooks/status
YOUR_NGROK_HTTPS_URL
with the URL you copied from ngrok).POST
.4.3 Create RedwoodJS Webhook Handler:
RedwoodJS functions are perfect for webhooks. Generate a function:
This creates
api/src/functions/vonageWebhook.ts
.4.4 Implement Webhook Logic:
Modify
api/src/functions/vonageWebhook.ts
to handle incoming messages and status updates. This version includes logic to handle both JSON and form-urlencoded payloads.parseRequestBody
helper to handle bothapplication/json
andapplication/x-www-form-urlencoded
content types, making it more robust. It uses theevent.path
to determine if it's an inbound message or a status update. It parses the payload, logs relevant information, and importantly, returns a200 OK
status code promptly to acknowledge receipt to Vonage. Error handling ensures issues are logged without causing Vonage to endlessly retry (unless a 500 is returned).4.5 Test Receiving SMS:
ngrok
is running and pointing to port 8911.yarn rw dev
.yarn rw dev
. You should see log entries fromapi/src/functions/vonageWebhook.ts
indicating an ""inbound SMS"" was received, along with details like the sender number (msisdn
) and the message text. Check for any parsing warnings or errors.http://127.0.0.1:4040
), including theContent-Type
header sent by Vonage.5. Implementing Error Handling, Logging, and Retry Mechanisms
try...catch
blocks in the service (sendSms
) and the webhook handler. InsendSms
, we catch errors from the Vonage SDK and return a{ success: false, error: '...' }
object. In the webhook, we catch errors during processing but still try to return200 OK
to Vonage, logging the error internally. The webhook now also handles potential body parsing errors. More specific error types could be handled (e.g., distinguishing network errors from API errors from Vonage).src/lib/logger
) is used. We log key events: attempts to send, success/failure of sending, reception of webhooks, specific details from payloads, and errors.logger.info
,logger.warn
,logger.error
, andlogger.debug
are used appropriately. For production, configure log levels and destinations (e.g., sending logs to a service like Datadog or Logflare).sendSms
doesn't implement retries. For critical messages, you could wrap thevonage.messages.send
call in a retry loop with exponential backoff (using libraries likeasync-retry
orp-retry
) for transient network errors or temporary Vonage API issues.200 OK
status within a reasonable time (a few seconds). Our handler is designed to return 200 quickly, even if background processing fails, to prevent unnecessary Vonage retries.Example: Testing Error Scenario (Send SMS)
Modify the
sendSms
service temporarily to force an error, e.g., provide an invalidto
number format known to cause Vonage API errors, or temporarily change the API key in.env
to something invalid. Then trigger thesendSms
mutation and observe the logged error and the{ success: false, ... }
response.6. Creating a Database Schema and Data Layer
Let's log sent and received messages to the database using Prisma.
6.1 Define Prisma Schema:
Edit
api/db/schema.prisma
. Add aSmsLog
model.vonageId
is unique to prevent duplicate entries from retried webhooks (though upsert logic is better) and uses a 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
sendSms
service and thevonageWebhook
function to interact with the database. You might need to add thecuid
package:yarn workspace api add cuid
.api/src/services/sms/sms.ts
(sendSms):api/src/functions/vonageWebhook.ts
(handler):Why: The
sendSms
service now logs the attempt to theSmsLog
table, recording whether it was initially submitted or failed. ThevonageWebhook
handler logs incoming messages (INBOUND
) and updates the status of existing outbound messages based on status webhooks (OUTBOUND
). It usesupsert
orupdate
logic (hereupdate
for status,create
for inbound with duplicate check) to handle message states correctly, including potential retries from Vonage for inbound messages. Error handling for database operations is included.