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

# Schedules

> Run a saved agent once, at intervals, or on a cron schedule.

First [create a saved agent](/docs/managing-agents) and keep its ID.

## Schedules

A schedule stores a run request (`input`, optional `conversation`, `previous_response_id`, `context_management`, and `metadata`) plus a timing rule, and starts a normal agent run each time the rule fires. The page calls one firing a tick.

### Create a schedule

<CodeGroup>
  ```ts TypeScript SDK theme={null}
  import { SDK } from '@meetkai/mka1';

  const sdk = new SDK({ bearerAuth: 'Bearer <mka1-api-key>' });

  const schedule = await sdk.agentSchedules.createAgentSchedule({
    agentId: 'agt_123',
    xOnBehalfOf: '<end-user-id>', // optional — attribute the request to one of your end users
    createAgentScheduleRequest: {
      name: 'weekday-morning-briefing',
      schedule: {
        type: 'cron',
        cronExpression: '0 9 * * 1-5',
        timezone: 'America/Los_Angeles',
      },
      input: 'Summarize the release notes published in the last 24 hours.',
      metadata: { source: 'briefing' },
    },
  });

  console.log(schedule.id, schedule.status);
  ```

  ```python Python SDK theme={null}
  from meetkai_mka1 import SDK

  sdk = SDK(bearer_auth="Bearer <mka1-api-key>")

  schedule = sdk.agent_schedules.create_agent_schedule(
      agent_id="agt_123",
      x_on_behalf_of="<end-user-id>",  # optional — attribute the request to one of your end users
      name="weekday-morning-briefing",
      schedule={
          "type": "cron",
          "cron_expression": "0 9 * * 1-5",
          "timezone": "America/Los_Angeles",
      },
      input="Summarize the release notes published in the last 24 hours.",
      metadata={"source": "briefing"},
  )

  print(schedule.id, schedule.status)
  ```

  ```csharp C# SDK theme={null}
  using MeetKai.MKA1;
  using MeetKai.MKA1.Types.Components;
  using MeetKai.MKA1.Types.Requests;

  var sdk = new SDK(bearerAuth: "Bearer <mka1-api-key>");

  var created = await sdk.AgentSchedules.CreateAgentScheduleAsync(
      agentId: "agt_123",
      body: new MeetKai.MKA1.Types.Components.CreateAgentScheduleRequest()
      {
          Name = "weekday-morning-briefing",
          Schedule = AgentScheduleSpec.CreateCron(new AgentScheduleSpecCron()
          {
              Type = TypeCron.Cron,
              CronExpression = "0 9 * * 1-5",
              Timezone = "America/Los_Angeles",
          }),
          Input = CreateAgentScheduleRequestInputUnion.CreateStr(
              "Summarize the release notes published in the last 24 hours."
          ),
          Metadata = new Dictionary<string, string> { { "source", "briefing" } },
      },
      xOnBehalfOf: "<end-user-id>" // optional — attribute the request to one of your end users
  );

  var schedule = created.AgentSchedule!;
  Console.WriteLine($"{schedule.Id} {schedule.Status}");
  ```

  ```bash CLI theme={null}
  mka1 agent-schedules create \
    --body '{
      "name": "weekday-morning-briefing",
      "schedule": {
        "type": "cron",
        "cron_expression": "0 9 * * 1-5",
        "timezone": "America/Los_Angeles"
      },
      "input": "Summarize the release notes published in the last 24 hours.",
      "metadata": {
        "source": "briefing"
      }
    }' \
    --agent-id agt_123 \
    -H 'X-On-Behalf-Of: <end-user-id>'
  ```

  ```bash Bash theme={null}
  curl https://apigw.mka1.com/api/v1/agents/agt_123/schedules \
    --request POST \
    --header 'Content-Type: application/json' \
    --header 'Authorization: Bearer <mka1-api-key>' \
    --header 'X-On-Behalf-Of: <end-user-id>' \
    --data '{
      "name": "weekday-morning-briefing",
      "schedule": {
        "type": "cron",
        "cron_expression": "0 9 * * 1-5",
        "timezone": "America/Los_Angeles"
      },
      "input": "Summarize the release notes published in the last 24 hours.",
      "metadata": {
        "source": "briefing"
      }
    }'
  ```
</CodeGroup>

The call returns `201 Created` with a schedule object (`sched_...`) in status `active`. A `502` means nothing was saved; retry the create.

The `schedule` object picks the kind:

