Check environment and feature availability before following this guide.
schedule.send_at is the earliest a scheduled message can go.
delivery_conditions can hold it past that moment until the conditions are met, up to a
deadline you choose.
Once the message is due, the evaluator checks the conditions every minute. While they hold it
back the status stays
scheduled, and each check is recorded in GET /v1/queue-executions as a
constraint_check with result: "deferred" and the reasons in error_message, for example
outside time window 09:00–17:00 (Europe/Brussels).
Time windows
The zone is the condition’s own
timezone, otherwise the message’s schedule.timezone,
otherwise UTC. A window may cross midnight: "start": "22:00", "end": "06:00" covers the evening
of a listed day and the small hours that follow it.
The deadline
max_delay_at in the response is send_at + max_delay_minutes, the moment the wait ends. It is
null when there is no max_delay_minutes. The evaluator recomputes it when you reschedule,
and each occurrence of a recurring message gets its own.
When max_delay_at passes and the conditions still do not hold:
on_miss: "send", or noon_missat all: the message is sent at that tick regardless.on_miss: "expire": the message becomesexpired, a terminal status, witherror_messagestartingexpired:followed by the reasons, and nothing is sent. The execution log records aconstraint_checkwithresult: "failed".
expired cannot be rescheduled or sent; schedule a new one.
Changing the conditions
PATCH /v1/scheduled-messages/{id} with a new delivery_conditions replaces the whole object;
with "delivery_conditions": null it removes the hold. POST …/send-now removes the conditions
and the deadline as well as making the message due, so it goes on the next tick.

