Skip to main content
Agent integrations

Manage schedules with natural language

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 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
Templates do not enable these capabilities by default. The 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: Example for creating a Template:
curl -s -X POST 'https://api.qoder.com/api/v1/forward/templates' \
  -H "Authorization: Bearer $QODER_ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Schedule assistant",
    "model": "ultimate",
    "environment_id": "env_xxx",
    "managed_tool_config": {
      "enabled_tools": [
        "create_forward_schedule",
        "list_forward_schedules",
        "update_forward_schedule",
        "delete_forward_schedule"
      ]
    }
  }'
Example for updating an existing Template:
curl -s -X POST 'https://api.qoder.com/api/v1/forward/templates/tmpl_xxx' \
  -H "Authorization: Bearer $QODER_ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "managed_tool_config": {
      "enabled_tools": [
        "create_forward_schedule",
        "list_forward_schedules",
        "update_forward_schedule",
        "delete_forward_schedule"
      ]
    }
  }'
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:
{
  "identity_config": {
    "managed_tool_config": {
      "create_forward_schedule": {
        "enabled": false
      }
    }
  }
}
Tools omitted from Identity Config inherit the Template baseline. Set an individual tool to 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 codeMeaning and action
schedule_feature_disabledThe 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_changedThe 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.
Both are business errors in tool results with 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

Every weekday at 9:00 AM, summarize AI industry news from the past 24 hours.
Select the five most important stories and include source links.
Every Monday at 10:00 AM, summarize last week's project progress, risks, and action items.
Format the result as a Markdown table.

One-time tasks

Remind me at 4:00 PM today to prepare the project review materials.
In two hours, review this report and list every data inconsistency.

Fixed-interval tasks

From 9:00 AM to 6:00 PM on May 1, 2027, check flight prices every 30 minutes.
If the price drops below CNY 600, tell me the flight, time, and purchase link.
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.

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 pointFailure indicatorError code location
Business result from a Forward Builtin MCP toolis_error=true; HTTP 200 can also indicate a business failurestructured_content.error_code
Tool result event from the legacy Custom Toolis_error=true on user.tool_result or user.custom_tool_resultParse the text of a type=text item in content as JSON, then read error.code
MCP request-level errorHTTP non-2xx, using the HTTP error envelopeerror.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_faileddata.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 codeApplicable entry pointsFailure scenarioRecommended action
trigger_policy_time_too_soonMCP, legacy toolThe 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 timeCheck 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_frequentMCP, legacy toolinterval 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_policyMCP, legacy toolThe 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 durationCorrect 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_sinksMCP, legacy toolNotification target configuration derived from the IM source fails validation, for example because required target information is missing or routing is invalidCheck the channel binding and notification target before sending a new request. The model must not supply sinks itself to override the source
schedule_feature_disabledMCPThe current Template or Identity has not enabled this Schedule capabilityEnable 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_changedMCPThe capability is enabled in the current configuration, but the Session has not yet applied the corresponding tool configurationSend a new request to refresh the Session configuration; if still unavailable, reopen the Session. Do not retry automatically
schedule_owner_unsupportedMCPThe current owner and its credential capabilities do not yet support Schedule creationAsk an administrator to check Schedule support for that owner; retrying the unchanged request cannot resolve it
Policy rules
Type or fieldValid rules and boundaries
once.expressionA 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.delayRelative 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.expressionUse 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.expressionUse 5-field cron, such as 0 9 * * *; expressions with 6 or more fields are rejected as too frequent
timezoneDefaults 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_atTimes 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
Natural-language creation uses 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.
ScenarioLegacy-tool resultMCP synchronous responseRecommended action
Wrong tool argument types, invalid fields, missing execution content, name or description over the limit, or unsupported control charactersUsually invalid_requestHTTP 400, error.type=invalid_request_error, possibly without error.codeCorrect the arguments before resubmitting
Missing trigger_policy or type, or an unsupported typeinvalid_trigger_policyHTTP 400, invalid_request_error, possibly without a detailed codeComplete 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 metadatainvalid_requestHTTP 400, invalid_request_error, possibly without a detailed codeRemove 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 deniedinvalid_identity; some ownership conflicts still use invalid_requestHTTP 403, error.type=permission_error; some context exceptions may use other HTTP errorsCheck 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 executionschedule_tool_forbidden_in_schedule_runHTTP 403, permission_error, possibly without a detailed codeReturn 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 itThere may be no result event for that toolHTTP 404 not_found_error or HTTP 403 permission_error, possibly without a detailed codeCheck tool configuration and the Session; do not treat this as a frequency or time problem
Execution content uses nonempty 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
ScenarioSynchronous response and Webhook differences
The source IM channel is disabledThe 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 ScheduleMCP 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 conflictsThe 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
Do not always interpret 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
For trigger_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.
{
  "is_error": true,
  "content": [
    {
      "type": "text",
      "text": "Trigger policy granularity must be at least 1 minute."
    }
  ],
  "structured_content": {
    "error_code": "trigger_policy_too_frequent",
    "message": "Trigger policy granularity must be at least 1 minute."
  }
}
Legacy tool: one-time target time has passed
Assume the server's current time is already later than 2026-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.
{
  "tool_name": "create_forward_schedule",
  "success": false,
  "name": "11点开会提醒",
  "trigger_policy": {
    "type": "once",
    "expression": "2026-07-29T11:00:00+08:00",
    "timezone": "Asia/Shanghai"
  },
  "error": {
    "code": "trigger_policy_time_too_soon",
    "message": "schedule time too soon"
  }
}
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:
{
  "type": "error",
  "request_id": "req_example",
  "error": {
    "type": "invalid_request_error",
    "message": "invalid Forward MCP tool arguments"
  }
}
Creation failure Webhook
After subscribing to forward.schedule.create_failed, the relevant fields in the event's data are:
{
  "tool_call": {
    "id": "stcall_example",
    "name": "create_forward_schedule",
    "session_id": "sess_example",
    "invocation_path": "mcp"
  },
  "error": {
    "code": "trigger_policy_time_too_soon",
    "category": "invalid_request",
    "message": "Schedule trigger time is too soon.",
    "requires_input": false
  }
}
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

