Customer-facing schedules: recurrence to delivery
Build the complete schedule path your customers use: local recurrence rules and previews in your UI, durable occurrences in incld, and signed run events delivered to your action handler.
Create with a stable action
const schedule = await incld.schedules.create(
{
action: "generate_report",
payload: { accountId: "acct_42" },
recurrence: {
frequency: "weekly",
interval: 1,
weekdays: ["monday", "friday"],
localTime: "09:00",
timezone: "Australia/Melbourne",
},
timezone: "Australia/Melbourne",
overlapPolicy: "skip",
misfirePolicy: "run_once",
},
{ idempotencyKey: "report-schedule:acct_42" },
)
Framework proxy calls inject externalUserId
and required organization scope. Direct server request paths should construct
Incld
with its organization and user scope option; the API then enforces both identifiers even for direct-ID lookups.
Recurrence variants
| Frequency | Required fields | Optional fields |
|---|---|---|
| once | date, localTime, timezone | — |
| daily | interval, localTime, timezone | startsAt, ends |
| weekly | interval, weekdays, localTime, timezone | startsAt, ends |
| monthly | interval, monthlyMode, localTime, timezone | dayOfMonth for day_of_month, startsAt, ends |
| Monthly mode | Meaning |
|---|---|
| day_of_month | The requested day; dayOfMonth is 1–31. |
| first_monday | First Monday in each selected month. |
| last_friday | Last Friday in each selected month. |
| last_day | Calendar month end. |
End conditions are never,
on_date
with a date, or after_occurrences
with a count.
Timezones and DST
Store an IANA timezone and the user’s intended local time. The recurrence engine computes UTC instants for each occurrence, including daylight-saving transitions. Do not convert a recurring 09:00 schedule into one permanent UTC time.
const preview = await incld.schedules.preview({
recurrence,
count: 10,
from: new Date().toISOString(),
})
// preview.summary and preview.occurrences[].utc/local/label
Overlap and misfire policies
| Policy | Value | Behavior |
|---|---|---|
| overlapPolicy | skip | Do not start a new occurrence while the previous run is still active. |
| overlapPolicy | allow | Create concurrent runs when occurrences overlap. |
| misfirePolicy | skip | Ignore occurrences missed while scheduling was unavailable. |
| misfirePolicy | run_once | Create one recovery run for a missed window. |
| misfirePolicy | catch_up | Create catch-up work according to the platform recovery policy. |
Schedule and run lifecycle
| Resource | States / commands |
|---|---|
| Schedule | active → paused → active; delete moves it to deleted and prevents future runs. |
| Run | scheduled → delivering → succeeded, retrying, failed, cancelled, or skipped. |
| Revision | Increments as schedule configuration changes; each run records scheduleRevision and payloadSnapshot. |
| History | Use schedules.runs(id), schedules.events(id), runs.list(), and runs.get(id). |
Delivery handler guidance
Treat delivery as at least once
event.idempotencyKey
as the deduplication key in your queue or database. The run payload is a snapshot, so later schedule edits do not change already-created work.