REST API Tasks - edmozley/freeitsm GitHub Wiki
โ REST API: Tasks
The complete usage guide for the Tasks (kanban) module of the REST API โ every URL, method, parameter and response shape, including moving cards on the board. Mirrors the interactive documentation at System โ API โ Documentation (with its live "Try it" tester).
[!NOTE] New to the API? The basics table on REST API: Tickets covers base URL, authentication, the response envelope, error codes, rate limits and PATCH semantics โ identical across all modules.
What's distinctive about Tasks:
| ๐ It's a board | Tasks live in status columns ordered by board_position. POST /tasks/{id}/move is the kanban drag as an API call โ target column + 0-based position, re-packed automatically. |
| ๐ช Subtasks are tasks | A subtask is just a task with parent_task_id set. Lists return top-level tasks by default (each with done/total subtask counts); pass parent_task_id=N to list a task's children. |
| ๐ Links respect company scope | A task can link to a ticket, change or contract. Ticket links are validated against the key's company scope, and a linked ticket's details only appear in responses when the key could read that ticket directly โ tighter than the UI. |
| ๐ท๏ธ Tags are curated | Task tags are a managed list (Tasks โ Settings) โ the API accepts existing names or ids and returns 422 for unknown ones rather than creating tags on the fly. |
| ๐ซ No audit trail | The product keeps no task history (comments are the closest thing) โ the API doesn't invent one. |
๐ Quick start
Create a task from a monitoring runbook and walk it across the board:
B="https://your-server/api/v1"; K="Authorization: Bearer fitsm_โฆ"
# 1. Create (lands at the end of the To Do column)
TASK=$(curl -s -X POST "$B/tasks" -H "$K" -H "Content-Type: application/json" -d '{
"title": "Renew SSL certificate for portal",
"priority": "High", "due_date": "2026-07-20",
"tags": ["Security"]}' | jq -r '.data.id')
# 2. Drag it to the top of In Progress
curl -s -X POST "$B/tasks/$TASK/move" -H "$K" -H "Content-Type: application/json" \
-d '{"status": "In Progress", "position": 0}'
# 3. Done โ completed_at stamped, task.completed workflow fires
curl -s -X PATCH "$B/tasks/$TASK" -H "$K" -H "Content-Type: application/json" -d '{"status": "Done"}'
โ Tasks
๐ข GET /tasks โ list / board feed ย ๐ tasks.read
Top-level tasks in board order by default. Every task carries its tags, subtasks: {total, done} counts and board_position โ enough to render a board.
| Parameter | Description |
|---|---|
state |
open | closed | all (default all) |
status / status_id |
One board column, by name (e.g. In Progress) or id |
priority / priority_id |
By name or id |
assigned_analyst_id / assigned_team_id |
Assignment filters ยท unassigned=true |
ticket_id ยท change_id ยท contract_id |
Tasks linked to a record |
parent_task_id |
List the subtasks of this task (default: top-level only) |
tag |
Only tasks carrying this tag (exact name) |
q |
Search title and description |
due_before / due_after |
YYYY-MM-DD bounds |
overdue |
true = open tasks past their due date โฐ |
sort |
board_position (default), created_at, updated_at, due_date, completed_at, title, id โ prefix - for descending |
page / per_page |
Pagination โ default 1 / 25, max 100 |
The task shape:
{ "id": 45, "title": "Renew SSL certificate for portal", "description": null,
"status": { "id": 2, "name": "In Progress", "is_closed": false, "colour": "#f59e0b" },
"priority": { "id": 3, "name": "High", "colour": "#f59e0b" },
"assigned_analyst": { "id": 1, "name": "Administrator" }, "assigned_team": null,
"contractor": null, "contractor_contact": null,
"start_date": null, "due_date": "2026-07-20", "estimate_hours": 4.5,
"parent_task_id": null, "ticket_id": null, "change_id": null, "contract_id": null,
"board_position": 0,
"tags": ["Security"], "subtasks": { "total": 1, "done": 0 },
"created_by": { "id": 1, "name": "Administrator" },
"created_at": "2026-07-03T12:40:44Z", "updated_at": "2026-07-03T12:41:12Z",
"completed_at": null }
estimate_hours(3.3.0) โ how long the task should take, in hours (up to two decimals, above 0, at most 9999;null= not estimated). Accepted on create and update, returned on every task.
๐ต POST /tasks โ create ย ๐ tasks.create
Only title is required. Defaults To Do / Medium; the card is appended to the end of its status column. Returns 201.
| Field | Description |
|---|---|
title โ
|
Task title |
description |
Details |
status / status_id ยท priority / priority_id |
By name or id |
assigned_analyst_id / assigned_team_id |
Assignment (both validated) |
assigned_supplier_id / assigned_contact_id |
(3.3.0) A contractor: a supplier from Contracts doing the work, and optionally a person there. The contact must work for that supplier; a contact alone brings its supplier; null clears. Setting or changing either needs the key's analyst to have Contracts (403 otherwise). Read back as contractor / contractor_contact ({id, name} or null) |
start_date / due_date |
YYYY-MM-DD |
parent_task_id |
Create as a subtask of this task |
ticket_id / change_id / contract_id |
Link to a record โ validated; ticket links must be within the key's company scope |
tags |
Array of existing tag names or ids (422 for unknown) |
๐ข GET /tasks/{id} โ get one ย ๐ tasks.read
Everything in the list shape plus parent summary, the ordered subtask_list, comments, and linked_ticket / linked_change summaries (linked-ticket details only when the key's scope allows).
๐ PATCH /tasks/{id} โ update ย ๐ tasks.update
Everything creatable is patchable; null clears. Two behaviours worth knowing:
- Closing: moving to a closed status (Done, Cancelled) stamps
completed_at(kept if already set) and fires thetask.completedworkflow event; moving back to an open status clears it. - Tags:
tagsreplaces the tag set.
๐ต POST /tasks/{id}/move โ move on the board ย ๐ tasks.update
The kanban drag as an API call:
{ "status": "In Progress", "position": 0 }
status/status_idโ target column (omit to reorder within the current one)positionโ 0-based slot in the column (omit = end)
The whole column is re-packed transactionally, so positions stay dense and ordered.
[!NOTE] Parity quirk, preserved deliberately: like the UI's drag,
/movedoes not fire thetask.completedworkflow event when a card lands in Done โ only a status change viaPATCHdoes. That's exactly how the product behaves (drag =reorder.php, edit =save.php); the API mirrors it rather than silently diverging.
๐ด DELETE /tasks/{id} โ delete ย ๐ tasks.delete
[!WARNING] Permanent, no trash. The whole subtask tree, comments and tag links are removed with it. The response reports
subtasks_deleted.
๐ฌ Comments
๐ข GET /tasks/{id}/comments ย ๐ task_comments.read
Comments oldest first, with the author.
๐ต POST /tasks/{id}/comments ย ๐ task_comments.create
Body: {"text": "โฆ"}. Attributed to the analyst the key acts as. Comments can't be edited or deleted (parity with the UI). Returns 201.
๐ Reference data
Under the shared ๐ reference.read permission:
| Endpoint | Returns |
|---|---|
๐ข GET /task-statuses |
The board columns with is_closed, colour, display_order (seeded To Do โ In Progress โ Blocked โ Done โ Cancelled) |
๐ข GET /task-priorities |
Low / Medium / High / Urgent (plus custom) |
๐ข GET /task-tags |
The curated tag list with colours and usage counts |
๐งช Worked example: sprint-bot standup report
A read-only key (tasks: read) posts a morning summary to your chat tool:
B="https://your-server/api/v1"; K="Authorization: Bearer fitsm_โฆ"
# Overdue tasks by assignee
curl -s -H "$K" "$B/tasks?overdue=true&sort=due_date&per_page=100" \
| jq -r '.data[] | "\(.due_date) \(.assigned_analyst.name // "unassigned") \(.title)"'
# Board totals per column
for s in "To Do" "In Progress" "Blocked"; do
n=$(curl -s -H "$K" "$B/tasks?status=$(echo $s | sed 's/ /+/g')" | jq '.meta.total')
echo "$s: $n"
done
And the automation direction โ a deployment pipeline creating a follow-up task with a subtask checklist:
P=$(curl -s -X POST "$B/tasks" -H "$K" -H "Content-Type: application/json" \
-d '{"title":"Post-deploy checks for release 2.4","priority":"High","due_date":"2026-07-05"}' | jq -r '.data.id')
for step in "Smoke-test portal login" "Check error rates" "Confirm backups ran"; do
curl -s -o /dev/null -X POST "$B/tasks" -H "$K" -H "Content-Type: application/json" \
-d "{\"title\": \"$step\", \"parent_task_id\": $P}"
done
Under the hood: REST API โ How It Works ยท Other modules: Tickets ยท Assets ยท Problems ยท Changes ยท Knowledge ยท Keys & permissions: System โ API (System module) ยท Module docs: Tasks.