code examples
code examples
How to Send Bulk SMS with MessageBird and Next.js: Complete Tutorial
Learn how to build a production-ready bulk SMS broadcasting system in Next.js using MessageBird Batch API. Step-by-step guide with TypeScript, API routes, and error handling for sending up to 50 SMS messages at once.
MessageBird Bulk SMS with Next.js: Complete Implementation Guide
Sending SMS messages to multiple recipients simultaneously – bulk or broadcast messaging – is a common requirement for applications distributing alerts, notifications, or marketing communications efficiently. Integrate directly with an SMS provider's API to control sending logic, manage costs, and handle responses effectively.
This guide walks you through building a production-ready bulk SMS feature in Next.js using the MessageBird SMS Batch API. You'll learn to set up the project, create a secure API endpoint to interact with MessageBird, implement error handling, and build a simple frontend interface for sending messages. The implementation includes TypeScript, Next.js App Router, and handles up to 50 recipients per request.
Important Note (January 2025): MessageBird rebranded as Bird in February 2024. While the legacy MessageBird API endpoints (developers.messagebird.com) remain operational and are used in this guide, the company now operates under bird.com with new API endpoints at api.bird.com. Third-party integrations may require updates. This guide uses the stable legacy MessageBird API endpoints, which remain functional as of January 2025.
By the end of this guide, you'll build a functional Next.js application that accepts a list of recipients and a message body, securely sends these messages via MessageBird's Batch API, and handles success/error feedback.
What you'll build: MessageBird bulk SMS system
What you'll build:
- A Next.js application with a dedicated API route (
/api/send-bulk-sms). - An API route that securely handles requests to send the same SMS message to multiple recipients using the MessageBird Batch API.
- A basic frontend interface (a simple page in the Next.js app) to input recipient phone numbers and message content, triggering the API route.
Common use cases for bulk SMS:
This implementation is perfect for sending appointment reminders, emergency alerts, promotional campaigns, delivery notifications, or any scenario where you need to reach multiple users simultaneously with the same message.
Problem solved:
This implementation addresses the need to programmatically send SMS messages to many users at once without manual intervention or iterating individual API calls, which is inefficient and harder to manage. It provides a scalable way to integrate bulk SMS capabilities directly into a web application.
Technologies used:
- Next.js: A React framework for building full-stack web applications. Use it for both the frontend UI and the backend API route handler. Its API routes provide a convenient serverless environment for handling backend logic.
- MessageBird SMS Batch API: A RESTful API service enabling sending SMS messages to multiple recipients in a single API request. Chosen for its clear documentation and specific endpoint for batch operations. (API verified operational January 2025 at https://rest.messagebird.com/messages/batches)
- Node.js: The underlying runtime environment for Next.js.
- Fetch API: Native browser/Node.js API for making HTTP requests to the MessageBird API.
System architecture:
graph TD
A[User's Browser] -- Enters recipients & message --> B(Next.js Frontend Page);
B -- POST /api/send-bulk-sms --> C{Next.js API Route};
C -- Reads API Key --> D[.env.local];
C -- POST /messages/batches --> E[MessageBird Batch API];
E -- Sends SMS --> F((Recipients));
E -- Returns Send Statuses --> C;
C -- Returns Success/Error --> B;
B -- Displays Result --> A;Prerequisites:
- Node.js v18.18.0 or later (required for Next.js 15, released October 2024). Verify with
node --version. - npm or yarn package manager.
- A MessageBird account (note: company rebranded as Bird in 2024, but legacy accounts remain functional).
- A MessageBird API Access Key (Live or Test key) from developers.messagebird.com.
- Basic understanding of React, Next.js, and REST APIs.
Setting up your Next.js bulk SMS project
Create a new Next.js project and set up the necessary environment configuration.
Important for Next.js 15 users: Next.js 15 (released October 2024) introduced breaking changes including async Request APIs and changed caching defaults for GET Route Handlers. This guide's code is compatible, but if you're using Next.js 15+, cookies(), headers(), and similar functions now return Promises. The code in this guide uses standard fetch and doesn't use these APIs, so it remains compatible.
1.1 Create a Next.js application
Open your terminal and run the following command to create a new Next.js project using the App Router. Replace messagebird-bulk-sms with your desired project name.
npx create-next-app@latest messagebird-bulk-smsFollow the prompts. Recommended settings:
- Would you like to use TypeScript? Yes
- Would you like to use ESLint? Yes
- Would you like to use Tailwind CSS? No (optional, not needed for this guide)
- Would you like to use
src/directory? Yes - Would you like to use App Router? Yes
- Would you like to customize the default import alias? No
1.2 Navigate to the project directory
cd messagebird-bulk-sms1.3 Configure environment variables
Store your MessageBird API key and sender ID (originator) securely. Create a file named .env.local in the root of your project.
- Why
.env.local? Next.js automatically loads variables from this file intoprocess.envon the server side. It's included in.gitignoreby default, preventing accidental commits of sensitive keys.
Add the following lines to .env.local:
# .env.local
# Obtain your API Access Key from the MessageBird Dashboard:
# Developers -> API access -> API Keys (use either Live or Test key)
# Note: MessageBird rebranded as Bird (2024), but legacy dashboard remains at dashboard.messagebird.com
MESSAGEBIRD_ACCESS_KEY=YOUR_MESSAGEBIRD_ACCESS_KEY
# Define your Sender ID. This can be a phone number (in E.164 format, e.g., +12025550181)
# or an alphanumeric string (max 11 characters, e.g., "MyApp").
# Note: Alphanumeric sender IDs may not be supported in all countries or may require pre-registration.
# Using a purchased MessageBird number is the most reliable option.
# **Important:** Consult MessageBird documentation AND check country-specific regulations
# regarding alphanumeric sender IDs *before* implementing, as this is a common failure point.
MESSAGEBIRD_ORIGINATOR=YourSenderID- Replace
YOUR_MESSAGEBIRD_ACCESS_KEYwith your actual key from the MessageBird dashboard (Developers > API access). - Replace
YourSenderIDwith your desired originator (phone number or alphanumeric string).
Security best practice: Never commit .env.local to version control. Rotate API keys regularly and use test keys during development, switching to live keys only in production.
1.4 Project structure
Your key files will be:
src/app/page.tsx: The simple frontend UI.src/app/api/send-bulk-sms/route.ts: The backend API route handling MessageBird interaction..env.local: Stores sensitive credentials.
No additional dependencies are required for this basic implementation – use the built-in fetch API.
Building the MessageBird Batch API integration
Create the core backend logic – the API route that communicates with MessageBird.
2.1 Create the API route file
Create the following directory structure and file within the src directory:
src/
└── app/
└── api/
└── send-bulk-sms/
└── route.ts
2.2 Implement the API route logic
Paste the following code into src/app/api/send-bulk-sms/route.ts:
// src/app/api/send-bulk-sms/route.ts
import { NextResponse } from 'next/server';
// Define expected request body structure
interface RequestBody {
recipients: string[];
body: string;
}
export async function POST(request: Request) {
// Note: console.log statements are included for debugging during development.
// Replace with a structured logger (e.g., Pino, Winston) in production.
console.log('Received request to /api/send-bulk-sms');
// 1. --- Environment Variable Check ---
const accessKey = process.env.MESSAGEBIRD_ACCESS_KEY;
const originator = process.env.MESSAGEBIRD_ORIGINATOR;
if (!accessKey || !originator) {
console.error('Error: MessageBird API Key or Originator not configured in .env.local');
return NextResponse.json(
{ error: 'Server configuration error. Contact support.' },
{ status: 500 }
);
}
try {
// 2. --- Parse and Validate Request Body ---
let requestBody: RequestBody;
try {
requestBody = await request.json();
console.log('Parsed request body:', requestBody);
} catch (error) {
console.error('Error parsing request body:', error);
return NextResponse.json({ error: 'Invalid request body format.' }, { status: 400 });
}
const { recipients, body } = requestBody;
// Basic validation
if (!Array.isArray(recipients) || recipients.length === 0) {
return NextResponse.json({ error: 'Recipients must be a non-empty array.' }, { status: 400 });
}
if (typeof body !== 'string' || body.trim() === '') {
return NextResponse.json({ error: 'Message body must be a non-empty string.' }, { status: 400 });
}
// --- Recipient Validation ---
// This validation is basic. Production applications need more robust checks.
for (const recipient of recipients) {
if (typeof recipient !== 'string' || recipient.trim() === '') {
throw new Error('Invalid recipient found: Contains empty or non-string value.');
}
// Basic E.164 check example (VERY basic, misses many edge cases)
// const e164Regex = /^\+[1-9]\d{1,14}$/;
// if (!e164Regex.test(recipient)) {
// throw new Error(`Invalid recipient format: ${recipient}. Use E.164 format (e.g., +12025550181).`);
// }
// **Recommendation:** Use a dedicated library like 'libphonenumber-js' for reliable E.164 validation in production.
}
// --- MessageBird Batch API Limit Handling ---
// The MessageBird Batch API allows max 100 message objects per request.
// Each message object can target a maximum of 50 recipients.
// This implementation sends ONE message object targeting multiple recipients.
// **Therefore, this endpoint implementation is limited to 50 recipients per call.**
// (Verified from MessageBird API documentation, January 2025: developers.messagebird.com/api/sms-batch-api/)
if (recipients.length > 50) {
console.error(`Error: Number of recipients (${recipients.length}) exceeds the limit of 50 for this implementation.`);
// **Production Enhancement:** To handle >50 recipients, implement logic here
// to split the 'recipients' array into chunks of 50 and make multiple separate
// requests to the MessageBird Batch API. This guide does not implement chunking.
return NextResponse.json(
{ error: `Too many recipients. Maximum is 50 per request in this implementation. You sent ${recipients.length}.` },
{ status: 400 }
);
}
// 3. --- Construct MessageBird API Payload ---
const messageBirdPayload = {
// The Batch API expects an array of message objects.
// Send the *same* message to multiple recipients by creating *one* message object within the array.
messages: [
{
originator: originator,
recipients: recipients, // Array of recipient phone numbers (max 50 here)
body: body,
// Optional parameters (e.g., reportUrl for status webhooks)
// reportUrl: 'YOUR_WEBHOOK_URL_HERE' // See Section 6 for details
},
// You can add more message objects here to send *different*
// messages to *different* sets of recipients within the same batch request,
// respecting the overall 100 message object limit per API call.
],
};
console.log('Constructed MessageBird Payload:', JSON.stringify(messageBirdPayload, null, 2));
// 4. --- Call MessageBird Batch API ---
// Endpoint verified operational as of January 2025
const MESSAGEBIRD_API_ENDPOINT = 'https://rest.messagebird.com/messages/batches';
console.log(`Sending request to MessageBird: ${MESSAGEBIRD_API_ENDPOINT}`);
const response = await fetch(MESSAGEBIRD_API_ENDPOINT, {
method: 'POST',
headers: {
'Authorization': `AccessKey ${accessKey}`,
'Content-Type': 'application/json',
},
body: JSON.stringify(messageBirdPayload),
});
console.log(`MessageBird response status: ${response.status}`);
// 5. --- Handle MessageBird Response ---
if (!response.ok) {
// Attempt to parse error details from MessageBird
let errorBody = 'Unknown error';
try {
const errorData = await response.json();
console.error('MessageBird API Error Response:', errorData);
// MessageBird errors include an 'errors' array
if (errorData.errors && Array.isArray(errorData.errors) && errorData.errors.length > 0) {
errorBody = errorData.errors.map((err: any) => `${err.description} (code: ${err.code})`).join(', ');
} else {
errorBody = JSON.stringify(errorData);
}
} catch (parseError) {
const responseText = await response.text();
console.error('Could not parse MessageBird error response. Raw response:', responseText);
errorBody = responseText || 'Could not parse error response.';
}
throw new Error(`MessageBird API request failed with status ${response.status}: ${errorBody}`);
}
// Success – MessageBird accepted the batch request.
// The response body contains details about each individual message created.
const responseData = await response.json();
console.log('MessageBird Success Response:', JSON.stringify(responseData, null, 2));
// Note: This indicates MessageBird *accepted* the request.
// Individual messages might still fail delivery later.
// Implement webhooks (using reportUrl) for final delivery status (See Section 6).
return NextResponse.json(
{
success: true,
message: 'Bulk SMS request submitted successfully.',
details: responseData, // Contains IDs and initial statuses
},
{ status: 202 } // 202 Accepted: Request accepted, processing underway
);
} catch (error: unknown) {
console.error('Error in /api/send-bulk-sms:', error);
const errorMessage = error instanceof Error ? error.message : 'An unexpected server error occurred.';
// Avoid exposing detailed internal errors to the client in production
let clientErrorMessage = 'An unexpected server error occurred.';
if (errorMessage.includes('Invalid recipient format') || errorMessage.includes('Invalid recipient found') || errorMessage.includes('Too many recipients')) {
clientErrorMessage = errorMessage;
} else if (errorMessage.startsWith('MessageBird API request failed')) {
clientErrorMessage = 'Failed to send messages due to an issue communicating with the SMS provider. Check inputs or contact support.';
}
return NextResponse.json(
{ error: clientErrorMessage, details: errorMessage },
{ status: error instanceof Error && error.message.includes('Too many recipients') ? 400 : 500 }
);
}
}Code explanation:
- Environment Variable Check: Checks if
MESSAGEBIRD_ACCESS_KEYandMESSAGEBIRD_ORIGINATORare loaded from.env.local. Returns a 500 error if missing. - Parse and Validate Request Body: Reads the JSON body. Basic validation ensures
recipientsis a non-empty array andbodyis a non-empty string.- Recipient Validation Note: The current recipient validation is basic. For production, use a dedicated library like
libphonenumber-jsto ensure recipients are in the correct E.164 format. - Recipient Limit Handling: Checks if the number of recipients exceeds 50. Returns a 400 error if it does. To send to more than 50 recipients, modify this code to split the recipients into chunks of 50 and make multiple API calls.
- Recipient Validation Note: The current recipient validation is basic. For production, use a dedicated library like
- Construct MessageBird Payload: Builds the JSON payload for the MessageBird Batch API, creating one message object targeting the provided recipients (up to 50).
- Call MessageBird API: Uses
fetchto make thePOSTrequest with correct headers. - Handle MessageBird Response: Checks
response.ok. Parses success or error responses from MessageBird. Returns202 Acceptedon success. - Error Handling: A top-level
try...catchhandles various errors. Logs detailed errors server-side and returns appropriate client-facing error messages and status codes. - Logging: Includes
console.logandconsole.errorfor debugging. In production, replace these with a proper logging library (e.g., Pino, Winston).
Testing the API endpoint (optional but recommended):
Test this endpoint using curl or a tool like Postman before building the frontend.
- Start your Next.js development server:
npm run dev - Open a new terminal window.
- Run the following
curlcommand (replace placeholders with your test numbers and ensure the server runs on port 3000):
curl -X POST http://localhost:3000/api/send-bulk-sms \
-H 'Content-Type: application/json' \
-d '{
"recipients": ["+12025550181", "+12025550182"],
"body": "Hello from Next.js Bulk Test!"
}'You should see a JSON response indicating success (status 202) or an error (status 400 or 500). Check the terminal running the Next.js server for detailed logs, and your MessageBird dashboard (Logs > SMS) to verify message processing.
Creating the frontend SMS form
Create a simple page to interact with your API route.
3.1 Update the home page
Replace the content of src/app/page.tsx with the following code:
// src/app/page.tsx
'use client'; // Required for using hooks like useState and event handlers
import React, { useState } from 'react';
interface ApiResponse {
success?: boolean;
message?: string;
error?: string;
details?: any;
}
export default function HomePage() {
// State for form inputs
const [recipientsInput, setRecipientsInput] = useState(''); // Comma-separated string
const [messageBody, setMessageBody] = useState('');
// State for handling API response and loading
const [loading, setLoading] = useState(false);
const [responseInfo, setResponseInfo] = useState<ApiResponse | null>(null);
const handleSubmit = async (event: React.FormEvent<HTMLFormElement>) => {
event.preventDefault();
setLoading(true);
setResponseInfo(null);
// Basic validation: Split recipients string into an array, trim whitespace
const recipients = recipientsInput
.split(',')
.map(r => r.trim())
.filter(r => r !== '');
if (recipients.length === 0) {
setResponseInfo({ error: 'Enter at least one recipient phone number.' });
setLoading(false);
return;
}
// Check recipient count before sending to API
if (recipients.length > 50) {
setResponseInfo({ error: `Too many recipients entered (${recipients.length}). Maximum allowed per submission is 50.` });
setLoading(false);
return;
}
if (!messageBody.trim()) {
setResponseInfo({ error: 'Enter a message body.' });
setLoading(false);
return;
}
try {
console.log('Sending request to /api/send-bulk-sms with:', { recipients, body: messageBody });
const response = await fetch('/api/send-bulk-sms', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({ recipients: recipients, body: messageBody }),
});
const data: ApiResponse = await response.json();
console.log('Received response from API route:', data);
if (!response.ok) {
throw new Error(data.error || `Request failed with status ${response.status}`);
}
// Handle success
setResponseInfo({ success: true, message: data.message || 'Request submitted successfully.' });
} catch (error: unknown) {
console.error('Error submitting form:', error);
const errorMessage = error instanceof Error ? error.message : 'An unexpected error occurred.';
setResponseInfo({ error: `Submission failed: ${errorMessage}` });
} finally {
setLoading(false);
}
};
// Basic inline styles for demonstration
const styles = {
container: { maxWidth: '600px', margin: '40px auto', padding: '20px', border: '1px solid #ccc', borderRadius: '8px', fontFamily: 'sans-serif' },
label: { display: 'block', marginBottom: '5px', fontWeight: 'bold' },
input: { width: '100%', padding: '10px', marginBottom: '15px', border: '1px solid #ccc', borderRadius: '4px', boxSizing: 'border-box' as const },
textarea: { width: '100%', padding: '10px', marginBottom: '15px', border: '1px solid #ccc', borderRadius: '4px', minHeight: '100px', boxSizing: 'border-box' as const, fontFamily: 'inherit' },
button: { padding: '10px 20px', backgroundColor: '#0070f3', color: 'white', border: 'none', borderRadius: '4px', cursor: 'pointer', fontSize: '16px' },
buttonDisabled: { backgroundColor: '#ccc', cursor: 'not-allowed' },
responseBox: { marginTop: '20px', padding: '15px', borderRadius: '4px', border: '1px solid' },
successBox: { borderColor: 'green', backgroundColor: '#e6ffed', color: 'darkgreen' },
errorBox: { borderColor: 'red', backgroundColor: '#ffebe6', color: 'darkred' },
};
return (
<div style={styles.container}>
<h1>Send Bulk SMS via MessageBird</h1>
<p>Enter recipient phone numbers (comma-separated, E.164 format recommended e.g., +12025550181,+442071234567) and the message body. **Maximum 50 recipients per submission.**</p>
<form onSubmit={handleSubmit}>
<div>
<label htmlFor="recipients" style={styles.label}>Recipients (Max 50):</label>
<textarea
id="recipients"
value={recipientsInput}
onChange={(e) => setRecipientsInput(e.target.value)}
placeholder="e.g., +12025550181, +442071234567, +31612345678"
rows={3}
style={styles.textarea}
required
/>
</div>
<div>
<label htmlFor="message" style={styles.label}>Message Body:</label>
<textarea
id="message"
value={messageBody}
onChange={(e) => setMessageBody(e.target.value)}
placeholder="Your SMS message content here..."
style={styles.textarea}
required
/>
</div>
<button type="submit" disabled={loading} style={{ ...styles.button, ...(loading ? styles.buttonDisabled : {}) }}>
{loading ? 'Sending...' : 'Send Bulk SMS'}
</button>
</form>
{responseInfo && (
<div style={{ ...styles.responseBox, ...(responseInfo.success ? styles.successBox : styles.errorBox) }}>
{responseInfo.success ? (
<p><strong>Success:</strong> {responseInfo.message}</p>
) : (
<p><strong>Error:</strong> {responseInfo.error}</p>
)}
</div>
)}
</div>
);
}Code explanation:
'use client': Marks this as a Client Component for using hooks and event handlers.- State Variables: Manage form inputs (
recipientsInput,messageBody), loading state (loading), and API response feedback (responseInfo). handleSubmitFunction:- Prevents default submission, sets loading state.
- Parses and trims recipients from the input string.
- Adds frontend validation to check for empty inputs and checks if the recipient count exceeds 50, preventing the API call if it does.
- Makes the
POSTrequest to/api/send-bulk-sms. - Handles success or error responses from the API route.
- Includes
try...catchfor fetch errors. - Resets loading state in the
finallyblock.
- JSX Structure: A simple form with textareas for recipients (clearly labeled with the 50 max limit) and message. The button shows loading state. A conditional area displays success/error messages. Basic inline styles are used.
Testing your bulk SMS application
Run the application and test the end-to-end flow.
4.1 Run the development server
If not already running, start the server from your project root:
npm run dev
# or
# yarn dev4.2 Test in the browser
- Open your browser and navigate to
http://localhost:3000. - You should see the form indicating the 50-recipient limit.
- Enter 1–50 valid phone numbers (E.164 recommended) separated by commas.
- Enter a test message.
- Click "Send Bulk SMS".
- Observe feedback: loading state, then success or error message.
- Check recipient phones for the SMS.
- Check MessageBird Dashboard (Logs > SMS) for entries.
- Check your terminal logs for details from the API route.
4.3 Test error scenarios:
- Submit with empty fields – see frontend validation errors.
- Submit with more than 50 recipients – see the frontend error message preventing the submission.
- Submit with invalid phone number formats (if you added stricter validation) or malformed comma separation.
- Temporarily invalidate your
MESSAGEBIRD_ACCESS_KEYin.env.local, restart the server, and submit. Expect an error message indicating a communication failure with the provider. Restore the key afterward.
Security best practices for bulk SMS
- API Key Security: Never commit
.env.localor expose yourMESSAGEBIRD_ACCESS_KEYin frontend code. Use it only server-side. - Input Validation: The current validation is basic, especially for phone numbers. In production:
- Implement robust E.164 phone number validation using a dedicated library like
libphonenumber-jswithin the API route (/api/send-bulk-sms/route.ts). - Sanitize the message body if displayed elsewhere.
- Enforce message length limits.
- Implement robust E.164 phone number validation using a dedicated library like
- Rate Limiting: Protect your API route (
/api/send-bulk-sms) from abuse. Implement rate limiting to prevent rapid, excessive SMS sending. Tools likeupstash/ratelimitintegrated with Next.js middleware are common solutions. - Authentication/Authorization: The current API endpoint is open. Secure it by ensuring only authenticated and authorized users (e.g., logged-in admins) can access it. Integrate checks within the API route based on your application's authentication system (sessions, JWTs, etc.).
- CSRF Protection: For production applications, implement CSRF token validation in your API routes to prevent cross-site request forgery attacks. Next.js doesn't include built-in CSRF protection for API routes.
Error handling and logging
- API Route Logging: The current route uses
console.log/console.error. For production, replace these with a robust logging library (e.g., Pino, Winston). This enables structured logging, setting levels, and sending logs to external services (Datadog, Sentry, etc.) for better monitoring and debugging. - MessageBird Errors: Review MessageBird's API error documentation to handle specific codes (e.g., insufficient balance, invalid originator) more gracefully within the API route's error handling.
- Delivery Status: A successful API response (202 Accepted) confirms MessageBird accepted the request. Messages can fail delivery later. For reliable status tracking:
- Specify a
reportUrlin the MessageBird API payload (see commented line inroute.ts). This URL should point to another API route in your Next.js app (e.g.,/api/message-status). - Implement that
/api/message-statusroute to securely receivePOSTrequests from MessageBird containing delivery reports (DLRs). - Process these DLRs to update your application's state (e.g., database records) with statuses like
delivered,delivery_failed, etc. - Note: Implementing a secure and robust webhook receiver is crucial for production but is beyond the scope of this guide. Refer to MessageBird documentation and tutorials on handling webhooks in Next.js.
- Specify a
Troubleshooting common MessageBird issues
- Invalid API Key: Check
.env.localfor correctness. Restart the dev server after changes. Look for 401 errors from MessageBird in server logs. - Incorrect Originator: Ensure
MESSAGEBIRD_ORIGINATORis valid for your account and complies with regulations in recipient countries. Check MessageBird docs and country rules first. - Invalid Recipient Numbers: Use E.164 format (
+14155552671). Incorrect formats cause failures. Use validation libraries. - MessageBird API Limits:
- Batch Size & Recipient Limit: The Batch API allows max 100 message objects per request. Each object can target max 50 recipients. This guide's implementation uses one message object per API call, limiting it to 50 recipients. To send to more, implement chunking logic (splitting the list into groups of 50) and make multiple API calls.
- Rate Limits: MessageBird enforces API request rate limits. Check their docs. For high volumes, implement delays or use queues.
- Costs: SMS messages cost money. Monitor your MessageBird balance.
- Content Restrictions: Adhere to SMS content regulations (spam, phishing) and MessageBird's policies.
- API Endpoint Status: This guide uses MessageBird's legacy API endpoint (https://rest.messagebird.com/messages/batches), which remains operational as of January 2025. If you encounter connectivity issues, check MessageBird/Bird's status page or consider migrating to Bird's new API endpoints at api.bird.com.
Deploying your Next.js bulk SMS app
- Environment Variables: When deploying (Vercel, Netlify, AWS, etc.), configure
MESSAGEBIRD_ACCESS_KEYandMESSAGEBIRD_ORIGINATORin your hosting provider's environment variable settings. Do not rely on.env.localin production. - Platform Settings: Ensure your deployment uses a compatible Node.js version (v18.18.0 or later recommended).
- CI/CD: Automate testing, building, and deployment. Securely inject environment variables.
- Rollback: Have a rollback strategy for deployments.
Frequently Asked Questions (FAQ)
How do I send bulk SMS with MessageBird in Next.js?
Use MessageBird's Batch API endpoint (/messages/batches) with a Next.js API route. Create a POST endpoint that constructs a payload with a messages array containing recipient lists and message content, then send it using the Fetch API with your MessageBird Access Key for authentication.
What is the MessageBird Batch API recipient limit?
The MessageBird Batch API allows a maximum of 100 message objects per request, with each message object supporting up to 50 recipients. This guide's implementation sends one message object per API call, limiting it to 50 recipients per request.
How do I handle more than 50 recipients with MessageBird?
To send to more than 50 recipients, implement chunking logic to split your recipient list into groups of 50, then make multiple API calls to MessageBird's Batch API. Each chunk becomes a separate API request with its own message object.
Is MessageBird compatible with Next.js 15?
Yes, MessageBird's API is compatible with Next.js 15. However, Next.js 15 (released October 2024) requires Node.js v18.18.0 or later and introduced async Request APIs. This guide's code uses the standard Fetch API and remains fully compatible with both Next.js 14 and 15.
What happened to MessageBird – did it rebrand?
MessageBird rebranded as Bird in February 2024. The legacy API endpoints at rest.messagebird.com remain operational as of January 2025, but the company now operates under bird.com with new API endpoints at api.bird.com. Consider migrating to Bird's new API structure for long-term projects.
How do I validate phone numbers for MessageBird SMS?
Use the E.164 international phone number format (e.g., +12025550181). For production applications, implement robust validation using a library like libphonenumber-js rather than basic regex patterns, as phone number validation has many edge cases across different countries.
How do I track MessageBird SMS delivery status?
Implement webhooks by adding a reportUrl parameter to your MessageBird API payload. This URL points to another API route in your Next.js application that receives delivery reports (DLRs) from MessageBird with statuses like delivered or delivery_failed.
What Node.js version do I need for Next.js bulk SMS?
You need Node.js v18.18.0 or later for Next.js 15 (released October 2024). Verify your version with node --version. Earlier Next.js versions support older Node.js versions, but v18.18.0+ is recommended for the latest features and security updates.
How much does MessageBird bulk SMS cost?
MessageBird pricing varies by destination country and message volume. Typical costs range from $0.01-$0.10 per SMS segment depending on the destination. Contact MessageBird sales for enterprise pricing and volume discounts. Monitor your MessageBird dashboard for real-time balance and usage tracking.
Can I send international SMS with MessageBird Batch API?
Yes, MessageBird supports international SMS delivery to 200+ countries. Ensure recipient numbers use E.164 format with the correct country code (e.g., +44 for UK, +91 for India). Note that pricing, delivery rates, and sender ID regulations vary by country. Check MessageBird's country-specific SMS guides before sending international messages.
Conclusion
You've successfully implemented a bulk SMS sending feature in a Next.js application using the MessageBird Batch API, limited to 50 recipients per submission in this implementation. You created a secure API route and a simple frontend interface. Key takeaways include secure API key handling, constructing the Batch API payload, error handling, understanding the 50-recipient limit per call for this setup, and the need for webhooks for final delivery status.
Important reminder: MessageBird rebranded as Bird in February 2024. While the legacy API endpoints used in this guide remain functional (verified January 2025), monitor for future deprecation announcements and consider migrating to Bird's new API structure at api.bird.com for long-term projects.
Next steps and potential enhancements:
- Implement Webhooks: Essential for production-grade status tracking. Set up
reportUrland a dedicated endpoint. - Database Integration: Manage recipients via a database.
- Robust Validation: Integrate
libphonenumber-jsfor E.164 validation. - Implement Chunking: Modify the API route to split recipient lists larger than 50 into multiple MessageBird API calls.
- Asynchronous Processing: Use queues (BullMQ, SQS, etc.) for large batches or scheduled sends.
- Advanced UI: Add contact management, templates, scheduling UI, status reporting.
- Enhanced Logging & Monitoring: Integrate production-grade logging/error tracking.
- Consider Bird API Migration: For new projects or long-term maintenance, evaluate migrating to Bird's updated API endpoints (api.bird.com) and documentation (docs.bird.com).
This foundation enables you to send bulk SMS messages from your Next.js application. Consult the official MessageBird API documentation (developers.messagebird.com) or Bird documentation (docs.bird.com) for the latest features and details, especially regarding API limits, webhooks, and originator regulations.