| `type`     | Required                                | Optional               | Fires                                                                                                                                                                                                           |
| ---------- | --------------------------------------- | ---------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `once`     | `run_at` (ISO 8601 date-time)           | `timezone`             | Once, at `run_at`. A tick missed during an outage is caught up for 10 minutes. The schedule then moves to `completed`.                                                                                          |
| `interval` | `interval_seconds` (60 to 31,536,000)   | `start_at`, `timezone` | Every `interval_seconds`, aligned to the Unix epoch rather than to creation time: `3600` fires on the hour, whenever you created it. `start_at` suppresses firings before it and does not shift that alignment. |
| `cron`     | `cron_expression` (1 to 200 characters) | `timezone`             | On every match of the expression, evaluated in `timezone`.                                                                                                                                                      |

`timezone` defaults to `UTC` and only affects `cron`. `run_at` and `start_at` are absolute instants: write them with an offset or a trailing `Z`.

```json theme={null}
{ "type": "once", "run_at": "2026-09-01T09:00:00Z" }
```

```json theme={null}
{ "type": "interval", "interval_seconds": 3600, "start_at": "2026-09-01T00:00:00Z" }
```

`input` takes the same shapes as a run: a string, or an array of input items. `metadata` is a string map; every run the schedule starts gets it, plus `agent_schedule_id`.

A schedule remembers the identity that created it, including `X-On-Behalf-Of`, and every run it starts executes as that identity. Runs from a schedule created for an end user are listed under that end user's run scope; org admins also see them in the team-wide run list.

### List, retrieve, and update

<CodeGroup>
  ```ts TypeScript SDK theme={null}
  const schedules = await sdk.agentSchedules.listAgentSchedules({
    agentId: 'agt_123',
    xOnBehalfOf: '<end-user-id>',
  });
  console.log(schedules.data.map((s) => `${s.id} ${s.status} runs=${s.runCount}`));

  const schedule = await sdk.agentSchedules.getAgentSchedule({
    agentId: 'agt_123',
    scheduleId: 'sched_123',
    xOnBehalfOf: '<end-user-id>',
  });
  console.log(schedule.lastRunAt, schedule.lastRunId);
  ```

  ```python Python SDK theme={null}
  schedules = sdk.agent_schedules.list_agent_schedules(
      agent_id="agt_123",
      x_on_behalf_of="<end-user-id>",
  )
  print([(s.id, s.status, s.run_count) for s in schedules.data])

  schedule = sdk.agent_schedules.get_agent_schedule(
      agent_id="agt_123",
      schedule_id="sched_123",
      x_on_behalf_of="<end-user-id>",
  )
  print(schedule.last_run_at, schedule.last_run_id)
  ```

  ```csharp C# SDK theme={null}
  var list = await sdk.AgentSchedules.ListAgentSchedulesAsync(
      agentId: "agt_123",
      xOnBehalfOf: "<end-user-id>"
  );
  foreach (var s in list.AgentScheduleList!.Data)
  {
      Console.WriteLine($"{s.Id} {s.Status} runs={s.RunCount}");
  }

  var detail = await sdk.AgentSchedules.GetAgentScheduleAsync(
      agentId: "agt_123",
      scheduleId: "sched_123",
      xOnBehalfOf: "<end-user-id>"
  );
  Console.WriteLine($"{detail.AgentSchedule!.LastRunAt} {detail.AgentSchedule!.LastRunId}");
  ```

  ```bash CLI theme={null}
  mka1 agent-schedules list \
    --agent-id agt_123 \
    --limit 20 \
    --order desc \
    -H 'X-On-Behalf-Of: <end-user-id>'

  mka1 agent-schedules get \
    --agent-id agt_123 \
    --schedule-id sched_123 \
    -H 'X-On-Behalf-Of: <end-user-id>'
  ```

  ```bash Bash theme={null}
  curl 'https://apigw.mka1.com/api/v1/agents/agt_123/schedules?limit=20&order=desc' \
    --header 'Authorization: Bearer <mka1-api-key>' \
    --header 'X-On-Behalf-Of: <end-user-id>'

  curl https://apigw.mka1.com/api/v1/agents/agt_123/schedules/sched_123 \
    --header 'Authorization: Bearer <mka1-api-key>' \
    --header 'X-On-Behalf-Of: <end-user-id>'
  ```
</CodeGroup>

Update takes any subset of the create fields, and at least one:

