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

# Run sessions on a schedule

> Run a session on a recurring cron cadence.

export const ScheduleTimeline = () => {
  const Fire = ({time, status, note, fired}) => <div className="flex w-[136px] shrink-0 flex-col items-center gap-2">
      <span className="font-mono text-xs text-zinc-500 dark:text-zinc-400">{time}</span>
      <span className={`${fired ? "h-3 w-3 rounded-full bg-zinc-900 dark:bg-zinc-100" : "h-3 w-3 rounded-full border-[1.5px] border-zinc-300 bg-white dark:border-zinc-600 dark:bg-zinc-950"}`} />
      <span className={`${fired ? "rounded-md px-2 py-0.5 font-mono text-xs bg-zinc-900 text-zinc-100 dark:bg-zinc-100 dark:text-zinc-900" : "rounded-md px-2 py-0.5 font-mono text-xs bg-zinc-100 text-zinc-500 dark:bg-zinc-800 dark:text-zinc-400"}`}>{status}</span>
      <span className="whitespace-nowrap text-xs text-zinc-500 dark:text-zinc-400">{note || "\u00a0"}</span>
    </div>;
  return <div className="not-prose my-8 overflow-x-auto">
      <div className="flex min-w-[680px] flex-col items-center">
        <div className="mb-5 flex items-center gap-2.5 text-sm text-zinc-500 dark:text-zinc-400">
          <span className="rounded-md bg-zinc-100 px-2 py-0.5 font-mono text-xs text-zinc-600 dark:bg-zinc-800 dark:text-zinc-300">0 9 * * 1-5</span>
          <span>Europe/Paris. Each fire creates a session from the template.</span>
        </div>
        <div className="relative flex items-start">
          <div className="absolute left-[68px] right-[68px] top-[29px] h-px bg-zinc-200 dark:bg-zinc-800" />
          <div className="relative"><Fire time="Mon 09:00" status="created" fired /></div>
          <div className="relative"><Fire time="Tue 09:00" status="created" fired /></div>
          <div className="relative"><Fire time="Wed 09:00" status="skipped_overlap" note="Tue's run still going" /></div>
          <div className="relative"><Fire time="Thu 09:00" status="created" fired /></div>
          <div className="relative"><Fire time="Fri 09:00" status="skipped_quota" note="no free slot" /></div>
        </div>
      </div>
    </div>;
};

<ScheduleTimeline />

A schedule creates a [session](/agents-api/sessions/overview) on a recurring cadence: a five-field cron expression evaluated in an IANA timezone, paired with a session template that is re-resolved on every fire. Use it for recurring work like a daily scrape or an hourly check.

Manage schedules with the [CRUD API](/agents-api/schedules/create). Each one has a `name`, a `timing`, and a `session_request` template:

<CodeGroup>
  ```bash cURL theme={"system"}
  curl -X POST https://agp.eu.hcompany.ai/api/v2/schedules \
    -H "Authorization: Bearer $HAI_API_KEY" \
    -H "Content-Type: application/json" \
    -d '{
      "name": "morning-market-scan",
      "timing": {"expression": "0 9 * * 1-5", "timezone": "Europe/Paris"},
      "session_request": {
        "agent": "h/web-surfer-flash",
        "messages": [
          {"type": "user_message", "message": "Scan new apartment listings in Paris 11e and summarize the top five"}
        ]
      }
    }'
  ```

  ```python Python theme={"system"}
  from hai_agents import Client

  client = Client()

  schedule = client.schedules.create_schedule(
      name="morning-market-scan",
      timing={"expression": "0 9 * * 1-5", "timezone": "Europe/Paris"},
      session_request={
          "agent": "h/web-surfer-flash",
          "messages": [
              {"type": "user_message", "message": "Scan new apartment listings in Paris 11e and summarize the top five"}
          ],
      },
  )
  print(schedule.id, schedule.next_run_times[0])
  ```

  ```typescript TypeScript theme={"system"}
  import { HaiAgentsClient } from "hai-agents";

  const client = new HaiAgentsClient();

  const schedule = await client.schedules.createSchedule({
    name: "morning-market-scan",
    timing: { expression: "0 9 * * 1-5", timezone: "Europe/Paris" },
    sessionRequest: {
      agent: "h/web-surfer-flash",
      messages: [
        { type: "user_message", message: "Scan new apartment listings in Paris 11e and summarize the top five" },
      ],
    },
  });
  console.log(schedule.id, schedule.nextRunTimes[0]);
  ```
