API REFERENCE
The Scheduled Tasks API
The endpoints behind the My-tasks panel. Users create tasks from chat, and these routes let your app read, mark seen, pause, or cancel them from your own UI.
A scheduled task is work the agent runs later, on its own. One-off tasks fire once at an ISO timestamp, recurring tasks fire on a 5-field cron in a named IANA timezone. Each run happens unattended as the owning user, and a successful result surfaces on their next visit. These endpoints expose the same list the widget's My-tasks panel shows.
SIGNED_IDENTITY_REQUIRED. GET carries it in the X-Era-User header (URL-encoded), POST and PATCH carry it in the JSON body, and DELETE passes it as a user_context query param.Origin header is rejected with 403 ORIGIN_NOT_ALLOWED — including a plain backend curl. Send an Origin header matching one of your allowed origins (a trailing slash on the header is stripped before comparison), or leave the allowlist empty. Every example below sends one.DATABASE_URL the task tables do not exist, so these routes return an empty list and a 404 on anything addressed by id.The task object
Every endpoint returns tasks in this shape:
| Field | Type | Description |
|---|---|---|
task_id | string | Task identifier, "sch_" followed by 12 hex characters. Pass it to update and cancel. |
instruction | string | The instruction the agent runs at fire time. |
schedule_kind | "once" | "cron" | Whether the task fires once or repeats on a cron. |
run_at | string (ISO 8601) | null | For a once task, when it fires. Null for cron. |
cron | string | For a cron task, a 5-field cron expression. Empty for once. |
timezone | string (IANA) | The zone the schedule is evaluated in, e.g. "Asia/Riyadh". Defaults to "UTC" when the task was created without one. |
status | string | One of the statuses below. |
next_run_at | string (ISO 8601) | null | The next scheduled fire time in UTC, computed from cron + timezone. Null once the task is done. |
last_run_at | string (ISO 8601) | null | When the task last fired. Null before the first run. |
run_count | int | Attempts that reached the agent, successful or not. A run that errored or timed out is counted; a run skipped for budget is not. |
max_runs | int | How many attempts a task may make before it is marked done. 0 means unlimited. |
last_result | string | null | The most recent run's output, truncated to 1000 characters. Null when there is no output, which is the case for every run that did not finish ok. |
last_run_status | string | null | Status of the most recent run: "ok", "error", "skipped_budget", or "cancelled". Null before the first run. |
last_error | string | null | Why the most recent run did not succeed, truncated to 500 characters. Null when it did. A failed run has no output, so this is the only thing that explains it. |
Status values:
| Field | Type | Description |
|---|---|---|
active | status | Waiting for its next fire time. |
paused | status | Paused by the user or your app. Resume by setting status back to "active". |
running | status | Currently executing a run. A task left here by a backend restart is reset to active on the next startup. |
done | status | A once task that has fired, or a cron task that reached max_runs. Never fires again. |
cancelled | status | Cancelled for good. You will not see this value here — the list route filters cancelled tasks out entirely. Only the console's admin view shows them. |
schedule_task, list_scheduled_tasks, update_scheduled_task, and cancel_scheduled_task. These HTTP routes are for reading and managing what already exists.List tasks
/v1/scheduled-tasksReturns the tasks owned by the user in the signed identity, newest first, plus a top-level unseen count. Cancelled tasks are excluded. Identity is carried in the X-Era-User header.
curl https://agentifys.ai/v1/scheduled-tasks \ -H "Authorization: Bearer era_your_project_key" \ -H "Origin: https://app.example.com" \ -H "X-Era-User: %7B%22id%22%3A%22u_42%22%2C%22_ts%22%3A1735689600%2C%22_sig%22%3A%22a1b2c3...%22%7D"
{
"tasks": [
{
"task_id": "sch_7a1c9e40b2d3",
"instruction": "Summarize this week's open tickets and email me.",
"schedule_kind": "cron",
"cron": "0 9 * * 1",
"run_at": null,
"timezone": "Asia/Riyadh",
"status": "active",
"next_run_at": "2026-09-07T06:00:00Z",
"last_run_at": "2026-08-31T06:00:00Z",
"run_count": 3,
"max_runs": 0,
"last_result": "6 tickets open, summary sent.",
"last_run_status": "ok",
"last_error": null
}
],
"unseen": 1
}last_result, truncated to 1000 characters, and it is overwritten on the next fire. Full history — up to 50 runs with tokens, tools used and untruncated output — exists only in the console. If your product needs to show a user their own history, store each result as you read it.| Field | Type | Description |
|---|---|---|
unseen | int | Run results the user has not acknowledged. Counts successful runs only: a run that errored, timed out or was skipped for budget never raises this number, even though it appears on the task. |
Mark results seen
/v1/scheduled-tasks/seenAcknowledges the run results so the My-tasks panel can clear its unread badge. This marks all of the user's undelivered runs seen in one call and drives the unseen count back to zero. It does not create tasks.
| Field | Type | Description |
|---|---|---|
user_contextrequired | object | The signed identity whose runs are being acknowledged. |
curl -X POST https://agentifys.ai/v1/scheduled-tasks/seen \
-H "Authorization: Bearer era_your_project_key" \
-H "Origin: https://app.example.com" \
-H "Content-Type: application/json" \
-d '{ "user_context": { "id": "u_42", "_ts": 1735689600, "_sig": "..." } }'Response, with the number of run records just marked delivered:
{ "ok": true, "marked": 1 }marked can exceed the unseen you just read. The count marks every undelivered run regardless of status, while unseen counts only successful ones. A live chat turn also marks results seen on its own: up to five unseen results are handed to the agent at the start of the turn and acknowledged at that moment, whether or not it mentions them.Pause or resume a task
/v1/scheduled-tasks/{task_id}Pauses or resumes a task. The task id goes in the path, and the body carries the new status. This is the only edit these routes support: retiming a task, or changing its cron, timezone, or max_runs, is not exposed here. Set status to "paused" to stop it firing, or "active" to resume it.
| Field | Type | Description |
|---|---|---|
user_contextrequired | object | The signed identity that owns the task. |
statusrequired | "active" | "paused" | Set "paused" to pause, or "active" to resume. |
curl -X PATCH https://agentifys.ai/v1/scheduled-tasks/sch_7a1c9e40b2d3 \
-H "Authorization: Bearer era_your_project_key" \
-H "Origin: https://app.example.com" \
-H "Content-Type: application/json" \
-d '{ "user_context": { "id": "u_42", "_ts": 1735689600, "_sig": "..." }, "status": "paused" }'{ "ok": true, "status": "paused" }Cancel a task
/v1/scheduled-tasks/{task_id}Cancels a task for good. The task id goes in the path and the signed identity is passed as a user_context query param (URL-encoded JSON). A cancelled task never fires again, and it disappears from GET /v1/scheduled-tasks rather than reappearing with status cancelled — so treat it vanishing from the list as your confirmation, not a status change you can poll for.
curl -X DELETE "https://agentifys.ai/v1/scheduled-tasks/sch_7a1c9e40b2d3?user_context=%7B%22id%22%3A%22u_42%22%2C%22_ts%22%3A1735689600%2C%22_sig%22%3A%22...%22%7D" \ -H "Authorization: Bearer era_your_project_key" \ -H "Origin: https://app.example.com"
{ "ok": true }A task id that does not exist, or that belongs to another user, returns 404 NOT_FOUND. The same is true of PATCH.
How a run ends
Every attempt writes a run record, and the task carries the latest one in last_run_status and last_error. These are the outcomes your UI has to render.
| Field | Type | Description |
|---|---|---|
ok | last_run_status | The agent turn completed. last_result holds the output and unseen goes up by one. |
error | last_run_status | The run raised, or passed the 120-second wall clock — last_error is "run timed out". run_count still increments, and a cron task advances to its next slot. |
skipped_budget | last_run_status | The project hit its monthly token budget before the run started. Nothing was spent or executed, and run_count does not increment. |
cancelled | last_run_status | The owning user no longer exists in the project. The task is cancelled, which also removes it from this list route. |
blocked | defined | Reserved for a run stopped at an unauthorised write. The current engine removes unauthorised write tools before the model sees them, so no run is recorded with this status today. |
schedule_kind: "once" that means status done with next_run_at: null. Raising the budget afterwards does not bring it back; the task has to be created again. A cron task survives the same gate and simply tries at its next slot.max_runs. run_count increments after every attempt that reached the agent, including one that errored or timed out, so a task capped at 5 that fails five times is marked done having produced nothing. Only budget skips are exempt. If you set a cap, read last_run_status before you trust run_count as a measure of work done.ok. The missing write is visible only in the text of last_result.