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 the task.completed workflow event; moving back to an open status clears it.
  • Tags: tags replaces 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, /move does not fire the task.completed workflow event when a card lands in Done โ€” only a status change via PATCH does. 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.