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 or SAT> |
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. |
sinks | array|null | No | Delivery targets for execution results. The array form is retained for compatibility; currently, at most one item is allowed. |
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 | Maximum actual attempts per Run. Allowed values: 1 or 2; values outside this range are rejected. |
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. |
max_attempts=2 means the server may automatically retry once after the first execution fails. Whether a retry actually happens depends on the failure type — parameter errors, permission errors, concurrency limits, timeouts, or connection interruptions are not guaranteed to be retried. Clients can check the attempt field on a Schedule Run to see how many attempts were made.
Omitting execution.max_attempts at creation uses the default value 1. When explicitly provided, only integers 1 or 2 are accepted.
Delivery target
sinks retains its array form for compatibility. Omitting it, passing null, or passing [] creates a Schedule without a delivery target. One valid item configures delivery. Two or more items return HTTP 400 unsupported_sinks_input. Each item must use one of these public formats:
identity_resolution.mode=fixed, be enabled and bound, and match the Schedule Identity and Template.
external_id is the channel-native opaque user or group ID. Reachability is not probed when the Schedule is created. target.type=group supports only a root group, not a thread or topic.
Send /target in a channel IM conversation to obtain the target configuration for that conversation.
Runtime delivery failures are recorded as push_status=failed on the corresponding Run and do not change the Agent Run status.
Example request
Example response
HTTP 200 OK
Response fields
| Field | Type | Description |
|---|---|---|
| Return value | object | The complete Schedule object that was created. |
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 | invalid_request | execution.max_attempts is not in the 1..2 range. |
| 400 | invalid_request_error | unsupported_sinks_input | The number, type, or fields of sinks are invalid, or the fixed Channel is unavailable, belongs to another user, or does not match the execution context. |
| 404 | not_found_error | identity_not_found | Identity does not exist. |
| 404 | not_found_error | template_not_found | Template does not exist. |
| 401 | authentication_error | authentication_required | The PAT or SAT is invalid or expired. |
Notes
- When
sinksis omitted,null, or[], the response containssinks: []for compatibility with older clients and nullable-field serialization. - Omitting
sinks, passingnull, or passing[]returnssinks: []. - A
manualSchedule can be triggered only through the Run Schedule endpoint. - A
onceSchedule is automatically archived after its first scheduled Run reaches a terminal state.