# Schedules

> Run a command in a sandbox at the times a cron line names, waking it when it sleeps.

A schedule runs a command in a sandbox at the times a cron line names, in UTC. It wakes the sandbox when it is asleep, like an [exec](https://nanite.run/docs/exec.md), and the sandbox goes back to sleep once the command is done and nothing else uses it.

## Add a schedule

```http
POST /v1/sandboxes/{name}/schedules
```

```json
{ "cron": "0 9 * * 1-5", "cmd": ["sh", "-c", "/srv/report >> /srv/report.log"] }
```

Answers `201` with the schedule:

```json
{
  "id": "sch_7c491e237bc742dcb202",
  "cron": "0 9 * * 1-5",
  "cmd": ["sh", "-c", "/srv/report >> /srv/report.log"],
  "next_run_at": "2026-11-02T09:00:00Z",
  "last_run_at": null,
  "last_result": null,
  "created_at": "2026-11-01T08:12:40.118Z"
}
```

| Field         | Type           | About                                                               |
| ------------- | -------------- | ------------------------------------------------------------------- |
| `cron`        | string         | Five fields: minute, hour, day of month, month, day of week. UTC.   |
| `cmd`         | array          | A command as exec takes it: 1 to 64 strings, at most 16 KiB in all. |
| `next_run_at` | string or null | When it runs next. `null` when the line names no time left.         |
| `last_run_at` | string or null | When it last ran.                                                   |
| `last_result` | string or null | How the last run ended: `exit 0`, an error code, or `timed out`.    |

Each field takes `*`, numbers, ranges such as `1-5`, steps such as `*/15`, and lists of them. Sunday is `0` or `7`. When both day of month and day of week are restricted, either one is enough, as in cron.

## List and remove

```http
GET /v1/sandboxes/{name}/schedules
DELETE /v1/sandboxes/{name}/schedules/{id}
```

The list answers `{ "schedules": [...] }`. A remove answers `204`, or `404 schedule_not_found`. Deleting a sandbox removes its schedules.

## How a run goes

- Runs start within the minute they are due, and a run is never repeated.
- The command runs as an exec with no stdin. Its output is not kept, so write what you need to a file.
- `last_result` is `timed out` when the command is still going after 60 seconds. It keeps running in the sandbox.
- A run that cannot start records why in `last_result`, such as `insufficient_credits`, `concurrent_sandbox_limit_exceeded` or `sandbox_held`, and the schedule moves on to its next time.

## Limits

| What                    | Limit         | Refusal                       |
| ----------------------- | ------------- | ----------------------------- |
| Schedules per sandbox   | 20            | `409 schedule_limit_exceeded` |
| How often one runs      | Once a minute |                               |
| Time before `timed out` | 60 seconds    |                               |
