Stan Tasks & Heartbeat
Create and manage Stan scheduled tasks -- actions Stan performs once or on a recurring schedule -- and configure the Stan heartbeat, a periodic run in which Stan acts on the user's standing instructions (watches).
All endpoints require authentication via X-API-Key header and the appropriate scope.
Scheduled Task Object
{
"_id": "task_abc001",
"userId": "user_456",
"organizationId": "org_xyz",
"name": "Daily workflow audit",
"executionMode": "llm",
"action": "Audit my workflows and report any that failed overnight",
"schedule": { "type": "recurring", "cron": "0 9 * * *", "timezone": "UTC" },
"modelId": "model_abc123",
"status": "active",
"lastRunAt": "2025-02-15T09:00:00Z",
"lastRunStatus": "success",
"lastRunResult": "All workflows ran successfully.",
"nextRunAt": "2025-02-16T09:00:00Z",
"runCount": 14,
"createdAt": "2025-02-01T08:00:00Z",
"updatedAt": "2025-02-15T09:00:00Z"
}
| Field | Description |
|---|---|
executionMode | llm (Stan runs action as an instruction, using modelId) or tool (Stan runs the tool toolName with toolParams directly, without a model) |
schedule | type is once (runs at runAt) or recurring (runs on the 5-field cron expression), in timezone |
status | active, running, paused, completed, or failed |
lastRunAt, lastRunStatus, lastRunResult | When the task last ran, success or failed, and what it produced |
nextRunAt | When the task runs next |
runCount | How many times the task has run |
GET /api/v1/stan/tasks
List all scheduled tasks for the authenticated user. It pages with limit and cursor (Pagination).
Scope: stan:execute
Response 200 OK
{
"data": [
{
"_id": "task_abc001",
"userId": "user_456",
"name": "Daily workflow audit",
"executionMode": "llm",
"action": "audit_workflows",
"schedule": { "type": "recurring", "cron": "0 9 * * *", "timezone": "UTC" },
"modelId": "model_abc123",
"status": "active",
"lastRunAt": "2025-02-15T09:00:00Z",
"nextRunAt": "2025-02-16T09:00:00Z",
"runCount": 14,
"createdAt": "2025-02-01T08:00:00Z",
"updatedAt": "2025-02-15T09:00:00Z"
}
],
"meta": { "total": 1, "limit": 50, "nextCursor": null, "requestId": "req_abc123" }
}
Tasks are listed newest first; completed tasks are left out.
POST /api/v1/stan/tasks
Create a new scheduled task.
Scope: stan:execute
Request Body
{
"name": "Daily workflow audit",
"action": "Audit my workflows and report any that failed overnight",
"schedule": { "type": "recurring", "cron": "0 9 * * *", "timezone": "UTC" },
"modelId": "model_abc123"
}
| Field | Type | Required | Description |
|---|---|---|---|
name | string | Yes | Human-readable task name |
schedule | object | Yes | type: once or recurring. A recurring schedule needs cron (5 fields, for example 0 9 * * *); a once schedule needs runAt (ISO 8601 datetime). timezone is an IANA name (default UTC) |
action | string | LLM mode | The instruction Stan runs each time |
modelId | string | LLM mode | Model the task runs on: a model ID, vendor model ID, or model name you can use (stored as the model ID) |
executionMode | string | No | llm or tool. Without it, a task with toolName and no action is tool mode, otherwise llm |
toolName | string | Tool mode | Tool the task runs directly |
toolParams | object | No | Parameters for toolName |
description | string | No | Task description |
An invalid schedule (missing or invalid cron, missing or invalid runAt, or another type) or a modelId that does not resolve to a model you can use returns 400 validation-error.
Response 201 Created
data is the full Scheduled Task object.
GET /api/v1/stan/tasks/:id
Get details for a single scheduled task.
Scope: stan:execute
Path Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
id | string | Yes | Task ID |
Response 200 OK
Returns the full Scheduled Task object.
PATCH /api/v1/stan/tasks/:id
Update an existing scheduled task.
Scope: stan:execute
Path Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
id | string | Yes | Task ID |
Request Body
{
"name": "Updated task name",
"schedule": { "type": "recurring", "cron": "0 10 * * *", "timezone": "UTC" }
}
| Field | Type | Required | Description |
|---|---|---|---|
name | string | No | Human-readable task name |
action | string | No | The instruction Stan runs |
schedule | object | No | The whole schedule, as for create |
modelId | string | No | Model used to execute the task |
Response 200 OK
The updated scheduled task.
DELETE /api/v1/stan/tasks/:id
Delete a scheduled task.
Scope: stan:execute
Path Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
id | string | Yes | Task ID |
Response 204 No Content
POST /api/v1/stan/tasks/:id/pause
Pause a scheduled task. Paused tasks remain configured but stop firing until resumed.
Scope: stan:execute
Path Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
id | string | Yes | Task ID |
Response 200 OK
The task, as GET /stan/tasks/:id shows it, status paused.
POST /api/v1/stan/tasks/:id/resume
Resume a previously paused task.
Scope: stan:execute
Path Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
id | string | Yes | Task ID |
Response 200 OK
The task, as GET /stan/tasks/:id shows it, status active.
Heartbeat Object
{
"enabled": true,
"intervalMinutes": 30,
"modelId": "model_abc123",
"lastRunAt": "2025-02-15T09:00:00Z",
"runCount": 12,
"recentRuns": [
{ "at": "2025-02-15T09:00:00Z", "notified": false, "summary": "HEARTBEAT_OK (nothing needed attention)" }
],
"monitors": [
{
"id": "Pq7Lm2Xc9RtY4vBnK",
"instruction": "Watch my deployed apps and tell me if any stops responding.",
"enabled": true,
"origin": "user",
"createdAt": "2025-02-01T08:00:00Z",
"updatedAt": "2025-02-01T08:00:00Z"
}
],
"brief": "### Watch 1 (monitor id: Pq7Lm2Xc9RtY4vBnK)\nWatch my deployed apps and tell me if any stops responding."
}
| Field | Description |
|---|---|
enabled | Whether the heartbeat runs on its interval (false until turned on) |
intervalMinutes | Minutes between runs (default 30, at least 5) |
modelId | Model the heartbeat runs on. When it is not set, the model of the user's Stan session is used |
lastRunAt, runCount, recentRuns | When it last ran, how many runs it has made, and its last 12 runs (at, notified, summary). Present once it has run |
monitors | The standing instructions (watches) each run acts on: id, instruction, state (notes Stan keeps between runs, when set), enabled, origin, createdAt, updatedAt |
brief | The enabled watches as one text, the way each run reads them (empty when there are none) |
GET /api/v1/stan/heartbeat
Get the current heartbeat configuration for the authenticated user, with its watches.
Scope: stan:execute
Response 200 OK
data is the Heartbeat object.
PATCH /api/v1/stan/heartbeat
Update the heartbeat configuration.
Scope: stan:execute
Request Body
{
"enabled": true,
"intervalMinutes": 60,
"standingInstructions": "Watch my deployed apps and tell me if any stops responding."
}
| Field | Type | Required | Description |
|---|---|---|---|
enabled | boolean | No | Whether the heartbeat runs on its interval |
intervalMinutes | integer | No | Run interval in minutes (minimum: 5) |
modelId | string | No | Model the heartbeat runs on |
standingInstructions | string | No | Adds one watch with this instruction (existing watches are kept) |
Response 200 OK
data is the updated Heartbeat object.
POST /api/v1/stan/heartbeat/monitors
Add one watch to the heartbeat. Existing watches are kept. Adding a watch does not turn the heartbeat on; use PATCH /stan/heartbeat with enabled: true for that.
Scope: stan:execute
Request Body
{
"instruction": "Every night check my deployed workflows for failed runs and fix or report them."
}
| Field | Type | Required | Description |
|---|---|---|---|
instruction | string | Yes | Plain-language watch: what to watch, what to do about it, and what needs your approval |
If an enabled watch with the same instruction already exists (ignoring case and extra spaces), that watch is returned and no copy is added.
Response 201 Created
{
"data": {
"id": "Pq7Lm2Xc9RtY4vBnK",
"instruction": "Every night check my deployed workflows for failed runs and fix or report them.",
"enabled": true,
"createdAt": "2025-02-01T08:00:00Z",
"updatedAt": "2025-02-01T08:00:00Z",
"origin": "user"
},
"meta": { "requestId": "req_abc123" }
}
Returns 400 validation-error if instruction is missing or blank.
PATCH /api/v1/stan/heartbeat/monitors/:id
Edit one watch. Other watches are not changed.
Scope: stan:execute
Path Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
id | string | Yes | Watch ID (monitors[].id in the Heartbeat object) |
Request Body
{
"state": "A/B test started 2026-06-23, evaluate 2026-06-30",
"enabled": true
}
| Field | Type | Required | Description |
|---|---|---|---|
instruction | string | No | New instruction for the watch |
state | string | No | Notes kept on the watch between heartbeat runs |
enabled | boolean | No | false pauses the watch without removing it; true resumes it |
Response 200 OK
The updated watch: its id, instruction, state, enabled, origin, createdAt and updatedAt.
Returns 404 not-found if you have no watch with this ID.
DELETE /api/v1/stan/heartbeat/monitors/:id
Remove one watch. Other watches are not changed. To pause a watch instead, set enabled: false with PATCH.
Scope: stan:execute
Path Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
id | string | Yes | Watch ID |
Response 204 No Content
Returns 404 not-found if you have no watch with this ID.
POST /api/v1/stan/heartbeat/run
Run the configured heartbeat checks on demand and return results immediately.
Scope: stan:execute
Response 200 OK
{
"data": {
"ran": true,
"notified": true,
"report": "1 deployment idle"
},
"meta": { "requestId": "req_abc123" }
}
report is what the heartbeat found and did (HEARTBEAT_OK (nothing needed attention) when nothing did), and notified is true when it had something to report. When no standing instructions are set, nothing runs and the response is { "ran": false, "report": "..." } (in data), with report explaining that there is nothing to do.