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

# Schedule a flow

> Fire a Definition on a recurring UTC cron schedule — create, list, pause, resume, and delete scheduled jobs

A scheduled job fires one of your Definitions on a recurring [cron](https://en.wikipedia.org/wiki/Cron) schedule. Each scheduled job is backed by a managed schedule; every fire creates a normal job (`source: "schedule"`) that shows up under `GET /definitions/{definition_id}/jobs` — so everything you already know about jobs and executions applies.

## How scheduled jobs work

When you `POST /scheduled-jobs` with a `definition_id` and a `cron_expression`:

1. GetDialed creates the record **and** its backing schedule in one call.
2. On every cron tick, a new job is created and the Definition runs with the schedule's `input_data`.
3. `next_fire_at` is computed at read time from the cron expression — it is never stored.
4. `last_fired_at` / `last_fire_status` are updated by the worker as fired jobs start and finish.

<Warning>
  Cron expressions are **UTC-only, 5-field syntax only**. Six-field expressions (with seconds), the `@hourly`/`@daily`/`@weekly`/`@monthly`/`@yearly` aliases, and any `timezone`/`tz` field are rejected with `422`.
</Warning>

<Note>
  Fire policy is not configurable: overlapping fires are **skipped** (`overlap=SKIP`) — if a previous fire is still running when the next tick arrives, that tick is dropped. Missed fires during downtime are replayed only within a 60-second catch-up window; anything older is skipped.
</Note>

## Create a scheduled job

Fire a Definition every 15 minutes. The `X-API-Key` header is admin-equivalent; a Clerk JWT needs the admin role.

<CodeGroup>
  ```bash curl theme={null}
  curl -X POST https://api.getdialed.ai/flows/scheduled-jobs \
    -H "X-API-Key: $API_KEY" \
    -H "Content-Type: application/json" \
    -d '{
      "definition_id": "def_a1b2c3d4",
      "description": "Refresh Five9 lists every 15 minutes",
      "cron_expression": "*/15 * * * *",
      "input_data": {"list": "prod"}
    }'
  ```

  ```javascript JavaScript theme={null}
  const res = await fetch("https://api.getdialed.ai/flows/scheduled-jobs", {
    method: "POST",
    headers: {
      "X-API-Key": process.env.API_KEY,
      "Content-Type": "application/json",
    },
    body: JSON.stringify({
      definition_id: "def_a1b2c3d4",
      description: "Refresh Five9 lists every 15 minutes",
      cron_expression: "*/15 * * * *",
      input_data: { list: "prod" },
    }),
  });
  const scheduledJob = await res.json();
  ```

  ```python Python theme={null}
  import os
  import httpx

  res = httpx.post(
      "https://api.getdialed.ai/flows/scheduled-jobs",
      headers={"X-API-Key": os.environ["API_KEY"]},
      json={
          "definition_id": "def_a1b2c3d4",
          "description": "Refresh Five9 lists every 15 minutes",
          "cron_expression": "*/15 * * * *",
          "input_data": {"list": "prod"},
      },
  )
  scheduled_job = res.json()
  ```
</CodeGroup>

```json theme={null}
{
  "id": "sched_c9beda5f",
  "definition_id": "def_a1b2c3d4",
  "org_id": "org_12345678",
  "description": "Refresh Five9 lists every 15 minutes",
  "cron_expression": "*/15 * * * *",
  "enabled": true,
  "input_data": {"list": "prod"},
  "metadata": {},
  "created_at": "2026-05-24T08:15:00Z",
  "updated_at": "2026-05-24T08:15:00Z",
  "next_fire_at": "2026-05-24T08:30:00Z",
  "last_fired_at": null,
  "last_fire_status": null
}
```

<Tip>
  Set `"enabled": false` on create to register the schedule **paused** — useful for staging a cadence you'll turn on later.
</Tip>

## List your schedules

Results are cursor-paginated, newest first. `next_cursor` is `null` on the last page.

<CodeGroup>
  ```bash curl theme={null}
  curl "https://api.getdialed.ai/flows/scheduled-jobs?limit=20" \
    -H "X-API-Key: $API_KEY"
  ```

  ```javascript JavaScript theme={null}
  const res = await fetch(
    "https://api.getdialed.ai/flows/scheduled-jobs?limit=20",
    { headers: { "X-API-Key": process.env.API_KEY } },
  );
  const { items, next_cursor } = await res.json();
  ```

  ```python Python theme={null}
  import os
  import httpx

  res = httpx.get(
      "https://api.getdialed.ai/flows/scheduled-jobs",
      headers={"X-API-Key": os.environ["API_KEY"]},
      params={"limit": 20},
  )
  page = res.json()
  ```
</CodeGroup>

## Pause and resume

There is no separate pause endpoint — flip `enabled` with a `PATCH`. `enabled: false` pauses the backing schedule; `enabled: true` unpauses it. Fire history is preserved either way. `definition_id` is immutable — to point a schedule at a different Definition, delete it and create a new one.

<CodeGroup>
  ```bash curl theme={null}
  # Pause
  curl -X PATCH https://api.getdialed.ai/flows/scheduled-jobs/sched_c9beda5f \
    -H "X-API-Key: $API_KEY" \
    -H "Content-Type: application/json" \
    -d '{"enabled": false}'

  # Resume
  curl -X PATCH https://api.getdialed.ai/flows/scheduled-jobs/sched_c9beda5f \
    -H "X-API-Key: $API_KEY" \
    -H "Content-Type: application/json" \
    -d '{"enabled": true}'
  ```

  ```javascript JavaScript theme={null}
  async function setEnabled(schedId, enabled) {
    const res = await fetch(
      `https://api.getdialed.ai/flows/scheduled-jobs/${schedId}`,
      {
        method: "PATCH",
        headers: {
          "X-API-Key": process.env.API_KEY,
          "Content-Type": "application/json",
        },
        body: JSON.stringify({ enabled }),
      },
    );
    return res.json();
  }
  await setEnabled("sched_c9beda5f", false); // pause
  await setEnabled("sched_c9beda5f", true); //  resume
  ```

  ```python Python theme={null}
  import os
  import httpx

  def set_enabled(sched_id: str, enabled: bool) -> dict:
      res = httpx.patch(
          f"https://api.getdialed.ai/flows/scheduled-jobs/{sched_id}",
          headers={"X-API-Key": os.environ["API_KEY"]},
          json={"enabled": enabled},
      )
      return res.json()

  set_enabled("sched_c9beda5f", False)  # pause
  set_enabled("sched_c9beda5f", True)   # resume
  ```
</CodeGroup>

<Tip>
  Change the cadence in place with the same `PATCH` — send `{"cron_expression": "0 */6 * * *"}`. Fire history and pause state are preserved.
</Tip>

## Delete a schedule

Removes the backing schedule, then the stored record. Jobs already fired by the schedule are unaffected. The delete is idempotent — a missing backing schedule still returns `204`.

<CodeGroup>
  ```bash curl theme={null}
  curl -X DELETE https://api.getdialed.ai/flows/scheduled-jobs/sched_c9beda5f \
    -H "X-API-Key: $API_KEY"
  ```

  ```javascript JavaScript theme={null}
  await fetch("https://api.getdialed.ai/flows/scheduled-jobs/sched_c9beda5f", {
    method: "DELETE",
    headers: { "X-API-Key": process.env.API_KEY },
  });
  ```

  ```python Python theme={null}
  import os
  import httpx

  httpx.delete(
      "https://api.getdialed.ai/flows/scheduled-jobs/sched_c9beda5f",
      headers={"X-API-Key": os.environ["API_KEY"]},
  )
  ```
</CodeGroup>

## Next steps

<CardGroup cols={2}>
  <Card title="Scheduled jobs" icon="clock" href="/concepts/scheduled-jobs">
    The full object reference, cron rules, and fire semantics.
  </Card>

  <Card title="Jobs and executions" icon="diagram-project" href="/concepts/jobs-and-executions">
    Every fire creates a job — track its lifecycle and executions.
  </Card>
</CardGroup>
