prompt, a trigger (when to fire), and a deliver_to (where the output lands), and HQ runs the agent on that cadence and delivers the result. This guide walks the full lifecycle: create, observe, pause/resume, fire once on demand, edit, and tear down.
All routes live under https://api.hq.zone/v1/api/schedules and authenticate with a personal access token: Authorization: Bearer hq_pat_.... Read operations need the schedules:read scope; everything that mutates a schedule needs schedules:write.
Create a recurring run
Pick a trigger
The
trigger field is a tagged object — a kind plus its parameters. For a recurring run you’ll use one of:cron— a 5-field cron expression (min hour dom month dow) in a named timezone.tzis an IANA name like"Europe/Stockholm"; fixed offsets such as"UTC+3"are rejected.rrule— an RFC 5545 RRULE for patterns cron can’t express (e.g. “third Tuesday of the month”), also with an IANAtz.
tz is required on the engine-side trigger. Pass an IANA zone name explicitly — a fixed UTC offset is refused because it can’t track DST.Choose where output is delivered
deliver_to is also a tagged object. The supported destinations are:{ "kind": "web_inbox" }— the user’s web inbox (read via the/v1/api/conversationssurface).{ "kind": "slack_dm", "user_id": "U0123..." }— DM a Slack user.{ "kind": "slack_channel", "channel_id": "C0123..." }— post in a Slack channel.{ "kind": "teams_dm", "conversation_id": "..." }— a Microsoft Teams chat.{ "kind": "teams_channel", "team_id": "...", "channel_id": "..." }— a Teams channel.
POST the schedule
POST /v1/api/schedules creates a schedule owned by the caller. The body is:name(required) and optionaldescription.trigger(required) — the object from step 1.prompt(required) — the instruction the agent runs on each fire.agent_id(optional) — which agent runs the prompt. If omitted, the workspace’s default enabled agent is used; a non-existentagent_idreturns404.deliver_to(required) — the destination from step 2.reset_each_fire(optional, defaultfalse) —falsereuses one persistent conversation thread across fires (so the agent can compare against prior runs);truestarts a fresh conversation each fire.delivery_locale(optional) — a BCP-47 locale override for this schedule’s deliveries; falls back to the owner’s workspace locale when absent.
201 with the full schedule object. If your plan’s schedule limit is reached, the request fails with 402.List and inspect
GET /v1/api/schedules returns your schedules plus a total count for pagination. By default scope=mine returns only the caller’s own schedules.
state, last_fire_at, last_fire_status, next_fire_at, fire_count, failure_count, consecutive_failure_count, last_fire_lag_ms, and last_run_conversation_id (a link to the conversation from the most recent run).
By default the list excludes archived schedules so you see the working set. To change that:
state=<value>filters by an explicit lifecycle state (passes through verbatim).include_archived=trueadds archived rows to the default view (the audit history view).limitdefaults to100(max500);offsetpaginates the workspace view.
GET /v1/api/schedules/{id}. You can read a schedule only if you own it or are an admin; otherwise it returns 404.
Lifecycle states
A schedule’sstate is one of:
active— firing on its trigger.paused— temporarily stopped; resumable.quarantined— its stored trigger or args won’t parse; the engine parked it.archived— cancelled; will never fire again (history retained).
Pause and resume
Pause an active schedule to stop it firing until you resume it.POST /v1/api/schedules/{id}/pause moves it from active → paused and clears its next fire.
POST /v1/api/schedules/{id}/resume brings it back and returns the newly computed next fire time.
You can’t resume an
archived schedule. A quarantined schedule must have its trigger fixed via an update before it will resume — resuming it as-is would just re-quarantine on the next fire.403.
Fire once now
POST /v1/api/schedules/{id}/fire_now triggers an immediate run without changing the regular firing cadence.
403 otherwise). See Fire a schedule now.
Update a schedule
PATCH /v1/api/schedules/{id} changes only the fields you supply: name, description, trigger, or args. When the trigger changes, the response includes the recomputed next_fire_at.
For
description specifically, sending an explicit null clears it, while omitting the field keeps the current value.403 otherwise). See Update a schedule.
Tear down: cancel, then erase
Teardown is a deliberate two-step path so you can’t destroy history by accident.Cancel (archive)
DELETE /v1/api/schedules/{id} cancels the schedule and archives it: it flips state → archived, drops pending timers, and stops all future runs while retaining its history.403 otherwise). References: Cancel a schedule and Erase a schedule.
Admin: filter by owner
Admins can list across the whole workspace withscope=workspace (non-admins get 403), optionally narrowing to one owner via owner_user_id. To populate a “filter by user” dropdown with only users who actually have schedules, call GET /v1/api/schedules/owners.
403 otherwise) and returns each distinct owner with a schedule_count. See List schedule owners.