Send scheduled notifications

Schedule notifications to reach customers at specific future times—subscription renewal reminders, appointment confirmations, promotional campaigns, or payment due dates. Send to one recipient or broadcast to thousands with a single API call. Messages deliver at or shortly after the scheduled time without requiring you to maintain background workers or cron jobs.


How scheduling works

Scheduled Chimes queue for delivery at a future timestamp you specify. One schedule can reach one recipient or thousands—ideal for broadcast announcements, marketing campaigns, or coordinated reminders. The API validates your message structure immediately but doesn't verify recipient addresses until send time. Invalid recipients fail gracefully without blocking valid deliveries.

Recipients receive messages via SMS, WhatsApp, or email based on address format. Phone numbers route to SMS or WhatsApp, email addresses route to email. All recipients in a single schedule should use the same contact type for optimal delivery tracking.


Schedule a notification

Call POST /chimes/schedule with your message content, recipient list, and delivery timestamp. The API returns a schedule ID immediately—actual delivery happens at the specified time.

Schedule notification

POST
/chimes/schedule
curl https://api.zebo.dev/chimes/schedule \
  -H "Authorization: Bearer YOUR_SECRET_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "recipients": [
      "+233544998605",
      "+233501234567",
      "+233208765432"
    ],
    "full_message": "Reminder: Your subscription renews tomorrow on Dec 18. Update payment method at https://checkout.zebo.dev/billing if needed or contact support.",
    "send_after": "2025-12-17T09:00:00Z",
    "sender_id": "YourBrand",
    "purpose": "subscription_reminder",
    "idempotency_key": "sched_renewal_batch_dec_2025"
  }'

The response confirms your schedule with an ID, recipient count, send time, and creation timestamp. Store the schedule ID if you need to track delivery later or reconcile sent messages with your records.


Recipient validation timing

Recipients aren't validated until send time. If you schedule a notification for 500 customers and 12 phone numbers are invalid, the API doesn't fail the entire schedule—it queues all 500 attempts and logs failures for the 12 invalid numbers when delivery executes.

This design prevents one bad recipient from blocking legitimate deliveries. Check individual Chime delivery status after send time to identify failed recipients and retry with corrected contact information.

Deferring validation until delivery keeps schedule creation fast and predictable. The API accepts your schedule immediately without waiting for format checks or recipient verification. Schedule creation completes in under 100ms regardless of recipient count—whether you're sending to 5 customers or 5,000. Format validation (checking phone number structure, email address syntax) happens at delivery time, when each recipient is processed for sending. Invalid formats fail gracefully without blocking valid recipients in the same schedule.


Delivery timing guarantees

Messages deliver at or shortly after send_after—typically within 1-2 minutes for SMS, up to 5 minutes for email. Exact timing depends on gateway load and recipient carrier processing times. Don't rely on sub-minute precision for scheduled Chimes.

If you need immediate delivery, send a Chime instead. For time-critical notifications like password resets or purchase confirmations, send immediately rather than scheduling.


Broadcast to many recipients

Schedule one message to thousands of recipients with a single API call. Each recipient receives an individual Chime—no shared message threads or group texts. Track each delivery independently through the Chime API.

Broadcast campaign

POST
/chimes/schedule
curl https://api.zebo.dev/chimes/schedule \
  -H "Authorization: Bearer YOUR_SECRET_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "recipients": [
      "+233544998605",
      "+233501234567",
      "+233208765432",
      "+233277654321",
      "+233248888888"
    ],
    "full_message": "Flash Sale! 30% off all items today only. Shop now: https://shop.example.com/sale Use code: FLASH30",
    "send_after": "2025-12-17T08:00:00Z",
    "sender_id": "ShopBrand",
    "purpose": "marketing_campaign"
  }'

The maximum recipients per schedule is 4,096. For larger broadcasts, batch into multiple schedules. Schedule multiple batches a few minutes apart to distribute load and enable partial progress tracking rather than sending all messages at exactly the same second.


Managing scheduled notifications

Tracking execution and delivery

Check schedule status, view delivered message IDs, and identify failed recipients using POST /schedules/lookup. Returns the schedule details plus IDs of all created Chimes after execution. The errors array includes failure reasons for any recipients that didn't receive messages.

Track schedule status

POST
/schedules/lookup
curl https://api.zebo.dev/schedules/lookup \
  -H "Authorization: Bearer YOUR_SECRET_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "schedule_id": "sch_kPvqTrqGsopu07wfC7ttoWqmfwt48ZW7BGvYUWk"
  }'

Before execution, chime_ids is empty and executed_at is null. After execution, chime_ids contains IDs of all successfully created Chimes. Use the Lookup a Chime endpoint with these IDs to check individual delivery status and transmission details. The errors array lists failed recipients with actionable fix codes—invalid phone numbers, blocked recipients, or gateway failures.

Use this to debug broadcast campaigns: if 485 out of 500 messages delivered, the errors array tells you exactly which 15 recipients failed and why. Correct the invalid addresses and create a new schedule for just those recipients.

Canceling pending schedules

Cancel schedules before execution using POST /schedules/cancel. Prevents delivery if called before send_after time. Returns an error if the schedule already executed or was previously canceled.

Cancel schedule

POST
/schedules/cancel
curl https://api.zebo.dev/schedules/cancel \
  -H "Authorization: Bearer YOUR_SECRET_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "schedule_id": "sch_kPvqTrqGsopu07wfC7ttoWqmfwt48ZW7BGvYUWk"
  }'

Common cancellation scenarios: customer opts out of marketing before campaign sends, you discover an error in the message content, or a scheduled event gets postponed. Cancel the original schedule and create a new one with corrected details.

Cancellation only works on pending schedules—you can't cancel schedules that already executed. The operation is idempotent, so retrying a cancellation is safe and returns the same result.


Using idempotency keys

Prevent duplicate schedules during network failures or retries by providing an idempotency_key. If your server crashes after scheduling but before recording the schedule ID, retry with the same key—the API returns the original schedule instead of creating a duplicate.

// First attempt - succeeds but network fails before you save schedule ID
await client.chimes.schedule({
  recipients: customerPhones,
  full_message: 'Your order ships tomorrow',
  send_after: tomorrowAt9AM,
  idempotency_key: 'ship_notif_order_12345',
})

// Retry with same key - returns original schedule, doesn't create duplicate
const { scheduled_chime } = await client.chimes.schedule({
  recipients: customerPhones,
  full_message: 'Your order ships tomorrow',
  send_after: tomorrowAt9AM,
  idempotency_key: 'ship_notif_order_12345', // Same key
})

// Save schedule ID to your database
await db.orders.update(orderId, {
  notification_schedule_id: scheduled_chime.id,
})

Construct idempotency keys from stable identifiers like order IDs, campaign IDs, or subscription IDs plus the notification type—ship_notify_order_${orderId} or renewal_remind_sub_${subId}.


Next steps

Was this page helpful?