Dates and scheduling
The date on a campaign draft is a calendar anchor, not a send time — nothing is scheduled from the API. This page covers the three accepted date forms, which timezone each one is read in, the separate time field, and why unparseable input is refused rather than guessed at.
date places a campaign draft on the dashboard calendar so a marketer opening the project can see what is coming and when it was meant to go out. It is a planning anchor, and setting it arms nothing.
date is also entirely optional: omit it and the draft simply carries no date, which is the right choice when your integration knows what to say but not yet when.
The three accepted forms
The precision you send is the precision that is stored — and the input decides which timezone applies:
| Form | Example | Interpreted in |
|---|---|---|
| ISO 8601 with an offset | 2026-06-15T09:30:00+02:00, 2026-06-15T09:30:00Z, 2026-06-15T09:30+0200 | the offset you sent — the project's timezone is not consulted |
| Date and time, no offset | 2026-06-15T09:30, 2026-06-15 09:30 | the project's timezone |
| Day only | 2026-06-15 | the project's timezone, at 19:00 |
The project's timezone falls back to the organization's when the project does not set one of its own.
Integrations should send the offset form
{
"date": "2026-06-15T09:30:00+02:00"
}It is the only form that means the same instant on both ends. A server in another region, a container running in UTC, a laptop on summer time — none of them change what that string denotes. The two offset-less forms are a convenience for a human typing a date into your UI, where "half past nine" naturally means half past nine where the audience lives; they are the wrong choice for a machine that already knows the exact moment.
Sending the time separately
Some callers hold the day and the time apart — a date picker and a time picker, two columns in a spreadsheet — and joining them into an ISO string is busywork. time exists for exactly that:
{
"date": "2026-06-15",
"time": "09:30"
}time is HH:MM, read in the project's timezone, and it replaces the 19:00 default a bare day would otherwise get.
Parsing is strict on purpose
The accepted forms above are an allow-list. Anything else is refused with invalid-date rather than interpreted:
| Input | Why it is refused |
|---|---|
15/06/2026 | Ambiguous. Depending on the separator and locale it reads as day 15 or month 15 — an API that silently picks one is worse than one that says no. |
tomorrow, +1 week | Relative expressions are not dates. Resolve them on your side, where you know the user's timezone. |
2026-13-45 | Out of range. It is not rolled over into February of the following year. |
2026-06-15T25:99 | Out of range. It is not rolled over into the next day. |
The overflow cases are the ones worth designing around: a caller that computed a date wrongly gets told, at the moment of the call, instead of finding a campaign anchored on a day nobody chose.
The one-year horizon
A campaign date must be less than a year from now. A date beyond that is understood perfectly well and then refused by the campaign itself, so it comes back as a field-level 422 keyed by the campaign's own field name (campaignAt) rather than as an invalid-date code:
{
"errors": {
"fields": {
"campaignAt": ["This value should be less than Jun 15, 2027, 12:00 AM."]
}
}
}Scheduling the actual send
The send time is chosen in the dashboard, on the campaign's Review & schedule step, along with the delivery settings that surround it. The reader-facing walkthrough is Creating a campaign; Delivery settings covers the options that shape how the send runs once it is armed.
For an integration this means the handover is clean: you supply the intent — who, what, and the day it is meant for — and a person supplies the confirmation.