Docs

Schedules

Call a path on your project on a cron timer in UTC, pause and resume it, and see when it last ran and how it answered.

Updated October 12, 2026
On this page
  1. Add a schedule
  2. The cron format
  3. What is refused
  4. Examples
  5. How a run works
  6. Missed runs are not replayed
  7. Pause, resume and remove
  8. List schedules
  9. Related

A schedule asks for a path on your project at the times a cron expression names. Each run is an ordinary GET request to your project's own address, so it reaches your app the same way a visitor's request does. Times are in UTC, the expression has five fields, and an expression Fortly cannot run is refused when you save it rather than silently never firing.

Add a schedule

Open schedules

Open your project, go to Deployments, and choose the Schedules tab.

Describe the job

Under Add a schedule, give it a Name (what it is for), When it runs as a cron expression such as 0 3 * * *, and the Path to request, such as /cron/digest.

Save it

The schedule appears under On this project, with when it runs next.

The cron format

Five fields separated by spaces, always evaluated in UTC:

┌───────── minute        0-59
│ ┌─────── hour          0-23
│ │ ┌───── day of month  1-31
│ │ │ ┌─── month         1-12
│ │ │ │ ┌─ day of week   0-7 (0 and 7 are both Sunday)
│ │ │ │ │
0 3 * * *

Each field accepts:

SyntaxMeaningExample
*Every value* in the hour field: every hour
A numberThat value30 in the minute field
a,bA list1,15 in the day field: the 1st and the 15th
a-bA range, inclusive1-5 in the weekday field: Monday to Friday
*/nEvery nth value*/15 in the minute field: 0, 15, 30, 45
a-b/nEvery nth value within a range9-17/2 in the hour field: 9, 11, 13, 15, 17

When both the day-of-month and the day-of-week fields are restricted, a day that matches either one runs. 0 9 1 * 1 runs at 09:00 on the 1st of every month and on every Monday. This is how cron has always behaved.

What is refused

Fortly accepts numbers only. These are refused when you save, with a message that says which field is wrong:

You wroteRefused with
@daily, @hourlya schedule has five fields — minute hour day month weekday — and this has 1
Six fields, with secondsa schedule has five fields — minute hour day month weekday — and this has 6
0 9 * * MONweekday: MON is not a number
0 9 * JAN *month: JAN is not a number
60 * * * *minute: 60 is outside 0-59
*/0 * * * *minute: a step of zero never comes round

L, W and # are not supported either.

An expression that can never come round, such as 0 0 31 2 * (31 February), is accepted but never runs. Its next_run_at is null, which is how you spot one.

Examples

ExpressionRuns
*/5 * * * *Every 5 minutes
0 * * * *At the start of every hour
0 3 * * *Every day at 03:00 UTC
30 8 * * 1-5Weekdays at 08:30 UTC
*/15 9-17 * * 1-5Every 15 minutes from 09:00 to 17:45 UTC, Monday to Friday
0 0 * * 0Every Sunday at midnight UTC
0 0 1 * *The first of every month at midnight UTC
0 6 1 1,4,7,10 *06:00 UTC on the first day of each quarter

How a run works

At the top of each minute, Fortly checks every enabled schedule and runs the ones whose expression matches that minute.

  • The request is a GET to the schedule's path on your project's own address. It goes through the same front door as visitor traffic, so it appears in your project's metrics like any other request.
  • Success is any 2xx or 3xx answer. Anything else is recorded as an error: the project answered 500.
  • Time limit: a run that has not answered within five minutes is abandoned and recorded as the job did not finish within five minutes.
  • The result is kept on the schedule: last_run_at, last_status (the HTTP status), last_ms (how long it took) and last_error.

A scheduled run carries no Fortly credential or header that marks it as scheduled. Anyone who knows the path can request it too. Make the job safe to run more than once, and check your own secret in the path's query string or handler if running it must be restricted.

Missed runs are not replayed

If a run's minute passes while Fortly cannot run it — during maintenance on the machine that runs schedules, for example — that run is skipped, not made up later. A five-minute schedule that missed an hour does not fire twelve times when it can run again. The schedule's last_run_at shows when it last actually ran.

Pause, resume and remove

Each schedule under On this project has a Pause button, which becomes Resume while it is paused. A paused schedule shows Paused where its next run would be.

A paused schedule does not run and its next_run_at is null. Resuming it does not run the times it missed while paused. To change a schedule's expression or path, remove it and add it again.

List schedules

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

Each schedule in schedules comes with next_run_at, the next time it will run in seconds since the epoch, worked out when you ask.

GET/projects/{name}/schedulesA project's schedules, with their next run
POST/projects/{name}/schedulesAdd one — name, spec, path
PATCH/projects/{name}/schedules/{id}Pause or resume
DELETE/projects/{name}/schedules/{id}Remove it
GET/schedulesEvery schedule across the projects you can reach
Something missing or unclear? Tell us and we will fix the page.© 2026 Fortly