Tasks API
Schedule, run, and cancel automated tasks (config backups and AI agent tasks) with cron-based scheduling, timezones, and retries.
Overview
The Tasks API lets you create, manage, run, and cancel scheduled automation tasks. Tasks run on standard cron schedules with IANA timezone support and configurable retry/timeout behavior. Each run produces a separate execution record that tracks state, timing, output, and errors.
Scheduled tasks are served by the NetStacks Controller. All task endpoints live under /api/tasks, require a valid JWT bearer token, and require the Operator permission. Execution-history endpoints (below) require the Admin permission.
The router exposes three groups of endpoints, all nested under /api/tasks:
/api/tasks/schedules— General scheduled tasks of any type (full request body, including retry/timeout fields)./api/tasks/agent-schedules— A simplified interface for AI agent tasks (you pass apromptinstead of a free-formparametersobject)./api/tasks/executions/:id/cancel— Cancel a running or pending execution.
Five task types are accepted by the schema, but only two run today: backup and agent_task. The deployment, health_check, and custom_script types are accepted at create time but their executor is not yet implemented — a run of those types fails with a "not yet implemented" error. Schedule only backup and agent_task tasks until the others ship.
Endpoints
All paths below are relative to your Controller base URL (for example https://netstacks.example.net). Path parameters are UUIDs.
General schedules (all task types)
| Method | Path | Description | Success |
|---|---|---|---|
| GET | /api/tasks/schedules | List all scheduled tasks in the org | 200 |
| POST | /api/tasks/schedules | Create a scheduled task | 201 |
| GET | /api/tasks/schedules/:id | Get one task (full fields) | 200 |
| PUT | /api/tasks/schedules/:id | Update a task | 200 |
| DELETE | /api/tasks/schedules/:id | Delete a task | 204 |
| POST | /api/tasks/schedules/:id/run | Run immediately (background) | 202 |
| POST | /api/tasks/schedules/:id/toggle | Enable or disable a task | 200 |
Agent schedules (agent tasks only)
| Method | Path | Description | Success |
|---|---|---|---|
| GET | /api/tasks/agent-schedules | List the caller's agent task schedules | 200 |
| POST | /api/tasks/agent-schedules | Create an agent task schedule | 201 |
| GET | /api/tasks/agent-schedules/:id | Get one agent schedule | 200 |
| PUT | /api/tasks/agent-schedules/:id | Update an agent schedule | 200 |
| DELETE | /api/tasks/agent-schedules/:id | Delete an agent schedule | 204 |
| POST | /api/tasks/agent-schedules/:id/run | Run agent task now (background) | 202 |
| POST | /api/tasks/agent-schedules/:id/toggle | Enable or disable | 200 |
Executions
| Method | Path | Description | Success |
|---|---|---|---|
| POST | /api/tasks/executions/:id/cancel | Cancel a running/pending execution | 204 |
Execution records for agent tasks are listed through the admin-scoped agent-tasks router, not the schedules router: GET /api/admin/agent-tasks/history and GET /api/admin/agent-tasks/history/:execution_id. These require the Admin permission. See the Executions section.
Task Types & Parameters
The task_type field accepts these snake_case values: deployment, backup, health_check, custom_script, and agent_task. Each type reads its own keys from the free-form parameters object. Only backup and agent_task are executable today.
backup
Collects running configs from devices matching a filter and stores them as a config snapshot. Recognized parameters keys:
snapshot_name(string, optional)- Name for the created snapshot. Defaults to the task name when omitted.
device_filter(object, optional)- Selects which devices to back up. Supported keys are
siteanddevice_type. An empty object{}targets all devices in the org. credential_id(UUID string, optional)- Overrides the credential used for collection. When omitted, the device's default credential is used, then the org default.
{
"snapshot_name": "Nightly DC1 Core Backup",
"device_filter": { "site": "dc1", "device_type": "router" },
"credential_id": "f47ac10b-58cc-4372-a567-0e02b2c3d479"
}agent_task
Runs an AI agent prompt through the agent system. The only recognized parameter is prompt. When you use the /api/tasks/agent-schedules endpoints, you pass prompt as a top-level field and the Controller wraps it into parameters for you.
{ "prompt": "Review the last 7 days of config snapshots and flag anomalies." }These types are defined in the schema but their executors are not yet implemented; running them returns an error. Their parameter shapes are subject to change and are intentionally not documented here.
Cron Scheduling & Retries
Cron expressions
Schedules use standard 5-field cron syntax (minute hour day-of-month month day-of-week), validated server-side. The 6-field form with a leading seconds field is not used by the default parser — stick to 5 fields. Examples:
0 2 * * *— every day at 02:000 */6 * * *— every 6 hours0 9 * * 1-5— weekdays at 09:000 0 1 * *— first day of each month at midnight
The timezone must be a valid IANA identifier (for example America/New_York, Europe/London). It defaults to UTC when omitted. The Controller computes next_run_at in the requested timezone and returns it (as UTC) on the response.
Retries and timeout
On POST /api/tasks/schedules these are top-level request fields (not inside parameters):
| Field | Type | Default | Meaning |
|---|---|---|---|
| max_retries | integer | 3 | Retry attempts after a failed run |
| retry_delay_seconds | integer | 60 | Delay between retry attempts |
| timeout_seconds | integer | 3600 | Max run duration before timeout |
The /api/tasks/agent-schedules create endpoint does not expose max_retries, retry_delay_seconds, or timeout_seconds. Agent task schedules are created with max_retries = 3, retry_delay_seconds = 60, and timeout_seconds = 3600 (1 hour). To customize these, create the task via /api/tasks/schedules with task_type: "agent_task" instead.
GET /api/tasks/schedules (the list view) returns the schema defaults 3 / 60 / 300 for max_retries, retry_delay_seconds, and timeout_seconds because the list query does not select those columns. To read the real per-task values, call GET /api/tasks/schedules/:id.
Code Examples
Create a scheduled backup task
curl -X POST https://netstacks.example.net/api/tasks/schedules \
-H "Authorization: Bearer eyJhbGciOiJIUzI1NiIs..." \
-H "Content-Type: application/json" \
-d '{
"name": "Nightly DC1 Core Backup",
"description": "Back up running configs for DC1 routers",
"task_type": "backup",
"cron_expression": "0 2 * * *",
"timezone": "America/New_York",
"parameters": {
"snapshot_name": "Nightly DC1 Core Backup",
"device_filter": { "site": "dc1", "device_type": "router" }
},
"enabled": true,
"max_retries": 2,
"retry_delay_seconds": 120,
"timeout_seconds": 1800
}'
# Response (201 Created):
# {
# "id": "a9b8c7d6-e5f4-3210-9876-543210fedcba",
# "name": "Nightly DC1 Core Backup",
# "task_type": "backup",
# "cron_expression": "0 2 * * *",
# "timezone": "America/New_York",
# "parameters": { "snapshot_name": "Nightly DC1 Core Backup",
# "device_filter": { "site": "dc1", "device_type": "router" } },
# "enabled": true,
# "max_retries": 2,
# "retry_delay_seconds": 120,
# "timeout_seconds": 1800,
# "next_run_at": "2026-03-11T07:00:00+00:00",
# "created_at": "2026-03-10T17:00:00+00:00"
# }import requests
base_url = "https://netstacks.example.net/api"
headers = {"Authorization": "Bearer eyJhbGciOiJIUzI1NiIs..."}
task = requests.post(f"{base_url}/tasks/schedules", headers=headers, json={
"name": "Nightly DC1 Core Backup",
"description": "Back up running configs for DC1 routers",
"task_type": "backup",
"cron_expression": "0 2 * * *",
"timezone": "America/New_York",
"parameters": {
"snapshot_name": "Nightly DC1 Core Backup",
"device_filter": {"site": "dc1", "device_type": "router"},
},
"enabled": True,
"max_retries": 2,
"retry_delay_seconds": 120,
"timeout_seconds": 1800,
})
task.raise_for_status()
data = task.json()
print(f"Created task {data['id']}, next run {data.get('next_run_at')}")List scheduled tasks
curl "https://netstacks.example.net/api/tasks/schedules?limit=20&offset=0" \
-H "Authorization: Bearer eyJhbGciOiJIUzI1NiIs..."
# Response (200 OK):
# {
# "tasks": [
# {
# "id": "a9b8c7d6-e5f4-3210-9876-543210fedcba",
# "name": "Nightly DC1 Core Backup",
# "task_type": "backup",
# "cron_expression": "0 2 * * *",
# "timezone": "America/New_York",
# "enabled": true,
# "last_run_at": "2026-03-10T07:00:00+00:00",
# "next_run_at": "2026-03-11T07:00:00+00:00"
# }
# ],
# "total": 5,
# "limit": 20,
# "offset": 0
# }limit is capped at 100. The list view returns the schema-default retry/timeout values; call GET /api/tasks/schedules/:id for real per-task values.
Run a task immediately
# Trigger a background execution (returns 202 Accepted)
curl -X POST https://netstacks.example.net/api/tasks/schedules/a9b8c7d6-.../run \
-H "Authorization: Bearer eyJhbGciOiJIUzI1NiIs..."
# Response (202 Accepted) — a TaskExecution record:
# {
# "id": "7c1f0e9a-2b3c-4d5e-6f70-8192a3b4c5d6",
# "task_id": "a9b8c7d6-e5f4-3210-9876-543210fedcba",
# "state": "pending",
# "triggered_by": "manual",
# "started_at": null,
# "completed_at": null,
# "output": null,
# "error_message": null,
# "retry_count": 0,
# "created_at": "2026-03-10T17:30:00+00:00"
# }A TaskExecution uses state (not status) and triggered_by (not trigger). Valid states are pending, running, completed, failed, cancelled, timeout, and approval_pending.
Toggle and delete
# Disable a task without deleting it
curl -X POST https://netstacks.example.net/api/tasks/schedules/a9b8c7d6-.../toggle \
-H "Authorization: Bearer eyJhbGciOiJIUzI1NiIs..." \
-H "Content-Type: application/json" \
-d '{"enabled": false}'
# Delete a task permanently (returns 204 No Content)
curl -X DELETE https://netstacks.example.net/api/tasks/schedules/a9b8c7d6-... \
-H "Authorization: Bearer eyJhbGciOiJIUzI1NiIs..."Update a task
PUT accepts a partial body — send only the fields you want to change. The task_type cannot be changed after creation. Changing cron_expression or timezone recomputes next_run_at.
curl -X PUT https://netstacks.example.net/api/tasks/schedules/a9b8c7d6-... \
-H "Authorization: Bearer eyJhbGciOiJIUzI1NiIs..." \
-H "Content-Type: application/json" \
-d '{
"cron_expression": "0 3 * * *",
"max_retries": 5,
"parameters": { "device_filter": { "site": "dc1" } }
}'Create an agent task schedule
# Simplified agent endpoint: pass a prompt, not a parameters object
curl -X POST https://netstacks.example.net/api/tasks/agent-schedules \
-H "Authorization: Bearer eyJhbGciOiJIUzI1NiIs..." \
-H "Content-Type: application/json" \
-d '{
"name": "Weekly Config Audit",
"description": "AI agent reviews config changes and flags anomalies",
"prompt": "Review all config snapshots from the past 7 days. Flag unauthorized changes, security policy violations, or BGP route leaks.",
"cron_expression": "0 9 * * 1",
"timezone": "America/Chicago",
"enabled": true
}'
# Response (201 Created):
# {
# "id": "b1c2d3e4-...",
# "name": "Weekly Config Audit",
# "prompt": "Review all config snapshots ...",
# "cron_expression": "0 9 * * 1",
# "timezone": "America/Chicago",
# "enabled": true,
# "last_run_at": null,
# "next_run_at": "2026-03-16T14:00:00+00:00",
# "created_at": "2026-03-10T17:00:00+00:00"
# }agent_task = requests.post(f"{base_url}/tasks/agent-schedules", headers=headers, json={
"name": "Weekly Config Audit",
"description": "AI agent reviews config changes and flags anomalies",
"prompt": "Review all config snapshots from the past 7 days. Flag anomalies.",
"cron_expression": "0 9 * * 1",
"timezone": "America/Chicago",
"enabled": True,
})
agent_task.raise_for_status()
print(f"Agent task created: {agent_task.json()['id']}")Executions & Cancellation
Each scheduled run and each manual /run creates a TaskExecution record. Its lifecycle: pending → running → completed / failed / cancelled / timeout. Some agent runs may pause at approval_pending when an approval gate is hit.
Cancel a running execution
Cancel by execution ID (the id from a /run response), not the task ID. The Controller aborts the in-flight run if it's on this node and marks the execution record cancelled so the UI reflects it. Returns 204 No Content.
curl -X POST \
https://netstacks.example.net/api/tasks/executions/7c1f0e9a-2b3c-4d5e-6f70-8192a3b4c5d6/cancel \
-H "Authorization: Bearer eyJhbGciOiJIUzI1NiIs..."
# HTTP/1.1 204 No ContentInspect agent task execution history
Agent task execution history is read through the admin-scoped agent-tasks router (requires the Admin permission). Filter by task_id to see one schedule's history.
# List recent agent task executions (limit max 100)
curl "https://netstacks.example.net/api/admin/agent-tasks/history?task_id=b1c2d3e4-...&limit=50" \
-H "Authorization: Bearer eyJhbGciOiJIUzI1NiIs..."
# Get one execution's details
curl https://netstacks.example.net/api/admin/agent-tasks/history/7c1f0e9a-... \
-H "Authorization: Bearer eyJhbGciOiJIUzI1NiIs..."
# Execution summary fields: id, task_id, task_name, state, triggered_by,
# started_at, completed_at, retry_count, created_atQuestions & Answers
- How do I create a scheduled task?
- Send
POST /api/tasks/scheduleswithname,task_type,cron_expression, an optionaltimezone(defaults to UTC), and a type-specificparametersobject. The task then runs automatically on its cron schedule. - What task types actually run?
- The schema accepts
deployment,backup,health_check,custom_script, andagent_task, but onlybackupandagent_taskhave working executors today. The other three are accepted at create time but fail when run with a "not yet implemented" error. - Where do I set retry and timeout values?
- On
/api/tasks/schedulesthey are top-level request fields:max_retries(default 3),retry_delay_seconds(default 60), andtimeout_seconds(default 3600) — not insideparameters. The agent-schedules endpoint does not expose them; it always uses 3 / 60 / 3600. - What parameters does a backup task take?
snapshot_name(defaults to the task name),device_filterwithsiteand/ordevice_typekeys (empty object means all devices), and an optionalcredential_idoverride.- Can I run a task immediately?
- Yes.
POST /api/tasks/schedules/:id/runreturns202 Acceptedwith aTaskExecutionrecord while the run proceeds in the background. - How do I cancel a run?
- Call
POST /api/tasks/executions/:id/cancelusing the execution'sid(returns204). It aborts the in-flight run if it is on the current node and marks the recordcancelled. - How do I disable a task without deleting it?
POST /api/tasks/schedules/:id/togglewith{"enabled": false}. The task stays in the system but will not fire on its schedule.
Troubleshooting
Invalid cron expression (400 Bad Request)
The expression failed validation. Use standard 5-field cron: minute hour day-of-month month day-of-week. The 6-field seconds form is not supported by the default parser.
Invalid timezone (400 Bad Request)
The timezone must be a full IANA identifier such as America/New_York or Europe/London — not abbreviations like EST or GMT.
409 Conflict (duplicate name)
A task with the same name already exists in your organization. Task names must be unique — the create endpoint returns 409 Conflict on a duplicate.
Run fails with "not yet implemented"
You scheduled a deployment, health_check, or custom_script task. Those executors are not implemented yet; the execution is marked failed. Schedule backup or agent_task instead.
Backup completes with 0 devices
The device_filter matched nothing. Check the site and device_type values against your inventory, or use an empty filter {} to target all devices. Verify reachability with the Devices API first.
Task not firing on schedule
Confirm the task is enabled (enabled: true) and that next_run_at on GET /api/tasks/schedules/:id matches your expectation in the configured timezone.
List shows wrong retry/timeout numbers
The list endpoint returns schema defaults (3 / 60 / 300) rather than the stored per-task values. Fetch a single task with GET /api/tasks/schedules/:id to read the real values.
Related Features
- API Authentication — Obtain the JWT bearer token required for every task endpoint.
- Devices API — Manage the devices that backup tasks collect configs from.
- Error Codes — Reference for 400 / 401 / 404 / 409 / 500 responses.
- Scheduled Tasks — UI guide for creating and managing scheduled tasks.
- Cron Expressions — Cron syntax reference and common patterns.
- Approvals — How agent runs reach the
approval_pendingstate.