Create, list, update, and archive schedules with natural language in a Forward Session.
Use natural language in a Forward Session to create, list, update, and archive schedules.
In addition to calling the API, end users can describe a task and its timing in the web app or an IM Channel. The Agent creates the Schedule, which then runs automatically without requiring the original Session to remain online.
A Schedule can use files enabled in the Template / Identity Config during execution. Attachments in the creating conversation are not automatically copied to the Schedule. To configure dedicated files, specify them in the
Before managing schedules, enable the corresponding Schedule managed capabilities in the effective configuration of the current Template or Identity:
Example for updating an existing Template:
If different Identities under the same Template need different Schedule capabilities, set individual switches by tool name in Identity Config:
Tools omitted from Identity Config inherit the Template baseline. Set an individual tool to
With a valid default Forward MCP configuration, interactive Sessions can see all four tools after a new request refreshes the configuration, even when Schedule is disabled. An existing custom tool with the same name is preserved. Tool visibility does not grant permission: calls still validate the effective Template and Identity switches and resource access permissions.
Both are business errors in tool results with
In the conversation, specify:
For monitoring tasks, specify the frequency, business date, year, start and end times, and trigger condition. The Agent asks follow-up questions if required information is missing.
After creation, the Agent returns the result. You can also ask it to show the newly created Schedule and confirm its name, trigger rule, and timezone.
The following describes creation failures from
MCP error codes in the following table are in
Natural-language creation uses
These scenarios do not always return an MCP business result, so checking only
Execution content uses nonempty
Do not always interpret
Each actual MCP creation request is processed independently, without automatic deduplication by Session, Turn, or arguments. Do not automatically replay creation when the outcome is unknown. Legacy-tool replay rules for the same trusted invocation identifier are not a universal idempotency guarantee for all entry points either.
You can list visible schedules and filter by name, task content, or status. For example:
You can change the task name, description, execution content, execution time, frequency, and monitoring window. For example:
Specify a task precisely by Schedule ID, or search by keywords in its name, description, or execution content. Updates are limited to tasks under the current Session's Owner and Identity. If a query matches multiple tasks, none are updated; the Agent returns candidates and asks you to specify a Schedule ID. If nothing matches, no new task is created.
The Agent uses
Provide at least one of
When updating cron or interval, omitted monitoring window boundaries remain unchanged. Switching to once clears the inherited monitoring window; nonempty start_at / stop_at cannot be set for once. Changing an interval rule recalculates subsequent trigger times from the update time; if the rule is unchanged, the existing next trigger time is preserved.
For example, to move a daily cron task to 10 AM while preserving its timezone and monitoring window, the tool parameters are:
Clear the end time while keeping other settings:
Uniquely identify a task by keywords and replace its execution content (the original task has only one initial message):
Change the task to run once in 10 minutes:
Archive a Schedule by its ID or by its name or task content. You can still say "delete" in natural language, but the system does not physically delete data. For example:
If multiple schedules match, the Agent does not archive any of them. It returns the candidates so that you can select one by Schedule ID. In natural-language management, "delete" archives the Schedule: no new Schedule Runs are created, the Schedule remains retrievable by ID or with
To receive create, query, update, or archive tool results in your application, subscribe to Schedule management tool result Webhooks. These notifications are independent of Schedule Run execution success or failure. Successful creation and archiving reuse the existing
Existing explicit subscriptions must add the new event;
resources array of HTTP Create or Update Schedule. The current natural-language create and update tools do not offer a resources parameter; HTTP API file configuration and execution do not depend on the managed tool switches described on this page.
Prerequisites
Before managing schedules, enable the corresponding Schedule managed capabilities in the effective configuration of the current Template or Identity:
- Create schedules:
create_forward_schedule - List schedules:
list_forward_schedules - Update schedules:
update_forward_schedule - Archive schedules:
delete_forward_schedule
schedule bundle configures all four capabilities together; they can also be configured independently by tool name. managed_tool_config is a top-level Template request field and can be configured through the following endpoints:
- Create a Template:
POST /api/v1/forward/templates - Update a Template:
POST /api/v1/forward/templates/{template_id}
enabled_tools replaces the complete Forward managed capability baseline. Include any other managed capabilities that must remain enabled.
You can also set enabled_tools to ["schedule"] to enable create, query, update, and archive together. Existing configurations that explicitly list only the create, query, and archive tools do not automatically enable updates; add update_forward_schedule or switch to the schedule bundle.
Override by Identity
If different Identities under the same Template need different Schedule capabilities, set individual switches by tool name in Identity Config:
null to remove its override, or set managed_tool_config: null to clear all overrides. See Upsert Identity Config for complete merge and conflict rules.
Existing Identities can still use identity_config.tools.<name>.enabled=false to disable an inherited managed tool. New integrations should use identity_config.managed_tool_config.
Tool visibility and enablement
With a valid default Forward MCP configuration, interactive Sessions can see all four tools after a new request refreshes the configuration, even when Schedule is disabled. An existing custom tool with the same name is preserved. Tool visibility does not grant permission: calls still validate the effective Template and Identity switches and resource access permissions.
| Tool result error code | Meaning and action |
|---|---|
schedule_feature_disabled | The capability is disabled and the operation is not performed. The Agent should ask the user to enable Schedule in the template page’s Tools section and save. If already enabled, an administrator should check Identity overrides. Users without configuration permission should contact the assistant administrator. |
schedule_configuration_changed | The current Session has not applied the newly enabled configuration. The user should send a new request and, if needed, reopen the Session to refresh it. |
retryable=false; the Agent must not automatically repeat the call. After enabling Schedule, the user should also send a new request to refresh the configuration.
These are not new HTTP errors for the Schedule CRUD API. The switches do not affect direct Schedule API calls or pause existing Schedules. Schedule execution Sessions do not expose management tools. The legacy Custom Tool path retains its previous behavior and does not follow the rule that disabled tools remain visible.
Create a schedule
In the conversation, specify:
- When to run, such as every day at 9:00 AM, every Monday at 10:00 AM, or in two hours.
- What the task should do.
- The required output.
- The timezone. If omitted, the default is
Asia/Shanghai.
Recurring tasks
One-time tasks
Fixed-interval tasks
Creation failures and error codes
The following describes creation failures from create_forward_schedule, so integrators can read error codes, show the reason, and decide what to do next. Handle these separately from HTTP Create Schedule, errors from query/update/archive tools, and Run execution or message delivery failures after creation.
To receive creation failure callbacks, subscribe to Schedule management tool result Webhooks. The tables below cover the existing stable business error codes for creation entry points. Cases without a detailed code or with an uncertain outcome are listed separately below.
Identify the error entry point first
| Entry point | Failure indicator | Error code location |
|---|---|---|
| Business result from a Forward Builtin MCP tool | is_error=true; HTTP 200 can also indicate a business failure | structured_content.error_code |
| Tool result event from the legacy Custom Tool | is_error=true on user.tool_result or user.custom_tool_result | Parse the text of a type=text item in content as JSON, then read error.code |
| MCP request-level error | HTTP non-2xx, using the HTTP error envelope | error.code, although some errors omit this field; also read error.type, HTTP status, and request_id when available |
| Creation failure Webhook (when subscribed) | Event type is forward.schedule.create_failed | data.error.code; also includes category, message, and requires_input |
error.message, structured_content.message, and natural-language response text are not guaranteed to be stable. Do not branch by matching message text. When a single call encounters multiple issues, it returns the first error encountered, not all validation errors at once.
Time rules and business error codes
MCP error codes in the following table are in structured_content.error_code; legacy-tool codes are in the parsed error.code. Webhook-specific differences are described below.
| Error code | Applicable entry points | Failure scenario | Recommended action |
|---|---|---|---|
trigger_policy_time_too_soon | MCP, legacy tool | The once target time is less than or equal to the server's current time, or the supplied stop_at is less than or equal to the current time | Check the actual current time, full date, and timezone. Confirm the user's intent again before using a future time; do not simply change a past date to the next day |
trigger_policy_too_frequent | MCP, legacy tool | interval is shorter than 1 minute, or cron has more than 5 fields (including expressions with seconds) | Use at least 1 minute for recurring tasks and a 5-field cron expression; use once for one-time reminders |
invalid_trigger_policy | MCP, legacy tool | The expression is missing or cannot be parsed, a required timezone cannot be parsed, the time window is invalid, or another policy validation fails, such as delay on a type other than once, delay supplied together with expression, or an invalid duration | Correct the policy according to the rules below. Structural errors such as a missing policy object or type in MCP may return HTTP 400 first; see “Parameter and permission failures” |
invalid_sinks | MCP, legacy tool | Notification target configuration derived from the IM source fails validation, for example because required target information is missing or routing is invalid | Check the channel binding and notification target before sending a new request. The model must not supply sinks itself to override the source |
schedule_feature_disabled | MCP | The current Template or Identity has not enabled this Schedule capability | Enable and save it in the template tool configuration, or ask an administrator to check Identity overrides; send a new request after correction, without automatic retries |
schedule_configuration_changed | MCP | The capability is enabled in the current configuration, but the Session has not yet applied the corresponding tool configuration | Send a new request to refresh the Session configuration; if still unavailable, reopen the Session. Do not retry automatically |
schedule_owner_unsupported | MCP | The current owner and its credential capabilities do not yet support Schedule creation | Ask an administrator to check Schedule support for that owner; retrying the unchanged request cannot resolve it |
Policy rules
| Type or field | Valid rules and boundaries |
|---|---|
once.expression | A one-time absolute time must be strictly later than the server's current time. once is exempt from the 1-minute minimum interval; a reminder 10 seconds in the future can be created |
once.delay | Relative one-time reminders use an ISO 8601 duration such as PT10S or PT2M. Supported only by tool entry points; the server converts it to an absolute time. Cannot be supplied together with expression |
interval.expression | Use an ISO 8601 duration of at least 1 minute, such as PT1M, PT15M, or P1D. PT30S returns a frequency-too-high error; 30s has an invalid format and returns a policy-format error |
cron.expression | Use 5-field cron, such as 0 9 * * *; expressions with 6 or more fields are rejected as too frequent |
timezone | Defaults to Asia/Shanghai when omitted from the tool. An absolute time with an offset is interpreted as that absolute instant; a time without an offset is interpreted in the specified timezone |
start_at / stop_at | Times must be parseable. stop_at must be later than the current time and, when both are set, later than start_at. once does not support these two window fields |
cron, once, or interval. MCP does not accept manual; the HTTP direct-creation convention that supports manual does not apply to this tool.
Parameter and permission failures
These scenarios do not always return an MCP business result, so checking only structured_content.error_code is insufficient.
| Scenario | Legacy-tool result | MCP synchronous response | Recommended action |
|---|---|---|---|
| Wrong tool argument types, invalid fields, missing execution content, name or description over the limit, or unsupported control characters | Usually invalid_request | HTTP 400, error.type=invalid_request_error, possibly without error.code | Correct the arguments before resubmitting |
Missing trigger_policy or type, or an unsupported type | invalid_trigger_policy | HTTP 400, invalid_request_error, possibly without a detailed code | Complete the policy; use only types supported by the tool |
The model supplies ownership/source fields such as user_id, identity_id, template_id, environment_id, sinks, or metadata | invalid_request | HTTP 400, invalid_request_error, possibly without a detailed code | Remove these fields; ownership and source are determined by the current Session |
| Source identity or Session context is missing or mismatched, or current identity/resource access validation is denied | invalid_identity; some ownership conflicts still use invalid_request | HTTP 403, error.type=permission_error; some context exceptions may use other HTTP errors | Check identity, resource authorization, and the current Session; reopen the Session or contact an administrator if necessary |
| Calling a Schedule management tool again in a Session created by Schedule execution | schedule_tool_forbidden_in_schedule_run | HTTP 403, permission_error, possibly without a detailed code | Return to a normal user Session to create the task, avoiding recursive creation |
| The tool does not exist or the Session is not allowed to use it | There may be no result event for that tool | HTTP 404 not_found_error or HTTP 403 permission_error, possibly without a detailed code | Check tool configuration and the Session; do not treat this as a frequency or time problem |
initial_events, or the compatible instruction field. Event type must be user.message, and content must not be empty. MCP validates field structure differently from the legacy tool, so the same invalid input can produce different responses at the two entry points.
Current response compatibility differences
| Scenario | Synchronous response and Webhook differences |
|---|---|
| The source IM channel is disabled | The current MCP synchronous call returns HTTP 500 api_error, possibly without a detailed code; the legacy synchronous tool result falls back to invalid_request. A subscribed creation failure Webhook normalizes it to invalid_sinks |
| The current owner does not support Schedule | MCP business results return schedule_owner_unsupported; the legacy synchronous tool result still returns invalid_request. In the corresponding Webhook, MCP retains schedule_owner_unsupported, while the legacy tool retains invalid_request and marks category=forbidden |
| Some ownership conflicts | The legacy synchronous tool result may return invalid_request; a subscribed failure Webhook may normalize it to invalid_identity with category=forbidden. The MCP synchronous call may also return an HTTP error without a detailed code |
invalid_request as a user argument error; it may also represent a rejection or exception not yet differentiated by the legacy entry point. A normalized Webhook error code does not imply that the synchronous response necessarily contains the same field.
Failure examples
MCP: recurring task interval of 30 seconds
Fortrigger_policy={"type":"interval","expression":"PT30S"}, an example business result follows. HTTP status is 200, but the caller must still handle the failure indicated by is_error=true.
Legacy tool: one-time target time has passed
Assume the server's current time is already later than2026-07-29T11:00:00+08:00. The following is the parsed JSON from content[].text in the tool result event; the event itself also has is_error=true.
schedule_id is not guaranteed to exist on failure; do not require it to be an empty string. When the legacy tool is rejected by recursive isolation, the result may contain only error; tool_name, success, and trigger policy fields are not guaranteed to be populated.
MCP: invalid arguments without a detailed error code
For example, when the request omits the policy object required by the tool, the HTTP 400 response can be:Creation failure Webhook
After subscribing toforward.schedule.create_failed, the relevant fields in the event's data are:
requires_input=false does not mean automatic retries are allowed. A failure Webhook may not be produced if the source cannot be verified. Failure to persist or deliver a notification, or to write back a tool result, does not establish that the Schedule was not created.
System errors, uncertain outcomes, and retries
| Situation | Caller action |
|---|---|
| An explicit time, policy, capability, or argument rejection | Correct the cause or clarify the user's intent before resubmitting; repeatedly sending the same arguments cannot resolve it |
| HTTP 401 / 403 | Handle as an authentication or permission issue; do not let the model guess identity or override ownership fields |
| HTTP 5xx, timeout, disconnection, or no result received | Retain available request/Session identifiers. Query Schedules first to confirm whether creation succeeded before deciding to create again; these situations can occur after creation has been committed |
| No tool call; the model asks a follow-up question or returns only natural language | There may be no creation error code; response text alone cannot establish creation success or failure |
| The task was created, but subsequent execution or delivery failed | Handle according to the Schedule Run or notification delivery result; do not classify it as a creation failure |
schedule_not_found, schedule_archived, and schedule_match_ambiguous belong to management scenarios for existing Schedules and must not be presented as routine creation validation errors. Integrator-defined top-level fields such as error_code, error_message, operation, and rule_description are not a unified response structure guaranteed across the entry points above.
List schedules
You can list visible schedules and filter by name, task content, or status. For example:
Update a Schedule
You can change the task name, description, execution content, execution time, frequency, and monitoring window. For example:
Update tool parameters
The Agent uses update_forward_schedule to make changes. The following are tool parameters, not the HTTP Update Schedule request body. Callers do not need to construct internal MCP calls themselves.
| Parameter | Type | Required | Description |
|---|---|---|---|
| schedule_id | string | Either this or query | Nonempty Schedule ID identifying the task precisely. |
| query | string | Either this or schedule_id | Nonempty keywords matching the name, description, or initial event content. Updates only when exactly one task matches. |
| name | string | No | Nonempty name, at most 256 characters. |
| description | string | No | Description, at most 2048 characters; an empty string clears it. |
| instruction | string | No | Nonempty execution instruction; applicable only when the original task has exactly one user.message initial event. Mutually exclusive with initial_events. |
| initial_events | array | No | Fully replaces the initial event list with 1–50 events. Each contains only type: user.message and nonempty content. Multiple events retain their array order. Mutually exclusive with instruction. |
| trigger_policy | object | No | Partially updates the trigger policy by subfield. Must contain at least one field; omitted fields keep their current values. |
name, description, instruction, initial_events, or trigger_policy. All parameters reject null and unknown fields. The tool does not accept identity_id, template_id, environment_id, resources, sinks, execution, metadata, or state fields; use the corresponding management APIs to change these settings.
trigger_policy supports these subfields:
| Field | Type | Description |
|---|---|---|
| type | string | cron, once, or interval; the tool does not accept manual. Switching type also requires a new expression, or delay for once. |
| expression | string | A 5-field cron expression, an absolute time for once, or an ISO 8601 duration for interval. Mutually exclusive with delay. |
| delay | string | A positive relative delay for once only, such as PT10M; replaces the previous absolute trigger time. |
| timezone | string | IANA timezone; omission preserves the original timezone. |
| start_at | string | Start time; accepts local time with second precision interpreted using timezone, or RFC3339 with an offset. An empty string clears this boundary. |
| stop_at | string | End time; same format as start_at. An empty string clears this boundary. |
Update results
| Tool result status | Meaning |
|---|---|
| updated | Updated; returns the task ID, name, schedule_status, initial_events_version, trigger policy, and next_trigger_at when available. |
| unchanged | The normalized request matches the current settings; the version, updated_at, and next trigger time are not updated. |
| not_found | No task matches query; no task is updated or created. |
| multiple_matches | Multiple tasks match query; candidates are returned. Specify one schedule_id before updating. |
status is the result of this tool operation; schedule_status is the task's active / paused state. Updating a paused task does not automatically resume it; unpause the Schedule separately when needed. An exact ID that does not exist or is archived returns a tool business error.
initial_events_version increments only when execution content actually changes; name and trigger rule changes do not increment it. Existing Runs continue to follow the input version and binding rules, and updates do not rewrite historical records. next_trigger_at is a tool result field, not a new field in the HTTP Schedule object.
Archive a schedule
Archive a Schedule by its ID or by its name or task content. You can still say "delete" in natural language, but the system does not physically delete data. For example:
include_archived=true, and historical runs remain available. Existing pending or running runs are not canceled.
View execution results
- A Schedule created in the web app returns results to the original Session. If you go offline, pending results are delivered the next time you open that Session.
- A Schedule created in an IM Channel sends results to the corresponding Channel Session.
- You can also use the API to list Schedule Runs or get a Schedule Run.
Receive management tool results
To receive create, query, update, or archive tool results in your application, subscribe to Schedule management tool result Webhooks. These notifications are independent of Schedule Run execution success or failure. Successful creation and archiving reuse the existing forward.schedule.created and forward.schedule.archived events.
The update tool sends forward.schedule.updated when it actually saves a change and returns updated. When the configuration matches the current values and the result is unchanged, no notification is sent, but the result remains available in the current Session. Deterministic business failures, no matches, or multiple matches are reported through forward.schedule.update_failed. Business-failure notifications are not guaranteed when infrastructure fails or the commit outcome is uncertain. A missing callback does not establish that the update failed.
For example, subscribe to notifications of actual changes and deterministic update failures:
* subscriptions receive it automatically. The update success event provides a summary including schedule_id, updated_at, and schedule_version, without task instructions or complete initial events. This notification covers only management tool calls; calling HTTP Update Schedule directly does not produce this success event.
Limitations
- The minimum granularity or interval for
cronandintervaltriggers is one minute. - A relative delay for a
oncetrigger is exempt from the minimum frequency, but the delay must be greater than zero. - While a Schedule is running, it cannot create, list, update, or archive other schedules. This prevents self-replication and recursive schedule management.