<CodeGroup>
  ```ts TypeScript SDK theme={null}
  const updated = await sdk.agentSchedules.updateAgentSchedule({
    agentId: 'agt_123',
    scheduleId: 'sched_123',
    xOnBehalfOf: '<end-user-id>',
    updateAgentScheduleRequest: {
      name: 'weekday-morning-briefing-v2',
      schedule: {
        type: 'cron',
        cronExpression: '30 8 * * 1-5',
        timezone: 'America/Los_Angeles',
      },
    },
  });
  console.log(updated.status); // "active"
  ```

  ```python Python SDK theme={null}
  updated = sdk.agent_schedules.update_agent_schedule(
      agent_id="agt_123",
      schedule_id="sched_123",
      x_on_behalf_of="<end-user-id>",
      name="weekday-morning-briefing-v2",
      schedule={
          "type": "cron",
          "cron_expression": "30 8 * * 1-5",
          "timezone": "America/Los_Angeles",
      },
  )
  print(updated.status)  # "active"
  ```

  ```csharp C# SDK theme={null}
  var updated = await sdk.AgentSchedules.UpdateAgentScheduleAsync(
      agentId: "agt_123",
      scheduleId: "sched_123",
      body: new MeetKai.MKA1.Types.Components.UpdateAgentScheduleRequest()
      {
          Name = "weekday-morning-briefing-v2",
          Schedule = AgentScheduleSpec.CreateCron(new AgentScheduleSpecCron()
          {
              Type = TypeCron.Cron,
              CronExpression = "30 8 * * 1-5",
              Timezone = "America/Los_Angeles",
          }),
      },
      xOnBehalfOf: "<end-user-id>"
  );
  Console.WriteLine(updated.AgentSchedule!.Status);
  ```

  ```bash CLI theme={null}
  mka1 agent-schedules update \
    --body '{
      "name": "weekday-morning-briefing-v2",
      "schedule": {
        "type": "cron",
        "cron_expression": "30 8 * * 1-5",
        "timezone": "America/Los_Angeles"
      }
    }' \
    --agent-id agt_123 \
    --schedule-id sched_123 \
    -H 'X-On-Behalf-Of: <end-user-id>'
  ```

  ```bash Bash theme={null}
  curl https://apigw.mka1.com/api/v1/agents/agt_123/schedules/sched_123 \
    --request POST \
    --header 'Content-Type: application/json' \
    --header 'Authorization: Bearer <mka1-api-key>' \
    --header 'X-On-Behalf-Of: <end-user-id>' \
    --data '{
      "name": "weekday-morning-briefing-v2",
      "schedule": {
        "type": "cron",
        "cron_expression": "30 8 * * 1-5",
        "timezone": "America/Los_Angeles"
      }
    }'
  ```
</CodeGroup>

Changing `schedule` re-creates the timer and sets `status` back to `active`, even if the schedule was paused. Changing any other field leaves the timer and the status alone.

A `502` from an update means the new spec was saved but the timer may not have been replaced; the status is unchanged. Repeat the update until it returns `200`.

### Pause, resume, and delete

