Scheduling
Send a notification later, at a time with its offset. A Workflow holds it through deploys until then.
Schedule a send
schedule() takes everything send() does, plus the time to send at:
const { scheduledId, op } = await env.CHASKI.schedule({
type: 'invoice_due',
recipient: { id: user.id, email: user.email },
payload: { invoice: 'INV-1042' },
scheduledAt: '2026-11-01T09:00:00-05:00',
// Scheduling the same key again moves the pending send instead of adding one.
idempotencyKey: 'invoice-due:INV-1042',
});scheduledAt is an ISO 8601 time with an explicit offset, Z or ±hh:mm. A time without one would
name a different instant in every timezone, so Chaski rejects it rather than guess. A time in the
past is rejected too, with five minutes of grace for clock skew.
When the time comes, the send runs as if you had called send() then: the contact’s
preferences and the template are read at that moment, with the recipient and payload you
scheduled.
Move a schedule
With an idempotencyKey, scheduling again updates the pending send instead of adding a second one.
Derive the key from what the notification is about, never from the time, so a new time moves it.
op in the result says what happened:
op | Meaning |
|---|---|
created | A new schedule. |
updated | The pending schedule with this key moved to the new time and content. |
completed | The schedule with this key already went out; nothing changed. |
cancelled | The new time is already past, so the pending schedule was retired instead of firing late. |
Cancel
Cancel by the schedule’s id, its idempotencyKey, or a groupKey you gave several schedules:
await env.CHASKI.schedules().cancel({ idempotencyKey: 'invoice-due:INV-1042' });
// Every pending reminder for one trial, scheduled with groupKey: `trial:${trial.id}`.
await env.CHASKI.schedules().cancel({ groupKey: `trial:${trial.id}` });The result says how many pending schedules it cancelled.
List what’s pending
const pending = await env.CHASKI.schedules().list({ recipientId: user.id });list() returns pending schedules, soonest first, for one recipient or for everyone. The
Schedules page in the dashboard shows the same list, and cancels from there too.
Updated Oct 30, 2026
MIT License · chaski.sh