Skip to main content

Schedules

A schedule runs one or more validations automatically — every weekday at 06:00, hourly, on the first of the month — so your checks keep pace with the data as it lands. Each time a schedule fires it starts one execution run per validation, exactly as if you had pressed Run on each of them.

You manage schedules on the validations they run: open a validation and use its Schedule card. It lists every schedule that runs the validation. When a schedule also runs other validations, the Also runs column names them. To schedule a data asset, use Schedule this asset on the asset's page. It opens the asset's default validation, which holds all of the asset's rules, at its Schedule card. The Validations page's Schedule tab shows every validation's past and upcoming runs on one calendar.

What a schedule holds​

FieldWhat it means
ValidationsThe validations it runs, 1 to 50, all in the same workspace. Each firing starts one run of each.
CadenceA standard 5-field cron expression (minute, hour, day of month, month, day of week). You never type it in the app: the schedule builder writes it for you.
TimezoneThe IANA zone the cadence is read in (Europe/London, America/New_York, …). A new schedule always takes the organization's schedule timezone. The form shows it but doesn't ask for it.
EnabledPaused schedules keep their settings but stop starting runs.
TeamOptional. By default a schedule takes its validations' team: the team of a team-restricted validation, or a team all of its validations share. Otherwise it is workspace-shared.

A schedule can't mix team-restricted work. A validation restricted to a team shares a schedule only with that team's validations and workspace-shared ones, and the schedule must belong to that team. Otherwise saving is refused with a 422. Team labels without a restriction never conflict.

The schedule builder​

Add schedule opens a builder with plain-language presets — no cron knowledge needed:

PresetYou chooseExample cron
Every N minutes1–59 minutes*/15 * * * *
Every N hours1–23 hours and a minute offset30 */4 * * *
Hourlythe minute past the hour15 * * * *
Daily at a timehour and minute0 6 * * *
Weekly on daysweekdays and a time0 9 * * 1-5
Monthly on a dayday of month and a time0 9 1 * *

A live preview reads the cadence back in plain English ("Runs 9:00 AM Mon–Fri") before you save. Editing a schedule re-opens it in the matching preset.

Anything the presets can't express (for example, only certain months) can still be scheduled: send any 5-field cron expression through the API. The app shows such a schedule as a read-only custom cadence with its plain-English summary, and saving an edit leaves the expression untouched unless you switch it to a preset. The schedules table never shows a raw cron expression: every cadence reads in words ("Every day at 8:00 AM"), and one the app can't put into words reads Custom cadence, with the expression behind its ℹ️.

Timezones and daylight saving​

Your organization has one schedule timezone, set by an org admin in Settings → Scheduling (Set the schedule timezone). It is UTC until an admin sets one.

  • Every new schedule runs in it. "Every day at 06:00" means 06:00 in that zone. The schedule form shows the zone, with a link to Settings, instead of asking for one.
  • Every schedule time is shown in it, not in your browser's zone. That covers the schedules table's Next run, the Validations list's next run, and the calendar. Each time carries the zone's abbreviation, for example Sep 16, 09:00 EDT. So everyone in the organization reads the same times.

The cadence is evaluated in the schedule's timezone, so 0 9 * * MON-FRI in America/New_York fires at 09:00 New York time all year. You don't retune anything when the clocks change. Unknown zone names are rejected when you save.

Around a daylight-saving change, a time that doesn't exist (spring forward) fires at the change, and a time that happens twice (fall back) fires twice. If a job must avoid those hours, schedule it outside them.

Schedules saved in another timezone​