<CodeGroup>
  ```ts TypeScript SDK theme={null}
  const paused = await sdk.agentSchedules.pauseAgentSchedule({
    agentId: 'agt_123',
    scheduleId: 'sched_123',
    xOnBehalfOf: '<end-user-id>',
  });
  console.log(paused.status); // "paused"

  const resumed = await sdk.agentSchedules.resumeAgentSchedule({
    agentId: 'agt_123',
    scheduleId: 'sched_123',
    xOnBehalfOf: '<end-user-id>',
  });
  console.log(resumed.status); // "active"

  const deleted = await sdk.agentSchedules.deleteAgentSchedule({
    agentId: 'agt_123',
    scheduleId: 'sched_123',
    xOnBehalfOf: '<end-user-id>',
  });
  console.log(deleted.deleted); // true
  ```

  ```python Python SDK theme={null}
  paused = sdk.agent_schedules.pause_agent_schedule(
      agent_id="agt_123",
      schedule_id="sched_123",
      x_on_behalf_of="<end-user-id>",
  )
  print(paused.status)  # "paused"

  resumed = sdk.agent_schedules.resume_agent_schedule(
      agent_id="agt_123",
      schedule_id="sched_123",
      x_on_behalf_of="<end-user-id>",
  )
  print(resumed.status)  # "active"

  deleted = sdk.agent_schedules.delete_agent_schedule(
      agent_id="agt_123",
      schedule_id="sched_123",
      x_on_behalf_of="<end-user-id>",
  )
  print(deleted.deleted)  # True
  ```

  ```csharp C# SDK theme={null}
  var paused = await sdk.AgentSchedules.PauseAgentScheduleAsync(
      agentId: "agt_123",
      scheduleId: "sched_123",
      xOnBehalfOf: "<end-user-id>"
  );
  Console.WriteLine(paused.AgentSchedule!.Status);

  var resumed = await sdk.AgentSchedules.ResumeAgentScheduleAsync(
      agentId: "agt_123",
      scheduleId: "sched_123",
      xOnBehalfOf: "<end-user-id>"
  );
  Console.WriteLine(resumed.AgentSchedule!.Status);

  var deleted = await sdk.AgentSchedules.DeleteAgentScheduleAsync(
      agentId: "agt_123",
      scheduleId: "sched_123",
      xOnBehalfOf: "<end-user-id>"
  );
  Console.WriteLine(deleted.Object!.Deleted);
  ```

  ```bash CLI theme={null}
  mka1 agent-schedules pause \
    --agent-id agt_123 \
    --schedule-id sched_123 \
    -H 'X-On-Behalf-Of: <end-user-id>'

  mka1 agent-schedules resume \
    --agent-id agt_123 \
    --schedule-id sched_123 \
    -H 'X-On-Behalf-Of: <end-user-id>'

  mka1 agent-schedules delete \
    --agent-id agt_123 \
    --schedule-id sched_123 \
    -H 'X-On-Behalf-Of: <end-user-id>'
  ```

  ```bash Bash theme={null}
  curl https://apigw.mka1.com/api/v1/agents/agt_123/schedules/sched_123/pause \
    --request POST \
    --header 'Authorization: Bearer <mka1-api-key>' \
    --header 'X-On-Behalf-Of: <end-user-id>'

  curl https://apigw.mka1.com/api/v1/agents/agt_123/schedules/sched_123/resume \
    --request POST \
    --header 'Authorization: Bearer <mka1-api-key>' \
    --header 'X-On-Behalf-Of: <end-user-id>'

  curl https://apigw.mka1.com/api/v1/agents/agt_123/schedules/sched_123 \
    --request DELETE \
    --header 'Authorization: Bearer <mka1-api-key>' \
    --header 'X-On-Behalf-Of: <end-user-id>'
  ```
</CodeGroup>

Delete returns `{ "object": "agent.schedule.deleted", "id": "sched_123", "deleted": true }`. Delete succeeds even when the scheduler is unreachable; a timer left behind that way is harmless. A repeated `DELETE` returns `404`.

Delete an agent's schedules before you delete the agent. Deleting the agent does not delete its schedules, and afterwards they cannot be reached, because a schedule is only addressable through `/agents/{agent_id}/schedules/...`.

### How runs are recorded

* Each tick creates a normal agent run, so it appears in the agent's run history with `metadata.agent_schedule_id` set.
* After the run, the schedule's `last_run_at`, `last_run_id`, and `run_count` are updated. A run that fails at the gateway is still recorded as a run (with `status: "failed"`) and still counts.
* There is no per-schedule run listing. To see a schedule's runs, list the agent's runs with the same `X-On-Behalf-Of` the schedule was created with and keep the ones whose `metadata.agent_schedule_id` matches. The console does the same to label a run as "schedule".

### Durability and failure

* Pause and resume act on the timer named by `temporal_schedule_id`; when that field is `null`, they return `409`.
* If a tick fires while the previous run is still executing, that tick is dropped rather than queued. Expect gaps in `run_count` on long-running agents with short intervals.
* Missed ticks are backfilled for up to 10 minutes after their scheduled time, for example after a service restart. Older misses are dropped.
* A tick that fails before its run is recorded is retried, up to 3 attempts. A retry can duplicate a run if the failure happened after the gateway accepted the request. A run that reaches the gateway and fails is recorded as failed and is not retried.
* A tick does nothing when the schedule is not `active`, or its agent has been deleted.

### Schedule reference

| Field                                                                 | Description                                                                                                                                                                  |
| --------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `id`                                                                  | `sched_...`                                                                                                                                                                  |
| `agent_id`                                                            | The agent the schedule runs.                                                                                                                                                 |
| `name`                                                                | Optional label, 1 to 120 characters.                                                                                                                                         |
| `status`                                                              | `active`, `paused`, `completed` (a `once` schedule that has fired), or `deleted`.                                                                                            |
| `schedule`                                                            | The timing rule: `type` plus `run_at`, `start_at`, `interval_seconds`, `cron_expression`, and `timezone` as applicable. Interval schedules fire on epoch-aligned boundaries. |
| `input`, `conversation`, `previous_response_id`, `context_management` | The stored run request.                                                                                                                                                      |
| `metadata`                                                            | Copied onto every run, with `agent_schedule_id` added.                                                                                                                       |
| `temporal_schedule_id`                                                | ID of the backing timer, or `null` when there is none (pause and resume then return `409`).                                                                                  |
| `last_run_at`, `last_run_id`, `run_count`                             | Updated after each tick.                                                                                                                                                     |
| `created_at`, `updated_at`, `deleted_at`                              | ISO 8601 timestamps.                                                                                                                                                         |

