Schedules

Start runs of a workflow on a recurrence — daily, weekly, monthly or yearly at a set time — with a run-name pattern, preset field values and per-task assignees; pause, resume, run now and preview.

View this page as Markdown

Operations: Schedules endpoints · scope schedules:manage.

A schedule starts runs of one published workflow on a recurrence. Each run gets a name from the schedule's pattern, the schedule's preset field values, and — for the tasks you name — the schedule's assignees instead of the task's own assignment rule. Schedules are managed in the app (Automations → Schedules, Builders and Admins) and through the API with the schedules:manage scope.

Operation HTTP SDK method
List schedules GET /v1/schedules listSchedules(…)
Create a schedule POST /v1/schedules createSchedule(…)
Get a schedule GET /v1/schedules/{id} getSchedule(…)
Update a schedule PATCH /v1/schedules/{id} updateSchedule(…)
Delete a schedule DELETE /v1/schedules/{id} deleteSchedule(…)
Pause a schedule POST /v1/schedules/{id}/pause pauseSchedule(…)
Resume a schedule POST /v1/schedules/{id}/resume resumeSchedule(…)
Start a run from a schedule now POST /v1/schedules/{id}/run runScheduleNow(…)
Preview a schedule's next occurrences GET /v1/schedules/{id}/preview previewSchedule(…)

Create a schedule

curl -X POST https://app.processcart.com/api/v1/schedules \
  -H "Authorization: Bearer pc_live_…" \
  -H "Content-Type: application/json" \
  -d '{ "workflowId": "3c1d…", "name": "Weekly order review",
        "recurrence": { "freq": "weekly", "interval": 1, "time": "09:00",
                        "startDate": "2026-10-12", "weekly": { "days": ["mon"] } },
        "namePattern": "{{workflow}} — {{date:YYYY-MM-DD}}",
        "presetValues": { "customer": "Acme Corp", "amount": 250 },
        "assignmentOverrides": { "review": [{ "kind": "group", "groupId": "7f0e…" }] } }'
const schedule = await client.createSchedule({
  workflowId: "3c1d…",
  name: "Weekly order review",
  recurrence: {
    freq: "weekly",
    interval: 1,
    time: "09:00",
    startDate: "2026-10-12",
    weekly: { days: ["mon"] },
  },
  presetValues: { customer: "Acme Corp", amount: 250 },
});
console.log(schedule.description, schedule.nextOccurrences);

The answer is the schedule (201, with an absolute Location): its recurrence in words (description), nextRunAt and the next three occurrences. A recurrence with no future occurrence is refused (422).

  • timezone is an IANA zone such as America/New_York; leave it out to use the workspace's zone.
  • presetValues are canonical values keyed by field key, checked against the published version like POST /v1/runs fields (Field values & typing). A preset its field's format rules refuse — outside a minimum or maximum, or failing a pattern — is refused when the schedule is saved (422, errors[].code invalid_value at presetValues.<key>), so a schedule never starts runs with it. Every required kickoff field needs a preset (422, errors[].code required; a required checkbox needs true) — except a File field, a field the API cannot write (a formula or other computed field), and a field whose default value fills it.
  • assignmentOverrides maps a task key to the members and groups that get that task in every run — { "kind": "user", "userId" } or { "kind": "group", "groupId" } (1–20 per task), the same spelling the Run resource uses for those two kinds. Only these two kinds are accepted: a Run's role or guest assignee cannot be an override, and an entry carrying any other member is refused (422). An override replaces the task's own assignment rule for those runs; an override whose members have all left the workspace, or whose group was deleted, falls back to that rule.
  • A schedule stays on its workflow; create another schedule for a different one. The workflow must be published, not archived and not in Trash.

Recurrence

Member Meaning
freq daily, weekly, monthly or yearly.
interval Every N days (1–365), weeks (1–52), months (1–24) or years (1–10), counted from startDate.
time HH:mm, 24-hour, minutes on 5-minute steps (00, 05, …, 55), in the schedule's zone.
startDate / endDate The first and last local dates an occurrence may fall on (endDate inclusive; omit it or send null for no end).
weekly { "days": ["mon", "wed", "fri"] } — weeks start on Monday; the week holding startDate is the first.
monthly { "kind": "day", "day": 31 } (a day past the end of a shorter month runs on its last day) or { "kind": "ordinal", "ordinal": "last", "target": "weekday" } — ordinal is first, second, third, fourth or last; target is a weekday (mon … sun), day, weekday or weekend_day (“the last weekday”, “the first Monday”).
yearly { "month": 3, "day": 15 }; February 29 runs on February 28 in other years.

Only the member that matches freq may be present. GET /v1/schedules/{id}/preview?count=5 answers the next occurrences (1–10, default 3) as UTC instants; for a paused schedule, the ones a resume would produce.