SituationCaller action
An explicit time, policy, capability, or argument rejectionCorrect the cause or clarify the user's intent before resubmitting; repeatedly sending the same arguments cannot resolve it
HTTP 401 / 403Handle as an authentication or permission issue; do not let the model guess identity or override ownership fields
HTTP 5xx, timeout, disconnection, or no result receivedRetain 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 languageThere may be no creation error code; response text alone cannot establish creation success or failure
The task was created, but subsequent execution or delivery failedHandle according to the Schedule Run or notification delivery result; do not classify it as a creation failure
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. 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:
List all my current scheduled tasks.
Which of my scheduled tasks are related to flights?
Show my archived scheduled tasks.

Update a Schedule

You can change the task name, description, execution content, execution time, frequency, and monitoring window. For example:
Move the daily morning AI news summary to 10 AM Beijing time, keeping all other settings unchanged.
Change the flight price check to run every 15 minutes, keeping the original start and end times.
Update Schedule sched_019f00112233445566778899aabbccdd:
Summarize 10 news items with a source link for each, keeping the execution time unchanged.
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.

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.
ParameterTypeRequiredDescription
schedule_idstringEither this or queryNonempty Schedule ID identifying the task precisely.
querystringEither this or schedule_idNonempty keywords matching the name, description, or initial event content. Updates only when exactly one task matches.
namestringNoNonempty name, at most 256 characters.
descriptionstringNoDescription, at most 2048 characters; an empty string clears it.
instructionstringNoNonempty execution instruction; applicable only when the original task has exactly one user.message initial event. Mutually exclusive with initial_events.
initial_eventsarrayNoFully 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_policyobjectNoPartially updates the trigger policy by subfield. Must contain at least one field; omitted fields keep their current values.
Provide at least one of 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:
FieldTypeDescription
typestringcron, once, or interval; the tool does not accept manual. Switching type also requires a new expression, or delay for once.
expressionstringA 5-field cron expression, an absolute time for once, or an ISO 8601 duration for interval. Mutually exclusive with delay.
delaystringA positive relative delay for once only, such as PT10M; replaces the previous absolute trigger time.
timezonestringIANA timezone; omission preserves the original timezone.
start_atstringStart time; accepts local time with second precision interpreted using timezone, or RFC3339 with an offset. An empty string clears this boundary.
stop_atstringEnd time; same format as start_at. An empty string clears this boundary.
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:
{
  "schedule_id": "sched_019f00112233445566778899aabbccdd",
  "trigger_policy": {
    "expression": "0 10 * * *"
  }
}
Clear the end time while keeping other settings:
{
  "schedule_id": "sched_019f00112233445566778899aabbccdd",
  "trigger_policy": {
    "stop_at": ""
  }
}
Uniquely identify a task by keywords and replace its execution content (the original task has only one initial message):
{
  "query": "AI news summary",
  "instruction": "Summarize 10 AI news items from the past 24 hours, with a source link for each."
}
Change the task to run once in 10 minutes:
{
  "schedule_id": "sched_019f00112233445566778899aabbccdd",
  "trigger_policy": {
    "type": "once",
    "delay": "PT10M"
  }
}

Update results

Tool result statusMeaning
updatedUpdated; returns the task ID, name, schedule_status, initial_events_version, trigger policy, and next_trigger_at when available.
unchangedThe normalized request matches the current settings; the version, updated_at, and next trigger time are not updated.
not_foundNo task matches query; no task is updated or created.
multiple_matchesMultiple 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:
Delete Schedule sched_019f00112233445566778899aabbccdd.
Delete the daily morning AI news summary task.
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 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.
Each Schedule Run uses an independent execution Session and does not mix context with the Session that created the Schedule.

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:
{
  "events": [
    "forward.schedule.updated",
    "forward.schedule.update_failed"
  ]
}
Existing explicit subscriptions must add the new event; * 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 cron and interval triggers is one minute.
  • A relative delay for a once trigger 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.