> ## Documentation Index
> Fetch the complete documentation index at: https://docs.plungeai.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Bot schedules and wake

> Give a bot a clock. Cron and one-time schedules from outside or from the bot itself, the wake call, result delivery, the SILENT marker and run history.


A bot runs when something starts it: you, a trigger, a chat message, or a schedule. A schedule is a scheduler job that runs the bot's saved workflow. You can create one from outside, or let the bot create its own.

## Schedule a bot from outside

Over REST, `POST /v1/schedules` takes a saved workflow or bot id and either a cron expression or `@once` with `run_at`:

```bash
curl -s -X POST https://api.plungeai.com/v1/schedules \
  -H "Authorization: Bearer $PLUNGE_API_KEY" -H 'Content-Type: application/json' \
  -d '{"name":"Morning digest","workflow_id":"<bot id>","schedule":"0 9 * * 1-5","timezone":"America/Los_Angeles","parameters":{"deliver":["slack"]}}'
```

A one-time run removes itself after it fires:

```bash
curl -s -X POST https://api.plungeai.com/v1/schedules \
  -H "Authorization: Bearer $PLUNGE_API_KEY" -H 'Content-Type: application/json' \
  -d '{"name":"One-off report","workflow_id":"<bot id>","schedule":"@once","run_at":"2026-10-06T09:00:00Z"}'
```

| Field | Meaning |
|---|---|
| `schedule` | A cron expression, or `@once` together with `run_at`. |
| `run_at` | ISO-8601 time with a UTC offset, in the future. Required for `@once`. Refused with `run_at_required` or `run_at_past` otherwise. |
| `timezone` | The IANA zone the cron is read in. Default UTC. |
| `ends_at` | ISO-8601 time or ms epoch after which the schedule stops. `PATCH` with `ends_at: null` clears it. |
| `parameters.deliver` | Where each result goes (below). |
| `parameters.input` | The per-run input. |

The same operations are on MCP (`plungeai_schedule`) and the CLI (`schedules create`, `--cron @once --at <iso>`, `--ends-at`); see [REST, MCP and CLI](/bots/rest-mcp-cli).

## Let the bot schedule itself

List `schedule` in the bot's `allowed_tools`. The tool works on the bot's own jobs only:

| Action | Input | Does |
|---|---|---|
| `create` | `name`, `cron`, `timezone?`, `prompt?`, `deliver?`, `ends_at?` | A recurring job. The model writes the 5-field cron and the reply echoes the schedule in words, so you can check it said what you asked. |
| `create` with `cron: "@once"` | `run_at` | One run at a clock time. Refused without a UTC offset. |
| `wake` | `in`, `note?` | One later run after a delay (`10m`, `2h`, `1d`; at least 60 s). The note becomes the run's input. |
| `list` | | The bot's jobs with ids, the schedule in words and the next run. |
| `pause`, `resume`, `delete` | `id` | By job id. |
| `run_now` | `id`, `input?` | Fires a job once, now. |

A bot holds at most 50 active jobs. `ends_at` retires a job after that time. With no `timezone` the job uses the user's zone, otherwise UTC.

The class of a `schedule` call is by action: `delete` is `delete`, `list` is `read`, the rest are `write`. Under `posture: read_only` only `list` runs.

## Wake

A wake re-runs the bot once, later, without touching its schedule. The bot calls `schedule` with `action: wake`; from outside, `POST /v1/schedules/{id}/wake` does the same:

```bash
curl -s -X POST https://api.plungeai.com/v1/schedules/<id>/wake \
  -H "Authorization: Bearer $PLUNGE_API_KEY" -H 'Content-Type: application/json' \
  -d '{"note":"the inbox has new mail","in":"10m"}'
```

- `note` becomes the run's input. `in` is seconds or a string like `"90s"`, `"10m"`, `"2h"`; left out, the wake fires on the scheduler's next tick.
- A pending wake is re-timed, never stacked, so repeated wakes leave one job.
- A schedule with no saved workflow (a heartbeat) cannot be woken.

Behind a wake is the scheduler's `runAgain`: it creates one `@once` job for the bot.

## One-time jobs

An `@once` job fires once at its `run_at`, then deletes itself. A failed run may retry five minutes later first; the job is deleted on the final failure or on success. Because the job deletes itself, an [outbound hook](/bots/triggers-and-hooks#outbound-hooks) on it receives the run's last event and is then gone.

## Deliver the result

`parameters.deliver` is a list of `{channel, chat_id?, to?}`. A bare channel name such as `"slack"` means the owner's own account.

| Channel | Target |
|---|---|
| `inapp` | The Studio inbox. |
| `email` | The owner's registered address; other addresses must be confirmed recipients. |
| `slack`, `telegram`, `discord` | `chat_id`. |
| `whatsapp` | `to` (a phone number) and the sending `phone_number_id`. |
| `teams` | `chat_id`, a Microsoft Graph chat id. |

Delivery is fenced by the owner's pairing and a per-channel length cap. Any other channel is `422 invalid_params` and nothing is created.

- **`[SILENT]`:** when a run's result is exactly `[SILENT]`, or starts with it, the scheduler delivers to no channel and strips the marker from what it stores. A bot emits it when nothing is worth reporting. A run held for approval is never silent.
- **Threads:** a delivery target may carry the reply or thread id of its channel, so the answer lands in the originating thread.
- **Retries:** a failed delivery of a completed run is retried about 1 minute and then about 5 minutes later (three sends in all), then marked failed with an in-app notice.
- **Local bots:** a job for a bot that runs on the owner's machine is skipped cleanly, with one notice, when that machine is offline.

## Run history

`GET /v1/schedules/{id}/runs` lists the runs; `GET /v1/schedules/{id}` returns the schedule with its ten latest. A run has `status`, `started_at`, `ended_at`, `duration_ms`, `execution_id` and `error`. `POST /v1/schedules/{id}/run` runs it now and returns the `execution_id`, which `POST /v1/executions/{id}/cancel` accepts. `DELETE` removes the schedule and keeps its history readable.