## Troubleshooting

| Symptom                                                                                                   | Cause                                                                                                                                                                                                                                     | Fix                                                                                                                                                              |
| --------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| The bot never replies                                                                                     | `status` is not `active`. Anything else is acknowledged and dropped.                                                                                                                                                                      | Read the connector; `last_error` says why. Fix the cause, then activate.                                                                                         |
| The bot never replies                                                                                     | The chat or sender is not in `config.access`. Unlisted chats are dropped silently. Telegram group and supergroup IDs are negative numbers.                                                                                                | Delete the connector and create it again with the right allowlist; there is no update call.                                                                      |
| Telegram stopped delivering after a token change                                                          | The stored token is the old one; credentials cannot be edited.                                                                                                                                                                            | Delete the connector and create it again with the new token. Creation drops updates queued under the old binding.                                                |
| WhatsApp messages never reach the agent                                                                   | The app-level webhook is missing in Meta, or its values differ from setup.                                                                                                                                                                | Configure **WhatsApp → Production setup → Configure Webhooks** with the exact `callback_url` and `verify_token` from setup, subscribed to `messages`.            |
| WhatsApp replies are not sent                                                                             | The 24-hour customer-service window is closed.                                                                                                                                                                                            | Wait for the user to message again; the connector never sends template messages.                                                                                 |
| `403` on a connector endpoint                                                                             | The request carried `X-On-Behalf-Of`; create or activate was called with a session; the key lacks `read:agents` or `write:agents`, or the runtime scopes on create and activate; or someone other than the creating user called activate. | Drop the header. Use an API key with the scopes listed under [Before you start](/docs/agent-connectors#before-you-start). Activate with the creating user's key. |
| `400` at creation: "Telegram rejected the bot credentials" or "WhatsApp rejected the account credentials" | The token or app credentials are wrong.                                                                                                                                                                                                   | Check them and create again. A `502` instead means the provider was unreachable; retry.                                                                          |
| `409` at creation                                                                                         | The bot or phone number is already bound to another connector, possibly in another team.                                                                                                                                                  | Delete that connector first.                                                                                                                                     |
| `status: "error"` with `last_error.code` = `connector_identity_revoked`                                   | The API key behind the connector was revoked, disabled, or lost a runtime scope, or the creating user left the team.                                                                                                                      | Fix the key, then activate from the creating user's key. If that user is gone, delete the connector and create it again under another key.                       |
| `status: "error"` with `last_error.operation` = `register_webhook` or `unregister_webhook`                | The provider call failed; `http_status` and `error_code` are the provider's. After activate, it can also mean the stored credentials no longer match the bot or phone number.                                                             | Activate, or repeat the delete, once the provider is healthy. If the credentials no longer match, delete and recreate.                                           |
| A schedule never runs                                                                                     | `status` is `paused` or `completed`.                                                                                                                                                                                                      | Resume a paused schedule. A `completed` one has fired; create a new schedule.                                                                                    |
| A `once` schedule never runs                                                                              | `run_at` was already in the past.                                                                                                                                                                                                         | Create a new schedule with a future `run_at`.                                                                                                                    |
| A cron schedule fires at the wrong hour                                                                   | `timezone` is `UTC` by default. `0 9 * * 1-5` in `UTC` is early morning on the US west coast.                                                                                                                                             | Set `timezone`.                                                                                                                                                  |
| `400` on create with an interval                                                                          | `interval_seconds` is below 60.                                                                                                                                                                                                           | Raise it.                                                                                                                                                        |
| Ticks are missing from `run_count`                                                                        | The previous run was still executing when the next tick fired, so the tick was skipped.                                                                                                                                                   | Compare `last_run_at` with the run's duration and lengthen the interval.                                                                                         |
| `run_count` never increases                                                                               | The agent was deleted; a tick for a deleted agent creates no run.                                                                                                                                                                         | Nothing to do; the schedule cannot be reached without its agent. Delete schedules before their agent.                                                            |
| `502` on create                                                                                           | The scheduler refused the schedule. Nothing was kept.                                                                                                                                                                                     | Retry the create.                                                                                                                                                |
| `502` on update                                                                                           | The new spec was saved, but the timer may not have been replaced.                                                                                                                                                                         | Repeat the update until it returns `200`.                                                                                                                        |