When runs are created

  • Runs are created at the scheduled time, usually within a minute: the scheduler checks for due schedules every 5 minutes, and schedule times sit on 5-minute steps.
  • Daylight saving time. A time that does not exist on a spring-forward day (02:30 when clocks jump from 02:00 to 03:00) runs at the same offset into the new hour (03:30). A time that happens twice on a fall-back day runs once, at the first.
  • Catch-up. If runs could not be created while the schedule was on (an outage), the next check creates ONE run, for the latest missed occurrence, and records how many it skipped in lastError. It never creates one run per missed occurrence.
  • Resuming never catches up. Occurrences that fall while a schedule is paused are skipped; after a resume, the next run is the first occurrence after now.
  • Time zones. The schedule's zone decides when a run is created and what {{date}} and {{time}} read. Inside the run, TODAY(), date-field defaults and due rules use the workspace's zone, as for any run.
  • Outages. A start that fails for a passing reason — the database did not answer, or the start failed unexpectedly — is not a refusal: lastError records it, the next check retries it, and the schedule is never paused for it. Run now answers 503 unavailable with Retry-After instead (500 internal_error for an unexpected failure). Any other error while creating a run counts toward a pause: the third in a row pauses the schedule (failed).
  • Which server fires it. A schedule fires only on the kind of server (production, preview or local) that created it or last edited or resumed it. When an edit or a resume moves it to another kind, its next run is recomputed from now, so the new server never creates a catch-up run for occurrences the old one missed.

Run names

namePattern (default {{workflow}} — {{date}}) takes these tokens; anything else is kept literally, and the name is cut to 200 characters.

Token Renders
{{workflow}} The workflow's name.
{{date}} The occurrence's local date, MMM D, YYYY.
{{date:<pattern>}} The date in a Date-field pattern: YYYY-MM-DD, MM/DD/YYYY, DD/MM/YYYY, DD-MMM-YYYY, MMM D, YYYY or MMMM D, YYYY.
{{time}} The occurrence's local time, HH:mm.

Runs a schedule creates

Every such run has startedBy: "schedule" and schedule: { id, name } (Runs). scheduledFor is the occurrence it was created for; it is null for a run started with Run now. Each occurrence creates at most one run. After a schedule is deleted its runs stay, and their schedule reads null. Subscribe to schedule.run_created to hear about them (Webhooks).

curl -X POST https://app.processcart.com/api/v1/schedules/5b2a…/run \
  -H "Authorization: Bearer pc_live_…"

Run now (POST /v1/schedules/{id}/run) starts one run right away — paused or not — with the schedule's pattern (rendered at the start instant), presets and overrides. It answers the new Run (201, its revision in the body) and an absolute Location. Presets the published version no longer accepts are skipped (the schedule's presetMismatches names them); a required kickoff field without a preset is refused with 422 required_fields_unsatisfied.

Pause, resume, update, delete

  • POST /v1/schedules/{id}/pause and /resume answer the schedule (200), unchanged when it already was. Resuming a schedule whose end date has passed is 409 schedule_ended — change its recurrence first. Creating, resuming or running a schedule now — or a PATCH that changes its presetValues or assignmentOverrides — on an unpublished workflow is 409 workflow_not_published, on one in Trash 409 workflow_trashed, on an archived one 403 workflow_not_runnable.
  • PATCH /v1/schedules/{id} changes any of name, recurrence, timezone, namePattern, presetValues and assignmentOverrides; a new recurrence or zone recomputes the next run from now. enabled is refused (422, errors[].code unknown_key on enabled) — pause and resume own it.
  • DELETE /v1/schedules/{id} answers 204.
  • GET /v1/schedules lists schedules newest first; filter by workflowId or enabled, and use updatedSince for a sync (Incremental sync).

Schedules carry no revision: no schedule operation reads Expected-Revision (the SDK's expectedRevision option is ignored here), and an update applies to the schedule as it is stored, so the last write wins. Read the schedule again before an update that depends on what another client may have changed.

Every change is recorded in the workspace's audit log under the key's name.

Why a schedule is paused

disabledReason says why enabled is false:

Reason Meaning
manual Paused by a person or a key.
ended The recurrence's end date passed, or it has no occurrence left to schedule (lastError then reads “This schedule has no future runs.”).
unpublished The workflow has no published version.
failed A start was refused (a preset or required field problem), three attempts in a row to create a run failed for a reason other than an outage, or the recurrence can no longer be read; lastError says why.
workflow_trashed The workflow moved to Trash. Restoring it does not resume the schedule.
workflow_archived The workflow was archived. Unarchiving it does not resume the schedule.

When the scheduler itself pauses a schedule as failed or unpublished, the workspace's Builders and Admins are notified. Moving the workflow to Trash or archiving it pauses its schedules at once, without a notification.

Allowlists

A key restricted to workflows or folders lists only the schedules of workflows inside its allowlist; any other schedule answers 403 not_allowed_for_key, and so does creating one for a workflow outside it.