Schedules
In the portal: Journeys for a schedule on a delivery. Sequences for a sequence's own default.
What it is
A schedule decides three things about a delivery: when it is due, how often it comes back, and when it stops for good.
It sits on the delivery, not on the journey and not on the content. So the same questionnaire can be a one-off for one participant and a daily habit for another, with no second copy of anything.
Recurrence is the schedule's whole job. If something needs to happen every morning for six weeks, that is one delivery with one schedule, not forty-two nodes and not forty-two deliveries.
What it looks like
Three cadences, told apart by type.
{ "type": "once",
"start": { "type": "instant" },
"end": { "type": "never" } }
{ "type": "weekly", "days": ["MO","WE","FR"], "times": ["08:00","20:00"],
"start": { "type": "instant" },
"end": { "type": "after", "after": 6, "period": "weeks" } }
{ "type": "custom", "every": 3, "period": "days", "times": ["09:00"],
"start": { "type": "after", "after": 1, "period": "weeks" },
"end": { "type": "responses", "maxResponses": 12 } }
When you would use each
once for anything that happens one time: a welcome card, a consent screen, an
end of programme survey. It can still be timed, because start and end work on it.
weekly for anything anchored to days of the week. Weekday check-ins, a Monday
reading, a Sunday reflection.
custom for everything else: every third day, every other week, every four
hours.
The cadences count in hours, days and weeks. To repeat roughly monthly, use custom
with every: 4, period: "weeks", and expect it to drift against the calendar rather
than land on a date. If a programme genuinely needs a date in the month, that is a
conversation to have before the content is written.
The controls
The cadence
| Setting | Applies to | What it accepts | What it does |
|---|---|---|---|
type | all | once, weekly, custom | The cadence. |
days | weekly, and custom with period: "weeks" | any of MO, TU, WE, TH, FR, SA, SU | Which days it is due on. Ignored on any other cadence. Always write it out: with no days, weekly recurs on the one weekday the participant happened to be given it on. |
times | weekly, and custom with period of days or weeks | 24 hour "HH:mm" | Adds slots within a due day. Ignored when period is hours, because an hourly cadence already has its own grid. |
every | custom | a whole number, 1 or more | How many periods between occurrences. Defaults to 1. |
period | custom | hours, days, weeks | The unit every counts in. |
Write the cadence as one of the three names exactly. Anything the recurrence
engine cannot read, including a missing schedule and a misspelled cadence, becomes a
single occurrence starting at the moment of assignment. So when a recurring card
shows once and does not return, check the spelling of type before you look
anywhere else.
A schedule reads only the keys in these tables. Anything else you add saves without an error and has no effect, so check every key you write against the tables here.
The bounds
Every schedule carries both a start and an end. An open bound is written out
rather than left off, so nothing has to be guessed from a missing key.
start is one of:
| Written | Means |
|---|---|
{"type": "instant"} | Available from the moment it is assigned. |
{"type": "after", "after": 2, "period": "weeks"} | Available two weeks after it is assigned. period is days, weeks or months. |
{"type": "at", "at": "2026-10-06T09:00"} | Available from that date and time. |
end is one of:
| Written | Means |
|---|---|
{"type": "never"} | It never stops. |
{"type": "after", "after": 6, "period": "weeks"} | It stops six weeks after it was assigned. |
{"type": "at", "at": "2026-12-01T00:00"} | It stops at that moment. |
{"type": "responses", "maxResponses": 12} | It stops once twelve answers have been submitted, however long that takes. A participant can answer ahead of a day from History, so the count can run out before the calendar does. Where the spread of answers matters as much as the number, say so in the content. |
start and end offsets are measured in days, weeks or months. The shortest
delayed reveal is therefore the next day. For a delay of hours, hand the delivery out
from a later node and gate the arrow into it with secondsInNode.
Dates and times are the participant's own wall clock, written with no timezone on
them. A schedule set for 09:00 fires at nine in the morning wherever the
participant happens to be. It does not shift when they travel and it does not need to
know where they live.
Day boundaries are the participant's local midnight, and daylight saving is handled for you. A clock going back takes the earlier of the two possible moments. A clock going forward moves to the first real moment of that day. Neither loses a day.
How "due" works
A delivery appears on the home screen while it is inside one of its own windows, and not otherwise.
When something is not showing, that is almost always the reason.
Each occurrence has a window, and the window is what decides presence:
| Cadence | One occurrence is | Its window is |
|---|---|---|
once | the single occurrence | the whole span from start to end |
weekly | each chosen weekday | that whole day, in the participant's own time |
custom with period: "days" | each step of the count | the whole step, so every third day means one occurrence to do at some point in those three days |
custom with period: "weeks" | each chosen weekday of an on-count week | that whole day |
custom with period: "hours" | each step of the count | that step |
So a Wednesday check-in is due on Wednesday, and is not on the home screen on
Thursday. Something with a start two weeks out is simply absent until then. Something
whose end has passed is absent afterwards. end is the expiry setting.
Nothing is invented to fill a gap. A period with no occurrence in it produces nothing at all, rather than showing the last one again.
A delivery given part way through a day is not backdated. The first occurrence opens at the moment of assignment rather than at the start of that day, so nothing appears as already missed on the day somebody joins.
What times actually does
times does not gate whether something shows. It splits a due day into separate
things to do.
- With no
times, or one, a due day is one item. - With two or more, a due day is that many items, one per time, and all of them are available all day. A participant can do the evening one at breakfast.
times is what tells a morning entry apart from an evening one in the record. It is
not a lock.
Occurrence references
Every answer is filed against the occurrence it belongs to. The reference format tells you what kind of occurrence it was.
| Reference | Means |
|---|---|
once | The single occurrence of a one-off. |
2026-09-14 | A daily or less frequent occurrence, named by its own date. |
2026-09-14T20:00 | One slot of a day that had several, or an hourly occurrence. |
2026-09-14T20:00:07 | An answer added outside the schedule. |
The last one is the one to recognise. Seconds are what mark an out of schedule
answer, because a scheduled occurrence never has them. Those only exist when the
delivery has unscheduledSubmission switched on.
What stops something coming back
Three separate things can stop an item coming back, and they behave differently.
A time based end. Generation stops. Nothing more is due, ever.
end.maxResponses. A lifetime count across every occurrence. Once that many
answers exist, the delivery is finished, whatever the calendar says.
Submitting today's occurrence. This only clears today. A recurring delivery
whose persistent is off leaves the screen when it is submitted and comes back at
its next occurrence. That is the shape of a daily habit, and it is not the same as
retiring the delivery.
The same applies to dismissing: a dismissed occurrence is hidden, and the next occurrence is not.
persistent decides whether a submitted item stays on screen, and the schedule
does not. persistent: true leaves the item there with a tick until its window
closes. persistent: false takes it away the moment it
is submitted. Both come back at the next occurrence.
Waiting inside a journey
There is a second kind of timing, and it is not a schedule. It is the waiting a journey does between steps.
Two fields carry it, and they are read in a condition on an arrow:
| Field | Counts |
|---|---|
secondsInNode | Seconds since the participant arrived at the node they are on. Resets to zero every time they move. |
secondsInJourney | Seconds since the journey was assigned to them. |
Both are in seconds. An hour is 3600. A day is 86400. A week is 604800.
{ "field": "secondsInNode", "op": "at_least", "value": 604800 }
There is a floor of two seconds. A wait of less than two seconds using at_least
or greater_than is refused when you save, with time_gate_below_floor, on drafts
as well as published journeys. A wait that short is not served reliably and is nearly
always a mistake. The floor does not apply to at_most or less_than, which express
a different idea.
Waits are written in seconds. The two fields are secondsInNode and
secondsInJourney. A day is 86400, so check the number before you publish, and give
the node a second arrow that always fires.
A wait matures while the app is running. The phone arms a timer for the next pending wait and re-runs the journey when it matures, and if the app is not running, the wait matures the next time it is opened. Something set for seven days lands on the participant's next visit after seven days, rather than at midnight on the seventh.
Worked settings
Every weekday for six weeks.
{ "type": "weekly", "days": ["MO","TU","WE","TH","FR"],
"start": { "type": "instant" },
"end": { "type": "after", "after": 6, "period": "weeks" } }
Twice a day, twelve answers and then done.
{ "type": "weekly", "days": ["MO","TU","WE","TH","FR","SA","SU"],
"times": ["08:00","20:00"],
"start": { "type": "instant" },
"end": { "type": "responses", "maxResponses": 12 } }
Two items a day, both available all day, and it retires itself on the twelfth answer rather than on a date.
Something that appears in week three and stays.
{ "type": "once",
"start": { "type": "after", "after": 2, "period": "weeks" },
"end": { "type": "never" } }
Every third day, one item per three day step.
{ "type": "custom", "every": 3, "period": "days",
"start": { "type": "instant" },
"end": { "type": "after", "after": 30, "period": "days" } }
Next
Common patterns puts conditions, actions and schedules together into the twelve shapes that cover nearly everything anybody builds.