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

# Create a schedule

> Create a repeatable or manually triggered Template execution configuration.

`POST /api/v1/forward/schedules`

Creates a Schedule that binds one Identity, one Template, initial input events, trigger policy, and execution policy. Each trigger creates a separate Schedule Run.

## Headers

| Header            | Required | Description                                   |
| ----------------- | -------- | --------------------------------------------- |
| `Authorization`   | Yes      | `Bearer <PAT>`                                |
| `Content-Type`    | Yes      | `application/json`                            |
| `Idempotency-Key` | No       | Optional idempotency key for unsafe requests. |

## Body parameters

| Parameter        | Type         | Required | Description                                                                |
| ---------------- | ------------ | -------- | -------------------------------------------------------------------------- |
| `identity_id`    | string       | Yes      | Forward Identity ID that owns the Schedule.                                |
| `template_id`    | string       | Yes      | Forward Template ID to execute.                                            |
| `name`           | string       | Yes      | Schedule name.                                                             |
| `description`    | string       | No       | Schedule description.                                                      |
| `initial_events` | array        | Yes      | Events injected at each execution. Current design supports `user.message`. |
| `execution`      | object       | No       | Execution policy. Defaults are applied when omitted.                       |
| `trigger_policy` | object\|null | No       | Trigger policy. Omitted or `null` becomes `{"type":"manual"}`.             |
| `environment_id` | string       | Yes      | Execution environment.                                                     |
| `metadata`       | object       | No       | Custom metadata for labels or pass-through data only.                      |

## Trigger policy

`trigger_policy` is a typed object. Create and update requests accept only configuration fields: `type`, `expression`, and `timezone`. `upcoming_runs_at` and `last_run_at` are response-only fields computed by Forward.

| Field              | Type         | Required      | Description                                                                                                                                                  |
| ------------------ | ------------ | ------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `type`             | string       | Yes           | `cron`, `once`, `interval`, or `manual`.                                                                                                                     |
| `expression`       | string       | Conditional   | Trigger expression. Required for `cron`, `once`, and `interval`; not needed for `manual`.                                                                    |
| `timezone`         | string       | Conditional   | IANA timezone, such as `Asia/Shanghai`. Required for `cron`; required for `once` only when `expression` has no offset; optional for `interval` and `manual`. |
| `upcoming_runs_at` | array        | Response only | Upcoming trigger times in UTC ISO 8601. The current implementation returns `[]` or the next scheduled time only.                                             |
| `last_run_at`      | string\|null | Response only | Most recent trigger time.                                                                                                                                    |

| `type`     | Required input                            | Description                                                                              |
| ---------- | ----------------------------------------- | ---------------------------------------------------------------------------------------- |
| `cron`     | `type`, `expression`, `timezone`          | Repeats by a 5-field cron expression in the given IANA timezone.                         |
| `once`     | `type`, `expression`, optional `timezone` | Runs once at an ISO 8601 time. `timezone` is required when the expression has no offset. |
| `interval` | `type`, `expression`                      | Repeats by an ISO 8601 duration, such as `PT15M`.                                        |
| `manual`   | `type`                                    | Never runs automatically. Trigger with the Run Schedule endpoint.                        |

| `type`     | `expression` format    | Example                                         | Notes                                                                       |
| ---------- | ---------------------- | ----------------------------------------------- | --------------------------------------------------------------------------- |
| `cron`     | Standard 5-field cron  | `0 9 * * *`                                     | Minute-level calendar schedule. Seconds and 6-field cron are not supported. |
| `once`     | ISO 8601 absolute time | `2026-06-23T09:00:00` or `2026-06-23T01:00:00Z` | Runs once. The target time must be at least one minute in the future.       |
| `interval` | ISO 8601 duration      | `PT15M`, `PT1H`, `P1D`                          | Fixed interval schedule. Minimum interval is one minute.                    |
| `manual`   | Omitted or empty       | -                                               | Does not create scheduled runs.                                             |

## Execution policy

