Skip to main content
A scheduled job fires one of your Definitions on a recurring 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.
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.
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.

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.
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"}
  }'
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();
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()
{
  "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
}
Set "enabled": false on create to register the schedule paused — useful for staging a cadence you’ll turn on later.

List your schedules

Results are cursor-paginated, newest first. next_cursor is null on the last page.
curl "https://api.getdialed.ai/flows/scheduled-jobs?limit=20" \
  -H "X-API-Key: $API_KEY"
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();
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()

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.
# 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}'
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
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
Change the cadence in place with the same PATCH — send {"cron_expression": "0 */6 * * *"}. Fire history and pause state are preserved.

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.
curl -X DELETE https://api.getdialed.ai/flows/scheduled-jobs/sched_c9beda5f \
  -H "X-API-Key: $API_KEY"
await fetch("https://api.getdialed.ai/flows/scheduled-jobs/sched_c9beda5f", {
  method: "DELETE",
  headers: { "X-API-Key": process.env.API_KEY },
});
import os
import httpx

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

Next steps

Scheduled jobs

The full object reference, cron rules, and fire semantics.

Jobs and executions

Every fire creates a job — track its lifecycle and executions.