Pause, resume, cancel & reschedule
Once a schedule exists you control it with four side-effectful calls. Each one is a POST
to a sub-resource of the schedule and returns the updated schedule so you can read the
new state from the response.
pause cancel ┌────────┐ ──────────► ┌────────┐ ──────────► ┌──────────┐ │ active │ │ paused │ │ canceled │ (terminal) └────────┘ ◄────────── └────────┘ ──────────► └──────────┘ resume cancelA newly created schedule starts in state: "active". The states are active, paused,
and canceled — that’s the whole machine. Cancel is valid from both active and
paused — the diagram shows the cancel-from-paused path, but you can cancel an active
schedule directly too.
POST /v1/schedules/{id}/pause moves an active schedule to paused. Its pending
deliveries become non-claimable, so nothing fires while it’s paused. Any node already
holding an occurrence is notified to drop it.
curl -sS -X POST https://api.schedstack.com/v1/schedules/sch_01J9.../pause \ -H "Authorization: Bearer sk_test_…"{ "id": "sch_01J9...", "object": "schedule", "mode": "test", "kind": "recurring", "state": "paused", "endpoint": "https://example.com/hooks/billing", "method": "POST", "cron": "0 9 * * *", "timezone": "America/New_York", "next_fire_at": "2026-07-01T13:00:00Z", "next_runs": ["2026-07-01T13:00:00Z", "2026-07-02T13:00:00Z"], "updated_at": "2026-06-27T18:04:11Z"}Pause is durable: a recurring schedule stops minting new occurrences and an undelivered one-shot holds its slot until you resume.
Resume
Section titled “Resume”POST /v1/schedules/{id}/resume moves a paused schedule back to active. Deliveries
that were paused become claimable again and fire at their scheduled instant.
curl -sS -X POST https://api.schedstack.com/v1/schedules/sch_01J9.../resume \ -H "Authorization: Bearer sk_test_…"{ "id": "sch_01J9...", "object": "schedule", "state": "active", "kind": "recurring", "next_fire_at": "2026-07-01T13:00:00Z", "updated_at": "2026-06-27T18:09:55Z"}Cancel
Section titled “Cancel”POST /v1/schedules/{id}/cancel is terminal. The schedule moves to canceled, every
pending delivery is finalized as canceled (it shows up in the schedule’s delivery history
with that status), and no future occurrence is ever minted. A delivery that has already
landed a 2xx finalizes as succeeded (success wins); all other pending deliveries
finalize as canceled.
curl -sS -X POST https://api.schedstack.com/v1/schedules/sch_01J9.../cancel \ -H "Authorization: Bearer sk_test_…"{ "id": "sch_01J9...", "object": "schedule", "state": "canceled", "updated_at": "2026-06-27T18:12:30Z"}Reschedule (move the fire time)
Section titled “Reschedule (move the fire time)”POST /v1/schedules/{id}/reschedule is the only way to change when a schedule fires.
The body carries exactly one timing source — the same fields you used at creation:
| Field | Use |
|---|---|
delay |
Fire after a relative duration from now, e.g. "30m", "24h". Minimum 1s. |
fire_at |
An absolute RFC 3339 instant, e.g. "2026-07-01T09:00:00Z". |
local_fire_at + timezone |
A wall-clock time in an IANA zone, e.g. "2026-07-01T09:00:00" + "America/New_York" (DST-correct). |
cron + timezone |
For a recurring schedule: replace the recurrence and re-time the next run. |
Provide exactly one of delay / fire_at / local_fire_at / cron. Sending zero or
more than one returns a 400/422 with a missing_timing or multiple_timing error.
curl -sS -X POST https://api.schedstack.com/v1/schedules/sch_01J9.../reschedule \ -H "Authorization: Bearer sk_test_…" \ -H "Content-Type: application/json" \ -d '{ "fire_at": "2026-07-01T09:00:00Z" }'{ "id": "sch_01J9...", "object": "schedule", "kind": "one_shot", "state": "active", "fire_at": "2026-07-01T09:00:00Z", "next_runs": ["2026-07-01T09:00:00Z"], "updated_at": "2026-06-27T18:20:02Z"}Reschedule re-times the pending delivery in place: its scheduled_for moves to the new
instant and its TTL deadline shifts by the same delta, so the time-to-live you set is
preserved. A node already holding the old occurrence is told to drop and re-claim it at the
new time.
reschedule accepts an Idempotency-Key header, so a network retry of the same reschedule
is safe. See Idempotency keys.
PATCH does not move timing
Section titled “PATCH does not move timing”PATCH /v1/schedules/{id} updates the target (endpoint, method), policy (ttl,
retry_policy), and metadata — and nothing else. Timing fields are not part of a
PATCH; sending fire_at or delay in a PATCH body does not move the fire time. Use
reschedule for that. This split keeps “edit the config” and “move the clock” as separate,
explicit operations.
# Update target + retries (timing untouched)curl -sS -X PATCH https://api.schedstack.com/v1/schedules/sch_01J9... \ -H "Authorization: Bearer sk_test_…" \ -H "Content-Type: application/json" \ -d '{ "endpoint": "https://example.com/hooks/billing-v2", "retry_policy": { "max_attempts": 5 }, "metadata": { "owner": "billing" } }'A note on idempotent transitions
Section titled “A note on idempotent transitions”pause, resume, and cancel are forgiving: they return 200 with the current schedule
even when the transition is a no-op. Pausing an already-paused schedule, or pausing a
canceled one, doesn’t error — it just returns the schedule unchanged. The call only fails
with 404 not_found when the schedule ID doesn’t exist in your (project, mode).
Inspect a schedule and its deliveries
Section titled “Inspect a schedule and its deliveries”Read the current state at any time:
curl -sS https://api.schedstack.com/v1/schedules/sch_01J9... \ -H "Authorization: Bearer sk_test_…"List the deliveries this schedule has produced — pending and historical — newest first (cursor-paginated, see API conventions):
curl -sS https://api.schedstack.com/v1/schedules/sch_01J9.../deliveries \ -H "Authorization: Bearer sk_test_…"{ "object": "list", "data": [ { "id": "dlv_01J9...", "object": "delivery", "schedule_id": "sch_01J9...", "status": "canceled", "scheduled_for": "2026-07-01T13:00:00Z", "attempt_count": 0 } ], "has_more": false, "next_cursor": null}This is how you confirm a cancel took effect (the occurrence shows status: "canceled") or
check whether a paused schedule’s next occurrence is still pending.
Related
Section titled “Related”- One-shot scheduling — create a single durable delivery.
- Recurring schedules & DST —
cron+ timezone recurrence, whichreschedulecan also replace. - Retries & dead-letter — what happens to a delivery’s attempts independent of the schedule’s lifecycle.
- Dead-letter & replay — re-fire a delivery that ran out of attempts.
- Idempotency keys — make
rescheduleretries safe.