Scheduled Delivery
Send at a specific date and time
Time Zone Support
Respect each user's local time
Recurring Patterns
Cron-based daily, weekly, monthly
Cancellation
Cancel or pause scheduled sends
Overview
Notification scheduling lets you queue notifications for future delivery instead of sending them immediately. Schedule one-time notifications for a specific moment, or set up recurring patterns like daily digests and weekly summaries. Combined with time zone support, you can ensure every user receives notifications at the right local time regardless of where they are.
Quick Start
Schedule a notification for future delivery with a single API call:
import { platform } from '@/lib/platform'
// Schedule a notification for a specific time
const schedule = await platform.notifications.schedule({
userId: user.id,
title: 'Weekly Summary',
body: 'Your stats this week',
sendAt: new Date('2026-02-07T09:00:00Z'),
timezone: 'America/New_York',
})
// Returns a schedule ID for tracking and cancellation
console.log(schedule.id) // "sched_a1b2c3d4"
console.log(schedule.scheduledFor) // "2026-02-07T14:00:00Z" (adjusted for EST)Time Zone Handling
timezone: 'local', the platform automatically resolves each user's time zone from their profile. If no time zone is set for a user, it falls back to UTC.Time Zone Support
Deliver notifications at the right time for each user, regardless of their location. The platform supports three timezone modes:
Explicit Time Zone
Specify an IANA time zone like America/New_York or Europe/London. The sendAt time is interpreted in that zone.
User Local Time
Set timezone: 'local' to use each user's stored time zone. A “9 AM” notification arrives at 9 AM local time for every user.
UTC (Default)
Omit the timezone field or set it to UTC. The notification sends at the exact UTC time specified.
// Explicit timezone - all users get it at 9 AM EST
await platform.notifications.schedule({
userId: user.id,
title: 'Meeting Reminder',
body: 'Team standup in 15 minutes',
sendAt: new Date('2026-02-07T09:00:00'),
timezone: 'America/New_York',
})
// User-local timezone - 9 AM in each user's own timezone
await platform.notifications.schedule({
userId: user.id,
title: 'Good Morning',
body: 'Start your day with a quick review',
sendAt: new Date('2026-02-07T09:00:00'),
timezone: 'local',
})
// UTC - sends at exactly 14:00 UTC regardless of user location
await platform.notifications.schedule({
userId: user.id,
title: 'System Maintenance',
body: 'Scheduled maintenance window',
sendAt: new Date('2026-02-07T14:00:00Z'),
})Daylight Saving Time
Recurring Notifications
Set up recurring notifications with cron expressions. Recurring schedules continue until explicitly cancelled or paused.
// Daily digest at 9 AM in each user's timezone
await platform.notifications.scheduleRecurring({
segment: 'active_users',
title: 'Daily Digest',
body: 'Here is your daily summary',
cron: '0 9 * * *',
timezone: 'local',
})
// Weekly summary every Monday at 10 AM UTC
await platform.notifications.scheduleRecurring({
segment: 'all_users',
title: 'Weekly Summary',
body: 'Your week in review',
cron: '0 10 * * 1',
timezone: 'UTC',
})
// Monthly report on the 1st at 8 AM
await platform.notifications.scheduleRecurring({
segment: 'premium_users',
title: 'Monthly Report',
body: 'Your monthly analytics report is ready',
cron: '0 8 1 * *',
timezone: 'local',
// Optional: dynamic body template
template: 'monthly_report',
})| Cron Pattern | Description |
|---|---|
| 0 9 * * * | Daily at 9:00 AM |
| 0 9 * * 1 | Every Monday at 9:00 AM |
| 0 9 1 * * | First day of each month at 9:00 AM |
| 0 9 * * 1-5 | Weekdays at 9:00 AM |
| 0 */6 * * * | Every 6 hours |
| 0 9,18 * * * | Twice daily at 9:00 AM and 6:00 PM |
Cron Format
minute hour day-of-month month day-of-week. The minimum interval is 1 hour to prevent notification fatigue.Cancellation
Cancel or pause scheduled notifications at any time. Both one-time and recurring schedules support full lifecycle management.
// Cancel a one-time scheduled notification
await platform.notifications.cancelScheduled(scheduleId)
// Cancel a recurring schedule (stops all future deliveries)
await platform.notifications.cancelScheduled(recurringId)
// Cancel all scheduled notifications for a user
await platform.notifications.cancelAllScheduled({
userId: user.id,
})Cancellation Window
Delivery Modes
One-time
Send at a specific date and time
sendAt: new Date("2026-02-07T09:00:00Z")Recurring
Repeat on a cron schedule
cron: "0 9 * * *"Time Zone Aware
Deliver at the right time for each user's locale
timezone: "America/New_York"Immediate
Send right now (default behavior)
No sendAt requiredBest Practices
Respect Quiet Hours
Avoid sending between 10 PM and 8 AM in the user's local time. Use timezone: "local" to ensure compliance.
Batch Recurring Sends
For recurring notifications to segments, the platform batches deliveries to avoid overwhelming your infrastructure.
Set Expiration Windows
Time-sensitive notifications should include an expiry so they are not delivered if the window passes.
Monitor Delivery Metrics
Track delivery rates, open rates, and failure counts to optimize send times and content.
Pause During Incidents
Use the pause API to halt non-critical recurring notifications during incidents or maintenance.
Use Templates for Recurring
Recurring notifications with dynamic content should use templates that resolve at delivery time.
API Reference
notifications.schedule()
| Property | Type | Description |
|---|---|---|
userIdrequired | string | Target user ID for the notification |
titlerequired | string | Notification title |
bodyrequired | string | Notification body content |
sendAtrequired | Date | When to deliver the notification |
timezone | string= "UTC" | IANA timezone, "local" for user timezone, or "UTC" |
data | Record<string, unknown> | Custom payload attached to the notification |
expiresAt | Date | Do not deliver after this time. Useful for time-sensitive notifications. |
channel | "push" | "email" | "in_app" | "sms"= "push" | Delivery channel |
notifications.scheduleRecurring()
| Property | Type | Description |
|---|---|---|
segmentrequired | string | Target user segment key |
titlerequired | string | Notification title |
bodyrequired | string | Notification body content |
cronrequired | string | Cron expression (5-field format, minimum 1 hour interval) |
timezone | string= "UTC" | IANA timezone, "local" for per-user timezone, or "UTC" |
template | string | Template key for dynamic content resolved at delivery time |
startsAt | Date= now | When the recurring schedule becomes active |
endsAt | Date | When the recurring schedule stops automatically |
Management Methods
| Method | Description |
|---|---|
| notifications.cancelScheduled(id) | Cancel a scheduled or recurring notification |
| notifications.cancelAllScheduled(opts) | Cancel all schedules for a user |
| notifications.pauseSchedule(id) | Pause a recurring schedule |
| notifications.resumeSchedule(id) | Resume a paused recurring schedule |
| notifications.getSchedule(id) | Get schedule details and delivery history |
| notifications.listSchedules(opts) | List schedules with status and user filters |