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

# Scheduled tasks API

> Create and manage cron-scheduled tasks that prompt your agents on a schedule

# Scheduled tasks API

Schedule recurring prompts for your agents using cron expressions. You can create, update, list, and delete scheduled tasks through these endpoints.

<Note>Scheduled tasks are processed by an inline scheduler that runs inside the API process. The scheduler polls for pending tasks every 30 seconds and executes up to 10 tasks per cycle. Each task is dispatched as an HTTP request to the target agent with a 30-second timeout.</Note>

<Note>Each tick claims due tasks atomically using `SELECT ... FOR UPDATE SKIP LOCKED`. Tasks are only marked `completed` when the agent returns a `2xx` response. Failed dispatches are re-queued with backoff or marked `failed` once `attempts` reaches `maxAttempts`. See [Execution lifecycle](#execution-lifecycle) below.</Note>

<Note>All scheduled task endpoints require session authentication. Tasks are scoped to the authenticated user — you can only manage tasks for agents you own.</Note>

## List scheduled tasks

```http theme={"dark"}
GET /api/scheduled-tasks
```

Returns all scheduled tasks for the authenticated user, sorted by creation date (newest first).

### Query parameters

| Parameter | Type   | Required | Description              |
| --------- | ------ | -------- | ------------------------ |
| `agentId` | string | No       | Filter tasks by agent ID |

### Response

```json theme={"dark"}
{
  "tasks": [
    {
      "id": "task_abc123",
      "name": "Daily check-in",
      "description": "Morning status update",
      "cronSchedule": "0 9 * * *",
      "prompt": "Give me a morning briefing on today's schedule and priorities.",
      "enabled": true,
      "lastRun": "2026-03-22T09:00:00Z",
      "nextRun": "2026-03-23T09:00:00Z",
      "status": "pending",
      "attempts": 0,
      "maxAttempts": 5,
      "lastError": null,
      "agentId": "agent_456",
      "createdAt": "2026-03-15T12:00:00Z",
      "updatedAt": "2026-03-22T09:00:00Z"
    }
  ],
  "count": 1
}
```

### Task object

| Field          | Type           | Description                                                                                                                   |
| -------------- | -------------- | ----------------------------------------------------------------------------------------------------------------------------- |
| `id`           | string         | Unique task identifier                                                                                                        |
| `name`         | string         | Task name                                                                                                                     |
| `description`  | string \| null | Optional task description                                                                                                     |
| `cronSchedule` | string         | Cron expression (5 or 6 fields)                                                                                               |
| `prompt`       | string         | The prompt sent to the agent on each run                                                                                      |
| `enabled`      | boolean        | Whether the task is active                                                                                                    |
| `lastRun`      | string \| null | ISO 8601 timestamp of the last execution                                                                                      |
| `nextRun`      | string \| null | ISO 8601 timestamp of the next scheduled execution                                                                            |
| `status`       | string         | Current execution state. One of `pending`, `running`, `completed`, `failed`. See [Execution lifecycle](#execution-lifecycle). |
| `attempts`     | number         | Number of dispatch attempts made for the current run. Reset to `0` on the next scheduled trigger.                             |
| `maxAttempts`  | number         | Maximum dispatch attempts before the task is marked `failed`. Defaults to `5`.                                                |
| `lastError`    | string \| null | Error message from the most recent failed dispatch, or `null` if the last run succeeded.                                      |
| `agentId`      | string         | ID of the agent this task targets                                                                                             |
| `createdAt`    | string         | ISO 8601 creation timestamp                                                                                                   |
| `updatedAt`    | string         | ISO 8601 last-updated timestamp                                                                                               |

### Errors

| Code | Description                     |
| ---- | ------------------------------- |
| 401  | Unauthorized — no valid session |
| 500  | Failed to list tasks            |

## Create a scheduled task

```http theme={"dark"}
POST /api/scheduled-tasks
```

Creates a new scheduled task for one of your agents. The cron schedule is validated to ensure it contains 5 or 6 fields.

### Request body

| Field          | Type    | Required | Description                                                                       |
| -------------- | ------- | -------- | --------------------------------------------------------------------------------- |
| `name`         | string  | Yes      | Task name                                                                         |
| `cronSchedule` | string  | Yes      | Cron expression with 5 or 6 fields (for example, `"0 9 * * *"` for daily at 9 AM) |
| `prompt`       | string  | Yes      | The prompt to send to the agent on each run                                       |
| `agentId`      | string  | Yes      | ID of the agent to target. Must belong to you.                                    |
| `description`  | string  | No       | Optional description                                                              |
| `enabled`      | boolean | No       | Whether the task starts active. Defaults to `true`.                               |

### Example request

```json theme={"dark"}
{
  "name": "Weekly fan report",
  "cronSchedule": "0 10 * * 1",
  "prompt": "Generate a weekly fan engagement report with streaming stats and growth trends.",
  "agentId": "agent_456",
  "description": "Runs every Monday at 10 AM"
}
```

### Response (201 Created)

Returns the created task object.

### Errors

| Code | Description                                                                            |
| ---- | -------------------------------------------------------------------------------------- |
| 400  | Missing required fields (`name`, `cronSchedule`, `prompt`, and `agentId` are required) |
| 400  | Invalid cron schedule (expected 5–6 fields)                                            |
| 401  | Unauthorized — no valid session                                                        |
| 404  | Agent not found or does not belong to you                                              |
| 500  | Task creation failed                                                                   |

## Update a scheduled task

```http theme={"dark"}
PUT /api/scheduled-tasks
```

Updates an existing scheduled task. Only the fields you include in the request body are changed.

### Request body

| Field          | Type    | Required | Description                |
| -------------- | ------- | -------- | -------------------------- |
| `taskId`       | string  | Yes      | ID of the task to update   |
| `name`         | string  | No       | Updated task name          |
| `description`  | string  | No       | Updated description        |
| `cronSchedule` | string  | No       | Updated cron expression    |
| `prompt`       | string  | No       | Updated prompt             |
| `enabled`      | boolean | No       | Enable or disable the task |

### Example request

```json theme={"dark"}
{
  "taskId": "task_abc123",
  "enabled": false
}
```

### Response

Returns the updated task object.

### Errors

| Code | Description                              |
| ---- | ---------------------------------------- |
| 400  | `taskId` is required                     |
| 401  | Unauthorized — no valid session          |
| 404  | Task not found or does not belong to you |
| 500  | Task update failed                       |

## Delete a scheduled task

```http theme={"dark"}
DELETE /api/scheduled-tasks
```

Permanently deletes a scheduled task.

### Request body

| Field    | Type   | Required | Description              |
| -------- | ------ | -------- | ------------------------ |
| `taskId` | string | Yes      | ID of the task to delete |

### Response

```json theme={"dark"}
{
  "success": true,
  "taskId": "task_abc123"
}
```

### Errors

| Code | Description                              |
| ---- | ---------------------------------------- |
| 400  | `taskId` is required                     |
| 401  | Unauthorized — no valid session          |
| 404  | Task not found or does not belong to you |
| 500  | Task deletion failed                     |

## Execution lifecycle

Each scheduled task moves through a small state machine driven by the inline scheduler. The `status` field on the task object reflects the current state.

### Status values

| Status      | Meaning                                                                                                                                                                                                 |
| ----------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `pending`   | The task is waiting for its `nextRun` time. The scheduler will pick it up on the next tick after `nextRun <= NOW()`.                                                                                    |
| `running`   | The scheduler has claimed this task and is currently dispatching it to the target agent.                                                                                                                |
| `completed` | The most recent dispatch succeeded — the agent returned a `2xx` response. The task will return to `pending` and `nextRun` will advance to the next cron tick.                                           |
| `failed`    | All `maxAttempts` dispatches failed. The task is no longer retried automatically. Inspect `lastError` and re-enable manually by issuing a `PUT` with `enabled: true` after fixing the underlying issue. |

### Atomic claim

Each scheduler tick claims due tasks using `SELECT ... FOR UPDATE SKIP LOCKED` inside a single atomic statement. This guarantees that overlapping ticks, concurrent replicas, or restarted workers can never claim the same task twice. Up to 10 tasks are claimed per tick.

### Retry behavior

When a dispatch fails — the agent returns a non-`2xx` status, the request times out, or the network call raises — the task is settled as follows:

* If `attempts < maxAttempts`, the task is re-queued. `nextRun` is set to `NOW() + backoff`, `status` is reset to `pending`, and `lastError` is updated. The task is picked up again on a future tick.
* If `attempts >= maxAttempts`, the task is marked `failed` and stops retrying.

**Backoff schedule** (linear with a hard cap):

| Attempt | Backoff before next retry |
| ------- | ------------------------- |
| 1       | 30 s                      |
| 2       | 60 s                      |
| 3       | 90 s                      |
| 4       | 120 s                     |
| 5       | 150 s                     |
| 6+      | 300 s (capped)            |

The backoff is `min(30 × attempts, 300)` seconds. The default `maxAttempts` is `5`.

### Stale-claim recovery

If a worker dies mid-dispatch (process crash, container restart, network partition), the task can be left in `running` state with no worker driving it forward. On every tick, the scheduler scans for tasks that have been `running` for more than 10 minutes and returns them to `pending` with `nextRun = NOW()`, `lastError = "Recovered after stale worker lock"`. They are then picked up on the next tick.

You should never see a task stuck in `running` for more than 10 minutes during normal operation.
