Skip to main content
Schedules

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

HeaderRequiredDescription
AuthorizationYesBearer <PAT or SAT>
Content-TypeYesapplication/json
Idempotency-KeyNoOptional idempotency key for unsafe requests.

Body parameters

ParameterTypeRequiredDescription
identity_idstringYesForward Identity ID that owns the Schedule.
template_idstringYesForward Template ID to execute.
namestringYesSchedule name.
descriptionstringNoSchedule description.
initial_eventsarrayYesEvents injected at each execution. Current design supports user.message.
executionobjectNoExecution policy. Defaults are applied when omitted.
trigger_policyobject|nullNoTrigger policy. Omitted or null becomes {"type":"manual"}.
environment_idstringYesExecution environment.
sinksarray|nullNoUp to one Pairing Sink. Omitted, null, or [] means no Sink.
metadataobjectNoCustom 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.
FieldTypeRequiredDescription
typestringYescron, once, interval, or manual.
expressionstringConditionalTrigger expression. Required for cron, once, and interval; not needed for manual.
timezonestringConditionalIANA timezone, such as Asia/Shanghai. Required for cron; required for once only when expression has no offset; optional for interval and manual.
upcoming_runs_atarrayResponse onlyUpcoming trigger times in UTC ISO 8601. The current implementation returns [] or the next scheduled time only.
last_run_atstring|nullResponse onlyMost recent trigger time.
typeRequired inputDescription
crontype, expression, timezoneRepeats by a 5-field cron expression in the given IANA timezone.
oncetype, expression, optional timezoneRuns once at an ISO 8601 time. timezone is required when the expression has no offset.
intervaltype, expressionRepeats by an ISO 8601 duration, such as PT15M.
manualtypeNever runs automatically. Trigger with the Run Schedule endpoint.
typeexpression formatExampleNotes
cronStandard 5-field cron0 9 * * *Minute-level calendar schedule. Seconds and 6-field cron are not supported.
onceISO 8601 absolute time2026-06-23T09:00:00 or 2026-06-23T01:00:00ZRuns once. The target time must be at least one minute in the future.
intervalISO 8601 durationPT15M, PT1H, P1DFixed interval schedule. Minimum interval is one minute.
manualOmitted or empty-Does not create scheduled runs.

Execution policy

FieldTypeDefaultDescription
session_modestringnew_sessionnew_session or reuse_session.
max_concurrent_runsinteger1Maximum concurrent runs for this Schedule.
max_attemptsinteger1Maximum actual attempts per Run. Allowed values: 1 or 2; values outside this range are rejected.
timeout_msinteger300000Timeout for one attempt.
session_modeDescription
new_sessionCreates a new execution Session for each trigger. Previous context is not reused.
reuse_sessionForward 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.

IM sink delivery

Use a Pairing ID to configure up to one im_channel Sink:
{
  "sinks": [
    {
      "type": "im_channel",
      "channel_pairing_id": "pair_019eabc123"
    }
  ]
}
FieldTypeRequiredDescription
typestringYesMust be im_channel.
channel_pairing_idstringYesAn active Pairing ID owned by the current user. It must match the Identity and Template in this request.
Callers cannot submit channel_id, channel_type, an external channel user, Conversation, or other raw routing fields. Forward resolves the delivery route through the Pairing, and public responses return only type and channel_pairing_id.
sinks shapeResult
Omitted, null, or []Creates a Schedule without an explicit Sink and returns [].
One valid Pairing SinkStores and returns the normalized Pairing Sink.
More than one item, invalid fields or type, or an unavailable PairingReturns 400 invalid_request_error / unsupported_sinks_input without creating the Schedule.

Example request

curl -s -X POST 'https://api.qoder.com/api/v1/forward/schedules' \
  -H "Authorization: Bearer $QODER_ACCESS_TOKEN" \
  -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": 2,
    "timeout_ms": 300000
  },
  "environment_id": "env_019e64e01a137caf953ac2ac7b42ec5c",
  "sinks": [
    {
      "type": "im_channel",
      "channel_pairing_id": "pair_019eabc123"
    }
  ]
}'

Example response

HTTP 200 OK
{
  "id": "sched_019f00112233445566778899aabbccdd",
  "identity_id": "idn_019eabc123",
  "template_id": "tmpl_support",
  "name": "Daily tech brief",
  "description": "Generate a daily technology news summary",
  "status": "active",
  "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": 2,
    "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": [
    {
      "type": "im_channel",
      "channel_pairing_id": "pair_019eabc123"
    }
  ],
  "metadata": {},
  "created_at": "2026-06-22T10:00:00Z",
  "updated_at": "2026-06-22T10:00:00Z"
}

Errors

HTTPTypeCodeTrigger
400invalid_request_errorinvalid_trigger_policyTrigger policy type or expression is invalid.
400invalid_request_errortrigger_policy_too_frequentTrigger interval is less than one minute.
400invalid_request_errortrigger_policy_time_too_soononce target time is too soon.
400invalid_request_errorinvalid_requestexecution.max_attempts is not in the 1..2 range.
400invalid_request_errorunsupported_sinks_inputRequest body contains sinks.
404not_found_erroridentity_not_foundIdentity does not exist.
404not_found_errortemplate_not_foundTemplate does not exist.
401authentication_errorauthentication_requiredThe PAT or SAT is invalid or expired.

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.