Changing the organization timezone never moves an existing schedule on its own, so nothing starts firing at a different time without warning. A schedule saved in another zone keeps running in it. That happens to a schedule created before the setting existed (the form used to default to your browser's zone), and to one created through the API with an explicit timezone. Such a schedule is flagged:

  • The schedules table's Timezone column shows its zone with a Not the org timezone badge.
  • Its edit form says which zone it runs in and offers Run it in <org zone> from now on. Tick it and save to move that one schedule.
  • Settings → Scheduling counts these schedules by zone, and an org admin can Move N schedules onto the organization zone at once. That asks for confirmation first, and it needs a zone an admin has saved (it stays disabled on the UTC default). The audit log records the zone each moved schedule ran in before.

A moved schedule keeps its cadence. Only its zone changes, and its next run is recalculated in the new zone.

A schedule whose stored zone is blank or not a recognised zone (a very old or hand-edited schedule) runs in UTC, whatever the organization zone is. Settings → Scheduling lists it under its stored value, and the calendar plots it in UTC.

The calendar​

Validations → Schedule shows a month calendar of runs across your validations: past runs tinted by outcome (passed / failed) and upcoming scheduled runs marked Scheduled. A schedule that runs several validations shows one upcoming run per validation. The whole calendar is in the organization's schedule timezone, which it names above the grid: its days, "today", the Day view's times, and each schedule's next run. Each time is labelled with the zone abbreviation ("9:00 AM EDT"). A schedule still saved in another zone is read in its own zone and placed at the matching organization time, and its legend row names the zone it runs in. Weekday and month names, ranges, steps, and the @daily / @hourly / @weekly / @monthly / @yearly shorthands all expand; a cron using L, W, or # shows only its next run.

Operations you can do​

  • Add: on the validation's Schedule card, click Add schedule. Pick a cadence, then click Save. The schedule runs in the organization's schedule timezone. Use Also run to add other validations to the same schedule.
  • Edit: the pencil icon re-opens the schedule with its cadence and its Validations. Add or remove validations there. A validation you remove stops running from the next firing. Saving keeps the schedule's id and history, and its timezone, unless you tick Run it in <org zone> on a schedule saved in another zone.
  • Pause / resume — stop new runs without deleting anything. Runs already in progress finish.
  • Run now — start a run of each of its validations immediately, outside the cadence.
  • Delete — removes the schedule. Past runs and their results are kept.

Deleting a validation takes it off every schedule that runs it. A schedule that ran only that validation is deleted with it. A schedule that runs other validations keeps running them.

Adding, editing, and pausing schedules needs the editor role or higher. Everyone can see them.

How a scheduled run starts​

A worker job checks every minute for schedules that are due. For each due schedule, it starts one execution run per validation, through the same path as a manual Run. Then it moves the schedule's next run time forward once. Each run records the schedule and the trigger schedule. Scheduled runs appear in each validation's Execution runs card and on the Results page like any other run. They trigger alerts the same way, and each one counts toward the monthly run quota.

If one of the validations can't run at that moment, it is skipped and the others still run. That happens when all of its rules are disabled or its assets are gone. A firing is never started twice: if the worker retries a firing, it finds the runs the firing already started.

Older schedules were bound to a checkpoint. Checkpoints are retired, and a legacy checkpoint schedule nobody edited keeps firing: it runs the validation its checkpoint maps to. A checkpoint that maps to no validation can't run any more, so its schedule is skipped at each firing (the worker logs schedule_checkpoint_unmapped); point the schedule at a validation to bring it back.

API​

GET /api/v1/organizations/{org_id}/workspaces/{ws_id}/schedules
POST /api/v1/organizations/{org_id}/workspaces/{ws_id}/schedules
POST /api/v1/organizations/{org_id}/workspaces/{ws_id}/validations/{validation_id}/schedules
PATCH /api/v1/organizations/{org_id}/workspaces/{ws_id}/schedules/{schedule_id}
DELETE /api/v1/organizations/{org_id}/workspaces/{ws_id}/schedules/{schedule_id}
GET /api/v1/organizations/{org_id}/schedule-timezone
PUT /api/v1/organizations/{org_id}/schedule-timezone
  • Create. POST .../schedules takes {"validation_ids": ["…", "…"], "cron_expression": "0 6 * * *", "enabled": true}. POST .../validations/{validation_id}/schedules takes the same body with validation_ids optional. Any IDs you pass there run alongside the path's validation.
  • Timezone. Leave timezone out and the schedule runs in the organization's schedule timezone. An explicit IANA timezone on create or PATCH is still accepted for backward compatibility. A schedule saved that way is flagged in the app while its zone differs from the organization's.
  • The organization timezone. GET .../schedule-timezone (any member) returns {"data": {"timezone", "source", "mismatched_schedules", "schedule_timezones", "aligned_schedules"}}. PUT .../schedule-timezone with {"timezone": "America/New_York"} sets it; add "align_schedules": true to also move every schedule in another zone onto it. The PUT needs an org admin. See Set the schedule timezone.
  • Change the validations. PATCH with validation_ids replaces the list. Omit it to leave the list unchanged.
  • Filter. GET .../schedules?validation_id=… lists only the schedules that run that validation.
  • Validation errors. An empty list is a 422. A validation you can't see, or one in another workspace, is a 404. Mixing team-restricted work is a 422.

Every schedule in a response carries validation_ids, in order. rule_group_id is a deprecated alias: it is set only while the schedule runs exactly one validation, and null once it runs several. See the API reference.