</CodeGroup>

## Timing

```json Timing field theme={"system"}
"timing": {
  "type": "cron",
  "expression": "0 9 * * 1-5",
  "timezone": "Europe/Paris"
}
```

The expression is standard five-field cron (`minute hour day-of-month month day-of-week`), evaluated in the given timezone, so `0 9 * * 1-5` fires at 09:00 Paris time every weekday, across daylight-saving changes. An expression may not fire more often than once every 5 minutes. The `type` tag is optional on requests; `"cron"` is the default and only variant today.

The schedule object reports its upcoming fires in `next_run_times` (the next 5, empty while paused).

## The session template

`session_request` takes the same shape as the [Create session](/agents-api/sessions/create) body. It is stored as a template and re-resolved on every fire, so a catalog agent like `"h/web-surfer-flash"` always runs its current version.

* It must contain at least one initial message.
* It may not set `parent_session_id`.
* `max_time_s` defaults to 3600 seconds when unset.

## Fire outcomes

Every fire is recorded in the schedule's [run history](/agents-api/schedules/runs), whether or not it created a session:

| Status            | Meaning                                                                      |
| ----------------- | ---------------------------------------------------------------------------- |
| `created`         | A session was created. The run carries its `session_id`.                     |
| `skipped_overlap` | The session from a previous fire was still active, so this fire was skipped. |
| `skipped_quota`   | Your organization was at quota, so this fire was skipped.                    |
| `error`           | Session creation failed. The run carries the `error` detail.                 |

Fires do not queue behind each other: a skipped fire is skipped for good, and the schedule simply fires again at the next cadence point. Run history is retained for 90 days.

## Pausing and failures

[Pause](/agents-api/schedules/pause) stops future fires without deleting the schedule, and [Resume](/agents-api/schedules/resume) recomputes the next fire from now. After 5 consecutive `error` fires, the schedule is paused automatically with an explanatory `pause_note`. A successful fire or a resume resets the counter.

[Trigger](/agents-api/schedules/trigger) fires a schedule once immediately, even while paused, without affecting the regular cadence. Use it to test a template before the first scheduled fire.

## Consuming the results

Nobody is polling a scheduled session, so pair schedules with a [webhook](/agents-api/webhooks/overview): you receive a signed event when each scheduled session reaches a settled state, then fetch its answer with [Get session](/agents-api/sessions/retrieve). For batch inspection, list a schedule's sessions with the `schedule_id` filter on [List sessions](/agents-api/sessions/list); each fire's [run record](/agents-api/schedules/runs) also links to its session.

## Constraints

* An organization can have up to 20 schedules.
* Deleting a schedule stops future fires. Sessions already created keep running.

## Endpoints

| Method   | Path                                      | Description                                           |
| -------- | ----------------------------------------- | ----------------------------------------------------- |
| `POST`   | `/api/v2/schedules`                       | [Create a schedule](/agents-api/schedules/create)     |
| `GET`    | `/api/v2/schedules`                       | [List schedules](/agents-api/schedules/list)          |
| `GET`    | `/api/v2/schedules/{schedule_id}`         | [Retrieve a schedule](/agents-api/schedules/retrieve) |
| `PATCH`  | `/api/v2/schedules/{schedule_id}`         | [Update a schedule](/agents-api/schedules/update)     |
| `DELETE` | `/api/v2/schedules/{schedule_id}`         | [Delete a schedule](/agents-api/schedules/delete)     |
| `POST`   | `/api/v2/schedules/{schedule_id}/pause`   | [Pause a schedule](/agents-api/schedules/pause)       |
| `POST`   | `/api/v2/schedules/{schedule_id}/resume`  | [Resume a schedule](/agents-api/schedules/resume)     |
| `POST`   | `/api/v2/schedules/{schedule_id}/trigger` | [Trigger a schedule](/agents-api/schedules/trigger)   |
| `GET`    | `/api/v2/schedules/{schedule_id}/runs`    | [List schedule runs](/agents-api/schedules/runs)      |

## Next steps

<CardGroup cols={2}>
  <Card title="Webhooks" icon="bell" href="/agents-api/webhooks/overview">
    Get a signed event when each scheduled session settles.
  </Card>

  <Card title="Plans and limits" icon="gauge-high" href="/agents-api/plans-and-limits">
    How scheduled sessions count against your quota.
  </Card>
</CardGroup>
