# Schedules API

> Create, pause, resume and remove schedules that request a path on your project on a five-field cron timer in UTC.

Source: https://docs.fortly.com/api/schedules

A schedule makes a `GET` request to a path on your project on a cron timer. The run is an ordinary request to the project's own address, so it wakes the project and appears in its logs like any visitor's. For writing the handler, see [Schedules](https://docs.fortly.com/deploy/schedules).

- `GET /projects/{name}/schedules` — A project's schedules, with the next run
- `POST /projects/{name}/schedules` — Add a schedule
- `PATCH /projects/{name}/schedules/{id}` — Pause or resume a schedule
- `DELETE /projects/{name}/schedules/{id}` — Remove a schedule
- `GET /schedules` — Every schedule across your projects

## Cron syntax

Five fields, in UTC: minute, hour, day of month, month, day of week. Each field takes `*`, a number, a list `a,b`, a range `a-b`, or a step `*/n` or `a-b/n`. Sunday is `0` or `7`.

```text
0 3 * * *          every day at 03:00 UTC
*/15 9-17 * * 1-5  every 15 minutes, 09:00–17:45 UTC, Monday to Friday
0 0 1 * *          midnight UTC on the first of each month
```

Shorthands such as `@daily`, names such as `MON` or `JAN`, and `L` and `#` are not accepted. A spec that does not parse is refused when you save it.

Runs that were missed while the platform was down are not replayed afterwards. A run that takes longer than 5 minutes is abandoned.

## The schedule object

- `id` (string, optional) — The schedule's id, 48 hex characters.
- `project` (string, optional) — The project's `name`.
- `account_id` (string, optional) — The account that created it.
- `name` (string, optional) — Your label for it.
- `spec` (string, optional) — The cron spec.
- `path` (string, optional) — The path requested, starting with `/`.
- `enabled` (boolean, optional) — `false` while paused.
- `created_at` (integer, optional) — Unix seconds.
- `last_run_at` (integer | null, optional) — When it last ran.
- `last_status` (integer | null, optional) — The HTTP status the last run got.
- `last_ms` (integer | null, optional) — How long the last run took, in milliseconds.
- `last_error` (string | null, optional) — Why the last run failed: `the project answered {code}` for a status outside 200–399, `the job did not finish within five minutes`, or the connection error. `null` after a run that succeeded.
- `next_run_at` (integer | null, optional) — When it runs next, Unix seconds. `null` while paused. Returned by the list routes only.

## List a project's schedules

- `GET /projects/{name}/schedules` — A project's schedules, with the next run

- `name` (string, required) — Path parameter. The project's `name`.

**curl**

```bash
curl https://api.fortly.com/projects/my-app-ada/schedules \
  -H "Authorization: Bearer $FORTLY_TOKEN"
```

**JavaScript**

```js
const res = await fetch("https://api.fortly.com/projects/my-app-ada/schedules", {
  headers: { Authorization: `Bearer ${process.env.FORTLY_TOKEN}` },
});
const { schedules } = await res.json();
```

```json
{
  "schedules": [
    {
      "id": "5e0b8f1c3a7d4e2f9b6c1a8d3e5f7a9b0c2d4e6f8a1b3c5d",
      "project": "my-app-ada",
      "account_id": "8b1e4f0c2d6a4e7f9c3b5a1d0e2f4c6b",
      "name": "Nightly digest",
      "spec": "0 3 * * *",
      "path": "/jobs/digest",
      "enabled": true,
      "created_at": 1791820800,
      "last_run_at": 1791860401,
      "last_status": 200,
      "last_ms": 412,
      "last_error": null,
      "next_run_at": 1791946800
    }
  ]
}
```

## Add a schedule

- `POST /projects/{name}/schedules` — Add a schedule

Adds a schedule, enabled.

In the path, `{name}` is the project's `name`. The JSON body takes:

- `name` (string, required) — A label for the schedule. Not empty.
- `spec` (string, required) — A five-field [cron spec](#cron-syntax), in UTC.
- `path` (string, required) — The path to request on your project, starting with `/`. May include a query string.

**curl**

```bash
curl -X POST https://api.fortly.com/projects/my-app-ada/schedules \
  -H "Authorization: Bearer $FORTLY_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"name":"Nightly digest","spec":"0 3 * * *","path":"/jobs/digest"}'
```

**JavaScript**

```js
const res = await fetch("https://api.fortly.com/projects/my-app-ada/schedules", {
  method: "POST",
  headers: {
    Authorization: `Bearer ${process.env.FORTLY_TOKEN}`,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({ name: "Nightly digest", spec: "0 3 * * *", path: "/jobs/digest" }),
});
const schedule = await res.json();
```

Answers `201` with the [schedule](#the-schedule-object), without `next_run_at`:

```json
{
  "id": "5e0b8f1c3a7d4e2f9b6c1a8d3e5f7a9b0c2d4e6f8a1b3c5d",
  "project": "my-app-ada",
  "account_id": "8b1e4f0c2d6a4e7f9c3b5a1d0e2f4c6b",
  "name": "Nightly digest",
  "spec": "0 3 * * *",
  "path": "/jobs/digest",
  "enabled": true,
  "created_at": 1791820800,
  "last_run_at": null,
  "last_status": null,
  "last_ms": null,
  "last_error": null
}
```

An empty name, a spec that does not parse, or a path without a leading `/` answers `400` with the reason.

## Pause or resume a schedule

- `PATCH /projects/{name}/schedules/{id}` — Pause or resume a schedule

- `name` (string, required) — Path parameter. The project's `name`.
- `id` (string, required) — Path parameter. The schedule's `id`.
- `enabled` (boolean, required) — Body. `false` to pause, `true` to resume.

**curl**

```bash
curl -X PATCH https://api.fortly.com/projects/my-app-ada/schedules/5e0b8f1c3a7d4e2f9b6c1a8d3e5f7a9b0c2d4e6f8a1b3c5d \
  -H "Authorization: Bearer $FORTLY_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"enabled":false}'
```

**JavaScript**

```js
const id = "5e0b8f1c3a7d4e2f9b6c1a8d3e5f7a9b0c2d4e6f8a1b3c5d";
await fetch(`https://api.fortly.com/projects/my-app-ada/schedules/${id}`, {
  method: "PATCH",
  headers: {
    Authorization: `Bearer ${process.env.FORTLY_TOKEN}`,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({ enabled: false }),
});
```

Answers `204 No Content`, or `404` with `no such schedule` when the id is not one of this project's schedules. To change a schedule's spec or path, remove it and add a new one.

## Remove a schedule

- `DELETE /projects/{name}/schedules/{id}` — Remove a schedule

- `name` (string, required) — Path parameter. The project's `name`.
- `id` (string, required) — Path parameter. The schedule's `id`.

**curl**

```bash
curl -X DELETE https://api.fortly.com/projects/my-app-ada/schedules/5e0b8f1c3a7d4e2f9b6c1a8d3e5f7a9b0c2d4e6f8a1b3c5d \
  -H "Authorization: Bearer $FORTLY_TOKEN"
```

**JavaScript**

```js
const id = "5e0b8f1c3a7d4e2f9b6c1a8d3e5f7a9b0c2d4e6f8a1b3c5d";
await fetch(`https://api.fortly.com/projects/my-app-ada/schedules/${id}`, {
  method: "DELETE",
  headers: { Authorization: `Bearer ${process.env.FORTLY_TOKEN}` },
});
```

Answers `204 No Content`, or `404` with `no such schedule`.

## List all schedules

- `GET /schedules` — Every schedule across your projects

Every schedule on every project you can access, in the same shape as [List a project's schedules](#list-a-projects-schedules), `next_run_at` included.

**curl**

```bash
curl https://api.fortly.com/schedules \
  -H "Authorization: Bearer $FORTLY_TOKEN"
```

**JavaScript**

```js
const res = await fetch("https://api.fortly.com/schedules", {
  headers: { Authorization: `Bearer ${process.env.FORTLY_TOKEN}` },
});
const { schedules } = await res.json();
```

```json
{
  "schedules": [
    {
      "id": "5e0b8f1c3a7d4e2f9b6c1a8d3e5f7a9b0c2d4e6f8a1b3c5d",
      "project": "my-app-ada",
      "name": "Nightly digest",
      "spec": "0 3 * * *",
      "path": "/jobs/digest",
      "enabled": true,
      "next_run_at": 1791946800
    }
  ]
}
```

Items are shortened here; each is a complete schedule object.