| Field                 | Type    | Default       | Description                                                              |
| --------------------- | ------- | ------------- | ------------------------------------------------------------------------ |
| `session_mode`        | string  | `new_session` | `new_session` or `reuse_session`.                                        |
| `max_concurrent_runs` | integer | 1             | Maximum concurrent runs for this Schedule.                               |
| `max_attempts`        | integer | 1             | Reserved. Current implementation records and validates it but runs once. |
| `timeout_ms`          | integer | 300000        | Timeout for one attempt.                                                 |

| `session_mode`  | Description                                                                                                                                             |
| --------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `new_session`   | Creates a new execution Session for each trigger. Previous context is not reused.                                                                       |
| `reuse_session` | Forward manages one fixed execution Session for this Schedule and reuses it across triggers. Callers cannot provide an arbitrary existing `session_id`. |

## Example request

```bash theme={null}
curl -s -X POST 'https://api.qoder.com/api/v1/forward/schedules' \
  -H "Authorization: Bearer $QODER_PAT" \
  -H "Content-Type: application/json" \
  -d '{
    "identity_id": "idn_019eabc123",
    "template_id": "tmpl_support",
    "name": "Daily tech brief",
    "description": "Generate a daily technology news summary",
    "initial_events": [
      {
        "type": "user.message",
        "content": "Summarize current technology news in five bullet points."
      }
    ],
    "trigger_policy": {
      "type": "cron",
      "expression": "0 9 * * *",
      "timezone": "Asia/Shanghai"
    },
    "execution": {
      "session_mode": "new_session",
      "max_concurrent_runs": 1,
      "max_attempts": 1,
      "timeout_ms": 300000
    },
    "environment_id": "env_019e64e01a137caf953ac2ac7b42ec5c"
  }'
```

## Example response

**HTTP 200 OK**

```json theme={null}
{
  "id": "sched_019f00112233445566778899aabbccdd",
  "identity_id": "idn_019eabc123",
  "template_id": "tmpl_support",
  "name": "Daily tech brief",
  "description": "Generate a daily technology news summary",
  "status": "active",
  "paused_reason": null,
  "initial_events": [
    {
      "type": "user.message",
      "content": "Summarize current technology news in five bullet points."
    }
  ],
  "execution": {
    "session_mode": "new_session",
    "max_concurrent_runs": 1,
    "max_attempts": 1,
    "timeout_ms": 300000
  },
  "trigger_policy": {
    "type": "cron",
    "expression": "0 9 * * *",
    "timezone": "Asia/Shanghai",
    "upcoming_runs_at": ["2026-06-23T01:00:00Z"]
  },
  "environment_id": "env_019e64e01a137caf953ac2ac7b42ec5c",
  "sinks": [],
  "metadata": {},
  "archived_at": null,
  "created_at": "2026-06-22T10:00:00Z",
  "updated_at": "2026-06-22T10:00:00Z"
}
```

## Errors

| HTTP | Type                    | Code                           | Trigger                                       |
| ---- | ----------------------- | ------------------------------ | --------------------------------------------- |
| 400  | `invalid_request_error` | `invalid_trigger_policy`       | Trigger policy type or expression is invalid. |
| 400  | `invalid_request_error` | `trigger_policy_too_frequent`  | Trigger interval is less than one minute.     |
| 400  | `invalid_request_error` | `trigger_policy_time_too_soon` | `once` target time is too soon.               |
| 400  | `invalid_request_error` | `unsupported_sinks_input`      | Request body contains `sinks`.                |
| 404  | `not_found_error`       | `identity_not_found`           | Identity does not exist.                      |
| 404  | `not_found_error`       | `template_not_found`           | Template does not exist.                      |

## Notes

* HTTP create requests do not accept `sinks`. Direct API-created schedules return `sinks: []`.
* `manual` schedules can only be triggered with `POST /api/v1/forward/schedules/{schedule_id}/run`.
* `once` schedules are automatically archived after their first scheduled run reaches a terminal state.

## Related

<CardGroup cols={2}>
  <Card title="Run a schedule" icon="play" href="/cloud-agents/api/forward/schedules/run" />

  <Card title="List schedules" icon="list" href="/cloud-agents/api/forward/schedules/list" />
</CardGroup>
