Frequently Asked Questions
Use the MessageBird SMS API integrated with a Next.js API route. Create a server-side function that calls the MessageBird API to send messages, triggered by a user action like submitting a form in your Next.js application. This enables dynamic SMS functionality within your app.
MessageBird provides the SMS sending and receiving capability. Its API and SDK are used to programmatically send SMS messages, receive incoming messages via webhooks, and manage subscribers, enabling the core functionality of an SMS-based application within the Next.js framework.
Prisma acts as a type-safe ORM for database access. It simplifies interactions with databases like PostgreSQL, MySQL, or SQLite, ensuring data consistency, and facilitates database operations like creating, reading, updating, and deleting subscriber information.
Set up a MessageBird webhook after obtaining a virtual mobile number and exposing your local development server. This lets MessageBird send incoming SMS messages (like SUBSCRIBE or STOP commands) to your application for processing, enabling user interactions.
Yes, localtunnel creates a public URL for your local development server. This allows MessageBird to deliver webhooks to your machine even during development when your app is not publicly deployed, essential for testing interactions with the MessageBird API.
Users text keywords (e.g., SUBSCRIBE/STOP) to a MessageBird virtual mobile number. Your Next.js webhook receives these messages, updates the database based on the keywords, and sends confirmation SMS using the MessageBird API.
The `MESSAGEBIRD_API_KEY` authenticates your application with the MessageBird service. Keep this key secure and store it in a `.env` file (never commit to version control) to protect your account and prevent unauthorized API usage.
The Next.js App Router provides a streamlined approach to creating API routes and server components, simplifying the handling of server-side logic like interacting with the MessageBird API and managing webhooks.
The admin interface allows inputting a message, which a server-side function then sends to all active subscribers via the MessageBird API, sending in batches of up to 50 recipients per API request as specified by MessageBird.
The example uses PostgreSQL, but Prisma supports other providers like MySQL and SQLite. You'll need to configure the `DATABASE_URL` in your `.env` file accordingly for Prisma to connect and manage subscriber information.
Adding authentication is crucial *before* deploying to production. The admin panel and send API route are currently unsecured; implement proper authentication to prevent unauthorized access and protect against malicious use.
Use a tool like `localtunnel` or `ngrok` to expose your local development server. Then, configure the MessageBird Flow Builder to send webhooks to your public `localtunnel` URL to test incoming messages and subscription logic during development.
Users might send SUBSCRIBE or Stop. Converting to uppercase (`toUpperCase()`) ensures the application handles variations consistently, avoiding issues with case mismatches and providing a better user experience.
The MessageBird API allows sending to up to 50 recipients per request. The provided code implements batching to handle larger subscriber lists and ensures compliance with MessageBird's API limitations.
The `@unique` constraint on the `phoneNumber` field in the Prisma schema prevents database-level duplicates. The application logic also gracefully handles re-subscribe or re-opt-out attempts, providing clear feedback to the user.
Developer Guide: Building an SMS Marketing Campaign App with Next.js and MessageBird
This guide provides a step-by-step walkthrough for building the core components of an SMS marketing campaign application using Next.js and the MessageBird SMS API. You'll learn how to handle SMS subscriptions (opt-in/opt-out) via keywords and enable an administrator to broadcast messages to subscribers. While this guide covers the fundamental logic, critical features like robust authentication (discussed in Section 7) must be implemented for a truly production-ready deployment.
Project Goal: Create a web application where:
SUBSCRIBE
to a dedicated virtual mobile number (VMN) to opt into receiving SMS marketing messages.STOP
to the same VMN to opt out.Target Audience: Developers familiar with JavaScript, Node.js, and Next.js basics, looking to integrate SMS functionality into their applications using MessageBird.
Technologies Used:
System Architecture:
Prerequisites:
Final Outcome: A functional Next.js application capable of managing SMS subscriptions and broadcasting messages via MessageBird, forming a strong base for a production system once security and other considerations are fully implemented.
1. Setting up the Project
This section covers initializing the Next.js project, installing dependencies, setting up the database connection with Prisma, and configuring environment variables.
1.1 Initialize Next.js Project:
Open your terminal and run the following command to create a new Next.js application. Use the App Router when prompted (recommended for this guide).
1.2 Install Dependencies:
Install the necessary libraries: MessageBird SDK and Prisma Client.
@messagebird/api
: The official MessageBird Node.js SDK.prisma
: The Prisma CLI (dev dependency) and Prisma Client.Note: Next.js automatically loads variables from
.env
files, so explicit use of thedotenv
package is often unnecessary within the Next.js application code itself.1.3 Set up Prisma:
Initialize Prisma in your project. This creates a
prisma
directory with aschema.prisma
file and updates your.gitignore
. It also prompts for creating a.env
file if one doesn't exist.(Note: If you prefer SQLite or MySQL, replace
postgresql
accordingly).1.4 Configure Database Connection:
Open the
.env
file (create it if it doesn't exist). Add yourDATABASE_URL
variable..env
file would look like this:1.5 Define Prisma Schema:
Open
prisma/schema.prisma
and define the model for storing subscriber information.phoneNumber
: Stores the subscriber's phone number (ensure uniqueness). Storing in E.164 format is recommended for consistency.subscribed
: A boolean flag indicating the current subscription status. An index is added for efficient querying.createdAt
,updatedAt
: Timestamps managed automatically by Prisma.1.6 Apply Database Migrations:
Run the Prisma migrate command to create the
Subscriber
table in your database based on the schema. Prisma will prompt you to create a name for the migration (e.g.,init
).This command:
prisma/migrations
.Subscriber
table and indexes.Your basic project structure and database setup are now complete.
2. Implementing Core Functionality: Receiving SMS
This section focuses on handling incoming SMS messages (SUBSCRIBE/STOP) via a Next.js API route acting as a webhook for MessageBird.
2.1 Create Prisma Client Utility:
To avoid creating multiple Prisma Client instances (which is inefficient), set up a singleton instance.
Create
lib/prisma.ts
:2.2 Create MessageBird Client Utility:
Similarly, initialize the MessageBird client once.
Create
lib/messagebird.ts
:Make sure to add
MESSAGEBIRD_API_KEY
to your.env
file later (see Section 4).2.3 Create the Webhook API Route:
This API route will receive POST requests from MessageBird whenever an SMS is sent to your virtual number.
Create
app/api/messagebird/webhook/route.ts
(using App Router structure):Explanation:
NextRequest
,NextResponse
,prisma
,messagebird
, and types.async
function to handle POST requests.originator
,payload
).originatorFormatted
) is consistently formatted (e.g., E.164+1xxxxxxxxxx
) for database storage. Adjust based on observed MessageBird format if needed.originatorFormatted
exists in theSubscriber
table.SUBSCRIBE
/STOP
): Handles new subscriptions, re-subscriptions, and opt-outs by creating or updating the database record. Sets appropriateconfirmationMessage
text.MESSAGEBIRD_ORIGINATOR
is configured, it usesmessagebird.messages.create
to send an SMS back. Note the use ofnew Promise
to handle the SDK's callback within anasync
function. Uses the originaloriginator
format for the recipient field when replying.try...catch
blocks for overall processing and specifically for SMS sending. Logs errors.200 OK
JSON response to MessageBird. This is crucial for preventing retries.3. Implementing Core Functionality: Sending Broadcasts
This section covers creating a simple admin interface to send messages and the corresponding API route to handle the broadcast logic.
3.1 Create the Admin UI:
Create a simple page with a form for the administrator to type and send messages.
Create
app/admin/page.tsx
(App Router):Explanation:
useState
) for message input, loading state, and status feedback.handleSubmit
sends a POST request to/api/messagebird/send
.3.2 Create the Send API Route:
This route fetches active subscribers and sends the message using the MessageBird SDK, handling batching.
Create
app/api/messagebird/send/route.ts
:Explanation:
message
and validates it. Checks forMESSAGEBIRD_ORIGINATOR
.phoneNumber
.phoneNumber
array. Crucially, confirms the required format for the SDK (E.164 with+
is assumed here, matching storage).batchSize
to 50 and loops through recipients.messagebird.messages.create
for each batch usingnew Promise
for the callback.4. Integrating with MessageBird
This section details obtaining necessary credentials from MessageBird and configuring your application and the MessageBird platform.
4.1 Get MessageBird API Key:
Log in to your MessageBird Dashboard.
Navigate to Developers > API access.
Use an existing live API key or click Add access key.
Copy the Live API key. Keep it secret!
Add this key to your
.env
file:4.2 Get a Virtual Mobile Number (Originator):
You need a number for users to text and to send messages from.
In the MessageBird Dashboard, go to Numbers.
Click Buy a number.
Select the Country, ensure SMS capability is checked, choose a number, and complete the purchase.
Copy the purchased number (in E.164 format, e.g.,
+12025550183
).Add this number to your
.env
file:4.3 Expose Local Development Server:
MessageBird needs a public URL to send webhooks to your local machine. Use
localtunnel
orngrok
.npm install -g localtunnel
npm run dev
(usually on port 3000)lt --port 3000
https://your-subdomain.loca.lt
). Keep this terminal running. This URL is temporary.4.4 Configure MessageBird Flow Builder:
Connect your number to your webhook API route.
localtunnel
URL + webhook path:https://your-subdomain.loca.lt/api/messagebird/webhook
Now, SMS messages sent to your MessageBird number will trigger a POST request to your local development server's webhook endpoint.
5. Error Handling, Logging, and Retries
Robust applications need proper error handling and logging.
5.1 Error Handling Strategy:
try...catch
around major operations.console.error
or a logger). Return generic client errors.err
object from the SDK callback to understand API issues (e.g., auth errors, invalid numbers).5.2 Logging:
console.log
/error
is okay. Log key events (webhook receipt, DB actions, send attempts, errors).pino
) for better analysis and integration with log management services.npm install pino pino-pretty
lib/logger.ts
):console.*
calls withlogger.info()
,logger.error()
, etc.5.3 Retry Mechanisms:
messagebird.messages.create
fails for a batch (e.g., temporary network issue, MessageBird 5xx error), consider:catch
block.async-retry
for more robust retries with increasing delays. This adds complexity.6. Database Schema and Data Layer
prisma/schema.prisma
(Section 1.5) defines theSubscriber
model. Add related models (e.g.,MessageLog
) as needed.lib/prisma.ts
) for type-safe DB operations (findUnique
,findMany
,create
,update
).npx prisma migrate dev
locally andnpx prisma migrate deploy
in CI/CD for production schema changes.phoneNumber
(@unique
) andsubscribed
(@@index
) are included. Analyze query performance (EXPLAIN
) for complex queries if needed.prisma/seed.ts
for test data (npx prisma db seed
).7. Adding Security Features
/admin
and/api/messagebird/send
.middleware.ts
) to intercept requests to protected routes, verify session/token/API key, and redirect/block unauthorized access. Check for specific admin roles if applicable.payload
(usingtoUpperCase
). Validateoriginator
format if strict E.164 is required (though standardization logic helps).message
is a non-empty string. Consider adding length validation/feedback in the UI.rate-limiter-flexible
,upstash/ratelimit
, Vercel Edge Middleware rate limiting./api/messagebird/webhook
and/api/messagebird/send
..env
) out of Git. Use platform environment variable management (Vercel, Netlify, Docker secrets).8. Handling Special Cases
.toUpperCase()
forpayload
in the webhook.originator
without+
, while the SDK might prefer+
forrecipients
.+
) by checking/adding the prefix in the webhook (Section 2.3). When sending (Section 3.2), it uses the stored format. Always verify the exact format requirements of the MessageBird SDK'smessages.create
function.@unique
onphoneNumber
. The code handles re-subscribe/re-stop attempts gracefully.