Frequently Asked Questions
Use the Sinch SMS API's send_at parameter within the @sinch/sdk-core Node.js SDK. Provide the recipient's number, message content, and the desired send time in UTC ISO 8601 format. Sinch's system handles the scheduling and sending, eliminating the need for local scheduling libraries or background processes for the sending mechanism.
The Sinch SMS API allows developers to integrate SMS messaging into applications. In this example, it schedules and sends appointment reminders, demonstrating its reliability and robustness for a production-ready reminder system.
Sinch API credentials authenticate your application, authorizing it to access and utilize Sinch's services like sending SMS messages. These credentials include Project ID, Key ID, and Key Secret, which are vital for secure communication between your app and Sinch. Never expose the secret key publicly.
Luxon is especially useful when working with dates and times in different time zones, as it provides robust tools for managing and converting between them. It's crucial for accurately scheduling reminders using Sinch's send_at parameter, which requires UTC ISO 8601 format.
Session storage is inadequate for production as data is lost upon server restart. For scheduled jobs, persistent storage like a database (PostgreSQL, MySQL, MongoDB) is essential for maintaining appointment details.
You need Node.js, npm or yarn, a Sinch account with API credentials, a verified recipient number for initial testing, and basic familiarity with Node.js, Express, JavaScript, HTML, REST APIs.
Install the official Sinch Node.js SDK using npm with the command: npm install @sinch/sdk-core. This package provides the necessary functions for interacting with Sinch's services, including SMS.
The .env file stores sensitive information, like your Sinch API credentials and database connection strings. Dotenv loads these variables into process.env. Never commit this file to version control.
The user submits appointment data through a web form. The Node.js/Express app processes the data, using the Sinch SMS API to schedule a reminder. Sinch then sends the SMS at the designated time to the patient.
Environment variables offer a secure method to store sensitive information like API keys without directly embedding them in your code. This protects your credentials and makes it easy to manage configurations across different environments (development, testing, production).
While the example shows basic formatting, for production use a library like libphonenumber-js to validate and format phone numbers reliably into E.164 format, essential for international compatibility with Sinch.
Express.js acts as the web framework, handling routing, requests, and responses, serving static files like HTML and CSS, allowing us to create web applications easily using Node.js.
Create directories for public assets (CSS, JS), views (EJS templates), and routes. Configure app.js as the entry point, handling middleware, and routes.js for request processing.
Always use a database for production reminder systems. Databases (like PostgreSQL, MySQL, or MongoDB) persist data across sessions and server restarts, ensuring the reminders are sent as scheduled even if there are interruptions or downtime.
The send_at parameter in the Sinch SMS API lets you specify when to send the SMS message in the future. It's essential for scheduling reminders and must be in UTC ISO 8601 format.
Learn how to build a production-ready SMS appointment reminder system using Sinch SMS API, Node.js, and Express. This comprehensive guide shows you how to schedule SMS messages with the
send_atparameter—no cron jobs or background workers required. Sinch handles all message scheduling server-side, simplifying your infrastructure.The hospital appointment reminder example adapts to multiple use cases:
Sinch's built-in scheduling eliminates complex local scheduling libraries and persistent background processes. The API handles message delivery server-side, reducing your infrastructure complexity.
Prerequisites:
Environment:
Sinch Account & Credentials:
Dependencies:
@sinch/sdk-corev1.2.1@sinch/smsv1.2.1Technical Knowledge:
Source: Sinch Node.js SDK npm repository (@sinch/sdk-core v1.2.1, @sinch/sms v1.2.1); Node.js LTS release schedule; Sinch SMS API documentation (send_at parameter accepts ISO 8601 format, defaults to UTC if no offset specified)
What You'll Build:
send_atparameterSystem Architecture:
send_atparameter to schedule deliverysend_attimestamp1. Project Setup: Installing Sinch Node.js SDK and Dependencies
Create Project Directory:
Initialize Node.js Project:
Create Project Structure:
.env: Environment variables (API keys, secrets) – never commit to Git.gitignore: Files and folders Git should ignoreapp.js: Express application entry pointroutes.js: Application routing and request logicpublic/: Static assets (CSS, JavaScript, images)views/: EJS templatesInstall Dependencies:
express: Web framework for Node.js@sinch/sdk-core: Official Sinch Node.js SDKdotenv: Loads environment variables from.envluxon: Date/time library (v3.7.2) with native timezone supportexpress-session: Session management middlewareconnect-flash: Temporary message display middlewareejs: HTML templating engineNote: Avoid
sessionstorage-for-nodejsin production – data is lost on server restarts. Useexpress-sessionfor temporary data and a database for persistent storage (see Section 6).Source: Luxon npm package (v3.7.2); Luxon documentation (native timezone support)
Install Development Dependency:
Configure
.gitignore:Configure Environment Variables (
.env):Replace placeholder values with your actual credentials. Generate
SESSION_SECRETusing a cryptographically secure method:KEY_ID,KEY_SECRET,PROJECT_ID: Access Keys page in Sinch Customer Dashboard (treat Secret like a password)FROM_NUMBER: SMS-enabled virtual number from Sinch (E.164 format required)SMS_REGION: Sinch API region (us,eu) affecting endpoints and compliancePORT: Express application portSESSION_SECRET: Cryptographically secure random string (32+ bytes) for session cookie signingDEFAULT_COUNTRY_CODE: Prepends country code to phone numbers without oneSet Up
nodemonScript:Run
npm run devto start the development server.Configure Application Entry Point (
app.js):Key configurations:
dotenv.config()express.staticandexpress.urlencodedmiddlewareexpress-sessionwith 1-hour cookie lifetimesecure(HTTPS-only),httpOnly(XSS prevention),sameSite(CSRF protection)res.localsroutes.jsPORTSource: Express security best practices documentation (secure cookies require HTTPS, httpOnly prevents client-side JS access, sameSite provides CSRF protection)
2. Implementing SMS Scheduling with Sinch send_at Parameter
The Sinch SMS API's
send_atparameter is the key to serverless SMS scheduling. It accepts an ISO 8601 UTC timestamp and handles all message delivery server-side. When you make the API call, Sinch stores the message in a queue and automatically sends it at the specified time—no cron jobs, no background workers, no node-cron library needed. This architecture dramatically simplifies scheduled SMS implementation compared to traditional polling-based systems..envwith validation for missing variablesscheduleReminderFunction: Calls the Sinch API (sinchClient.sms.batches.send) with UTC ISO 8601 forsend_at/: Redirects to appointment form/appointment(GET): Renderspatient_details.ejs/appointment(POST):scheduleReminderto schedule via Sinch/success(GET): Retrieves and displays confirmation from session, then clears temporary data3. Building the Appointment Scheduling Interface
Create HTML forms for user interaction using EJS templates.
views/patient_details.ejs:views/success.ejs:public/css/style.css:4. Sinch SMS API Integration and Credentials Setup
Integration happens primarily in
routes.js:.envSinchClientinstantiated using Project ID, Key ID, Key Secret, and RegionscheduleReminderfunction usessinchClient.sms.batches.send, passing recipient (to), sender (from), message body, and thesend_atparameter (UTC ISO 8601 timestamp)Obtaining Credentials:
Key IDandKey Secret– the Secret is only shown once. Store these securely in your.envfile.env+1xxxxxxxxxx) and add it asFROM_NUMBERin.envus,eu, etc.) associated with your service plan/project and setSMS_REGIONin.env5. Production Error Handling and Logging Best Practices
The current implementation includes basic error handling:
routes.jschecks for essential Sinch variables on startup and exits if missingscheduleReminderfunction usestry...catcharoundsinchClient.sms.batches.send, logs errors, and returns failure status/appointmenthandler, with flash messages for user feedbacktry...catchin POST/appointmenthandler catches unexpected errors during processingconsole.logandconsole.errorwith consistent formattingProduction Enhancements:
Structured Logging: Use
winstonorpinofor structured JSON logsReplace
console.log/console.errorwith logger instances (e.g.,logger.info(),logger.error()). Configure transports to write logs to files or external logging services.Detailed API Error Parsing: Check
error.response.datafrom Sinch API errors for specific error codes to provide more informative feedback or trigger specific actions (e.g., retries for transient network issues)Centralized Error Handling Middleware: Implement more robust Express error-handling middleware in
app.jsto catch unhandled errors gracefullyRetry Mechanisms: For transient network errors, consider implementing a simple retry strategy (1-2 retries with short delay). However, since Sinch handles the sending schedule, retrying the scheduling call might result in duplicate scheduled messages if the first call succeeded but the response was lost. Log failures and alert administrators instead.
6. Database Persistence for Scheduled SMS Appointments
Using only
express-sessionis NOT persistent storage. Scheduled jobs require data that survives server restarts and deployments. If the server restarts between scheduling via the API and rendering the success page (or if the user's session expires), confirmation data will be lost. The application has no record of scheduled appointments after server restarts.A database is mandatory for production.
Conceptual Database Schema (PostgreSQL or MySQL):
Data Layer Implementation Steps:
npm install pg(driver) ornpm install sequelize/npm install @prisma/client(ORMs)npm install mysql2(driver) ornpm install sequelize/npm install @prisma/client(ORMs)npm install mongodb(driver) ornpm install mongoose(ODM)routes.js:/appointmenthandler, after successfully scheduling with Sinch (scheduleResult.success), save appointment details (includingpatientName,doctorName,formattedPhone,appointmentDateTimeLocal.toJSDate(),reminderDateTimeLocal.toJSDate(),scheduleResult.batchId) to databasereq.session.appointmentId = newAppointmentRecord.id/successhandler, retrieveappointmentIdfrom session and query database for full appointment details. Rendersuccess.ejsusing database data. Clearreq.session.appointmentIdafterwardslibphonenumber-jsbefore saving to database and sending to Sinch. Ensure numbers are stored consistently (E.164 format).This ensures appointment data persists reliably even after application restarts, providing a foundation for future features like viewing scheduled appointments, cancellation, or status tracking.
Frequently Asked Questions
How does Sinch SMS scheduling work with the send_at parameter?
The Sinch SMS API's
send_atparameter accepts an ISO 8601 timestamp in UTC format. When you include this parameter in your API call, Sinch stores the message and automatically sends it at the specified future time. You don't need local cron jobs or background workers – Sinch handles the entire scheduling mechanism server-side.What version of the Sinch Node.js SDK should I use for SMS scheduling?
Use
@sinch/sdk-corev1.2.1 and@sinch/smsv1.2.1 (latest as of January 2025). These versions provide full support for thesend_atscheduling parameter and are compatible with Node.js v16+ (v18 or v20 LTS recommended for production as of 2025).How do I handle timezones when scheduling SMS reminders with Luxon?
Luxon (v3.7.2) provides native timezone support. Parse user input in local time with
DateTime.fromISO(), perform calculations (like subtracting 2 hours for reminders), then convert to UTC using.toUTC().toISO()before sending to Sinch. Always store appointment times with timezone information (TIMESTAMPTZ in PostgreSQL) for accurate scheduling across regions.Why is express-session not suitable for production appointment storage?
The default MemoryStore for express-session loses all data when your server restarts, which means scheduled appointments would be lost. For production, you must use a persistent database (PostgreSQL, MySQL, MongoDB) to store appointment details. Use express-session only for temporary data like flash messages or passing confirmation IDs between requests.
What secure cookie settings should I use for Express session in production?
Enable three critical security options:
secure: true(HTTPS-only cookies),httpOnly: true(prevents XSS attacks by blocking client-side JavaScript access), andsameSite: 'strict'(CSRF protection). Also setapp.set('trust proxy', 1)if running behind a load balancer or reverse proxy.Can I schedule SMS messages more than 24 hours in advance with Sinch?
Yes, Sinch supports scheduling SMS messages days or even weeks in advance using the
send_atparameter. There's no documented hard limit, but for very long-term scheduling (months), consider storing appointments in your database and implementing a daily or weekly job to schedule upcoming reminders within a reasonable window (e.g., 7 days ahead).How do I validate international phone numbers before sending to Sinch?
Use the
libphonenumber-jslibrary for robust phone number validation:npm install libphonenumber-js. Parse numbers withparsePhoneNumber(input, defaultCountry), validate with.isValid(), and format to E.164 using.format('E.164'). This ensures all numbers are correctly formatted (e.g.,+442071234567) before sending to Sinch.What happens if my Express server restarts after scheduling an SMS?
If you only store appointment data in
express-session, it's lost on restart. However, the SMS message itself is already scheduled with Sinch's servers and will send at the specified time. For production reliability, persist all appointment details (including Sinch batch IDs) to a database so you can track, modify, or cancel scheduled messages even after server restarts.How do I cancel or update a scheduled SMS reminder in Sinch?
Use the Sinch batch ID returned when scheduling (stored in
response.id) to modify or cancel messages. CallsinchClient.sms.batches.update()with the batch ID to change the message or send time, orsinchClient.sms.batches.cancel()to prevent delivery. Store batch IDs in your database alongside appointment records for full management capabilities.Example:
What database schema should I use for storing scheduled appointment reminders?
Create an
appointmentstable with:id(primary key),patient_name,doctor_name,patient_phone(E.164 format),appointment_datetime(TIMESTAMPTZ in UTC),reminder_datetime(TIMESTAMPTZ in UTC),sinch_batch_id(unique, for tracking),status(scheduled/sent/failed/cancelled), andcreated_at/updated_attimestamps. Add indexes onpatient_phoneandappointment_datetimefor efficient queries.