Frequently Asked Questions
Use the Sinch SMS API with Node.js and Express to send SMS messages. This involves setting up an Express server, configuring the Sinch API, and implementing routes and controllers to handle message sending and delivery reports. A dedicated service like 'sinchService.js' helps encapsulate the API interaction logic.
The Sinch SMS API enables sending and receiving SMS messages globally within your Node.js applications. It provides a RESTful interface accessible using libraries like 'node-fetch', allowing developers to integrate SMS functionality into their projects.
Create a Node.js Express app with API endpoints for accepting campaign details (recipients, message content). Use environment variables to securely store your Sinch API credentials. Use a service to handle interaction with the Sinch API, and include error handling and logging.
Sinch uses callback URLs (webhooks) to deliver real-time updates on message delivery status. When you send a message, specify a callback URL in the API request. Sinch will POST delivery reports to this URL, including the status (Delivered, Failed) and other details. This is how you know whether your message was successfully sent and delivered.
Use ngrok during development to expose your local server and test Sinch webhooks. Ngrok provides a public HTTPS URL that Sinch can reach, essential for receiving delivery reports while your app is running locally.
The client_reference is a unique identifier you generate to track individual SMS messages within your system. Include it in the API request when sending messages, and Sinch will return it in delivery reports, allowing you to correlate reports back to your internal message records.
Create a specific route in your Express app to receive POST requests from Sinch (e.g., '/api/webhooks/delivery-reports'). In the route handler, process the JSON payload, validate it, and update your database based on the delivery status and unique client_reference.
Use npm or yarn to install the required packages. npm install express dotenv node-fetch will install Express for the webserver, dotenv for handling environment variables, and node-fetch for making API requests.
You'll need Node.js and npm installed, a Sinch account with a Service Plan ID and API Token, a Sinch phone number, and optionally ngrok for webhook testing. Basic knowledge of Node.js, Express, and REST APIs is also helpful.
Create directories for routes, controllers, and services. Create files for app configuration, server setup, and route definitions. Use .env to store sensitive information, and .gitignore to exclude files from version control.
Dotenv loads environment variables from a .env file into process.env, making it easy to manage configuration values like API keys and other sensitive information. This helps secure your credentials and keeps them separate from your code.
Storing sensitive information like API keys directly in your code is a security risk. Environment variables, loaded with dotenv, provide a more secure way to configure your Sinch integration without exposing credentials.
Use a strong validation library for API requests, implement robust input sanitization, and avoid logging sensitive data in production. If available, implement webhook signature validation to ensure requests come from Sinch.
Yes, ngrok creates a secure tunnel that allows you to receive webhooks locally, enabling testing of delivery reports during development without deploying your application.
Building SMS Marketing Campaigns with Sinch, Node.js & Express (2025 Guide)
Learn how to build a production-ready SMS marketing campaign system using the Sinch SMS API, Node.js, Express 5, and NextAuth authentication. This comprehensive tutorial covers everything from project setup to sending bulk SMS messages, handling delivery webhooks, securing your API endpoints, and deploying to production.
By the end of this tutorial, you will have a functional Express application capable of accepting campaign details via an API endpoint, sending SMS messages to a list of recipients using Sinch, and handling delivery status updates via webhooks. This solves the common need for businesses to programmatically send targeted SMS communications for marketing or notification purposes.
Framework Compatibility Note (2025): This guide uses Express 5.x, which became the default on npm as of March 31, 2025. Express 5 requires Node.js 18 or higher and includes breaking changes such as improved async error handling and removal of legacy middleware. This guide is compatible with Node.js 22.x (current LTS, Active until October 2025) and Node.js 24.x (released May 2025).
What You'll Build: SMS Marketing System with Sinch and Node.js
Technologies Used:
.envfile intoprocess.env. (Current version: 17.2.3)fetchAPI to Node.js, used for making HTTP requests to the Sinch API. (Note: Node.js 18+ includes native fetch support; node-fetch is optional)System Architecture:
Prerequisites:
ngrokinstalled globally (npm install ngrok -g).Note on Native Fetch: Node.js 18 includes experimental native fetch support (stable in Node.js 21+). If using Node.js 18 or higher, you can use native
fetch()instead of installingnode-fetch. This guide usesnode-fetchfor broader compatibility, but native fetch is recommended for production use with modern Node.js versions.Step 1: Setting Up Your Node.js SMS Marketing Project
Let's initialize our Node.js project and install the necessary dependencies for building SMS marketing campaigns with Sinch.
Create Project Directory: Open your terminal and create a new directory for the project.
Initialize npm: Initialize the project using npm. You can accept the defaults.
This creates a
package.jsonfile.Install Dependencies: Install Express for the web server,
dotenvfor environment variables, andnode-fetchfor making API requests.Alternative for Node.js 18+: If using Node.js 18 or higher, you can omit
node-fetchand use nativefetch()instead:Project Structure: Create a basic directory structure for organization.
src/: Contains all source code.src/routes/: Defines API endpoints.src/controllers/: Handles request logic.src/services/: Contains business logic, like interacting with Sinch.src/app.js: Configures the Express application (middleware, routes).src/server.js: Starts the HTTP server..env: Stores sensitive configuration (API keys, etc.). Never commit this file..gitignore: Specifies files/folders Git should ignore.Configure
.gitignore: Addnode_modulesand.envto your.gitignorefile to prevent committing them.Step 2: Configuring Sinch API Credentials
Securely store your Sinch credentials and configuration using environment variables.
Edit
.envfile: Open the.envfile and add your Sinch details. Replace the placeholder values with your actual credentials.SINCH_SERVICE_PLAN_ID: Found on your Sinch Customer Dashboard (SMS -> APIs -> Select your API).SINCH_API_TOKEN: Found on the same page as the Service Plan ID. Click ""Show"" to reveal it. Keep this secret.SINCH_BASE_URL: The regional endpoint for the Sinch SMS API. Ensure this matches your account's region (e.g.,https://us.sms.api.sinch.com,https://eu.sms.api.sinch.com).SINCH_NUMBER: The virtual phone number you acquired from Sinch, in E.164 format (e.g.,+12025550142). This will be the sender ID for your messages.PORT: The port your Express server will listen on.BASE_URL: The public base URL where your application is accessible. This is crucial for constructing the webhookcallback_url. Use yourngrokHTTPS URL during development/testing, and your actual domain name in production.Load Environment Variables: Configure
dotenvat the very beginning of your application entry point (src/server.js) to load these variables.Step 3: Building the Sinch SMS Service Module
Create a dedicated service to handle communication with the Sinch API. This encapsulates the logic and makes it reusable.
Edit
src/services/sinchService.js: Implement the function to send SMS messages.from: Your Sinch number.to: An array of recipient E.164 phone numbers.body: The message content.delivery_report: Set to"full"to receive detailed status updates via webhook.callback_url: The URL Sinch will POST delivery reports to (we'll define this route later).client_reference: (Optional) A unique ID you generate (e.g., UUID, database message ID) to correlate delivery reports back to your internal records. Useful for reliable lookups in the webhook handler.node-fetchto make a POST request with the correct headers (including theAuthorization: Bearertoken).Enable ES Modules: Since we are using
import/exportsyntax, add"type": "module"to yourpackage.json:(Ensure your Node.js version supports ES Modules and native fetch. Node.js 18+ recommended, Node.js 22+ for full LTS support).
Step 4: Creating the Express API for Campaign Management
Set up the Express server and define the API endpoints for sending campaigns and receiving webhooks.
Configure Express App (
src/app.js): Set up middleware and routes.express.json()andexpress.urlencoded()to parse incoming request bodies./healthzendpoint for monitoring./api/campaignsand/api/webhooks.Create Server Entry Point (
src/server.js): Load environment variables and start the server.dotenv.config()is called first.appfromapp.js.PORT.BASE_URL.Define Campaign Routes (
src/routes/campaignRoutes.js): Create the endpoint for sending campaigns.Implement Campaign Controller (
src/controllers/campaignController.js): Handle the logic for the/sendendpoint.recipientsandmessagefrom the request body.callbackUrldynamically using theBASE_URLenvironment variable. Warns ifBASE_URLis not set. Production Note: For production environments,ngrokis unsuitable. You'll need a publicly accessible server with a static IP or domain name. YourBASE_URLenvironment variable should then be set to this public URL (e.g.,https://yourapp.yourdomain.com) so Sinch can reach your webhook.client_referenceusingcrypto.randomUUID(). Crucially, this should be stored in your database before callingsendSmsso you can look it up when the webhook arrives.sinchService.sendSmsfunction, passing thecallbackUrlandclientReference.202 Acceptedstatus, indicating the request is processing, along with thebatch_idandclient_reference.// TODO:comments indicating where database interactions would typically occur.next(error)to delegate error handling.Test Sending:
npm start(ornpm run devif using Node >= 18).curlor Postman to send a POST request:(Replace
+1RECIPIENT_PHONE_NUMBERwith a valid test number in E.164 format).You should see logs in your terminal and receive an SMS on the recipient phone. The response should look similar to:
Step 5: Implementing Sinch Webhook Handlers for Delivery Reports
Configure and handle incoming delivery reports from Sinch to track SMS delivery status.
Define Webhook Routes (
src/routes/webhookRoutes.js):Implement Webhook Controller (
src/controllers/webhookController.js):client_referenceorbatch_id, status updates, error handling within the handler).batch_id,status,code,recipient, andclient_reference.client_referencefor reliability.200 OKresponse back to Sinch quickly to acknowledge receipt and prevent unnecessary retries. Discusses how to handle internal processing errors gracefully.Expose Localhost with
ngrok(Development/Testing Only):npm run dev), open another terminal window.httpsURL (e.g.,https://abcd-1234-5678.ngrok.io).ngrokis for development and testing only. For production, you need a publicly hosted server with a stable URL.Set
BASE_URLEnvironment Variable:.envfile and set theBASE_URLto thengrokHTTPS URL you copied.npm run devornpm start). It should now log the correctBASE_URL.Configure Callback URL in Sinch Dashboard:
BASE_URLplus the route path:https://YOUR_NGROK_HTTPS_URL/api/webhooks/delivery-reports(e.g.,https://abcd-1234-5678.ngrok.io/api/webhooks/delivery-reports)Test Webhook:
BASE_URLset) andngrokare running.curlcommand from Step 4.5. Make sure the server logs show it's using the correctngrokbasedcallbackUrl.'--- Received Sinch Delivery Report ---'log message followed by the JSON payload from Sinch indicating the message status (Delivered,Failed, etc.) and including theclient_referenceyou sent.Securing Your SMS API with NextAuth (Optional)
For production SMS marketing campaigns, you should secure your API endpoints with authentication. Here's how to integrate NextAuth for protecting campaign routes:
Install NextAuth dependencies:
Add authentication middleware to campaign routes to ensure only authorized users can send SMS campaigns.
For a complete NextAuth integration guide with SMS functionality, see our detailed tutorial on implementing SMS authentication with NextAuth.
Database Schema for SMS Campaign Tracking (Conceptual)
While this guide uses in-memory processing, a production system requires persistent storage.
Conceptual Schema (e.g., PostgreSQL):
Implementation Considerations:
client_referencebefore calling the Sinch API to ensure you can correlate webhook delivery reports.client_referencecolumn for fast lookups when processing webhooks.status,campaign_id, andsent_atfor query performance.Frequently Asked Questions About SMS Marketing with Sinch and Node.js
What Node.js version is required for building SMS campaigns with Sinch?
You need Node.js 18 or higher to use Express 5.x, which became the default on npm as of March 31, 2025. We recommend using Node.js 22.x (current LTS, Active until October 2025) or Node.js 24.x (released May 2025) for production applications. Express 5 includes breaking changes such as improved async error handling and requires the removal of legacy middleware patterns.
How many recipients can I send SMS to in a single Sinch API request?
As of 2024, Sinch supports a maximum of 1000 recipients per request. This limit was increased from the previous 100-recipient cap. If you need to send to more than 1000 recipients, implement batching logic to split your recipient list into groups of 1000 or fewer and process each batch sequentially with appropriate delays to respect rate limits.
Should I use node-fetch or native fetch() for Sinch API calls?
If you're using Node.js 18 or higher, use the native
fetch()function, which is built into Node.js (experimental in v18, stable in v21+). Native fetch provides better performance and eliminates an external dependency. Only usenode-fetchif you need to support older Node.js versions or require specific features not available in the native implementation.How do Sinch SMS delivery reports work with webhooks?
Sinch sends HTTP POST requests to your configured
callback_urlwhen message status changes occur (delivered, failed, etc.). Your webhook endpoint must return a200 OKresponse quickly to acknowledge receipt. Use theclient_referencefield (a UUID you generate before sending) to correlate delivery reports with your database records. Sinch may retry webhook delivery if your endpoint returns an error or times out.What are the Sinch SMS API rate limits for marketing campaigns?
Rate limits are plan-specific and set the maximum messages per second. Status queries have a limit of 1 request per second per IP address, with a maximum of 700 requests per second per IP for all endpoints. Each recipient in a batch counts as one message for rate limiting purposes. Contact your Sinch account manager to adjust rate limits for your specific use case.
How do I handle STOP/unsubscribe requests in SMS marketing?
Implement an inbound SMS webhook handler to process messages containing keywords like STOP, UNSUBSCRIBE, or END. When you receive these messages, immediately add the sender's number to your suppression list in your
recipientstable (setis_opted_out = TRUE) and send a confirmation message. Always filter opted-out numbers from your recipient lists before sending campaigns to maintain compliance with telecommunications regulations and avoid penalties.Can I integrate NextAuth authentication with this Sinch SMS setup?
Yes! This tutorial uses Express.js for the API server and can be extended with NextAuth for authentication. To integrate with Next.js and NextAuth, create API routes in the
pages/apiorapp/apidirectory and adapt the controller logic to Next.js API route handlers. You can add authentication middleware to protect your campaign endpoints and associate campaigns with authenticated users. The Sinch service layer code remains largely the same regardless of the framework.What's the difference between batch_id and client_reference in Sinch?
The
batch_idis generated by Sinch and returned when you send a message batch – it identifies the batch in Sinch's system. Theclient_referenceis a unique identifier you generate (typically a UUID) before sending, allowing you to correlate Sinch's delivery reports with your internal database records. Always useclient_referencefor reliable lookups in webhook handlers, as it's under your control and can be stored before the API call.How do I test Sinch webhooks locally during development?
Use ngrok to expose your local development server to the internet. Run
ngrok http 3000to get a public HTTPS URL, set this as yourBASE_URLenvironment variable, and configure the full webhook endpoint URL in your Sinch dashboard (e.g.,https://your-ngrok-id.ngrok.io/api/webhooks/delivery-reports). Remember that ngrok URLs change each time you restart, so update your.envfile and Sinch dashboard configuration accordingly. Never use ngrok in production – deploy to a server with a stable public URL.What security measures should I implement for production SMS campaigns?
Essential security measures include: API key authentication or JWT tokens for campaign endpoints, input validation using libraries like
express-validatorfor phone numbers and message content, rate limiting withexpress-rate-limitto prevent abuse, HTTPS-only communication (TLS), webhook signature verification if supported by Sinch, secure storage of API credentials using environment variables or secrets managers (AWS Secrets Manager, HashiCorp Vault), IP allowlisting for webhook endpoints, and proper error handling that doesn't expose sensitive information in responses.How much does it cost to send SMS marketing campaigns with Sinch?
Sinch SMS pricing varies by destination country and message volume. Costs typically range from $0.0075 to $0.05 per SMS depending on the country. Marketing campaigns should factor in delivery report costs if using premium features. Visit the Sinch pricing page for detailed rates. For cost optimization, implement message batching, use delivery reports only when necessary, and consider scheduling campaigns during off-peak hours.