REST API Problems - edmozley/freeitsm GitHub Wiki

๐Ÿ”ด REST API: Problems

The complete usage guide for the Problem Management module of the REST API โ€” every URL, method, parameter and response shape. 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 Problems:

๐Ÿข Company-scoped Problems belong to a company, like tickets. A key's company scope is enforced on every list, read and write โ€” and linking an incident requires the ticket and problem to belong to the same company. Invisible on single-company installs.
๐Ÿ“’ Append-only journal Problem notes are immutable โ€” you can add and read them, never edit or delete (same as the UI).
๐Ÿ—‘๏ธ Delete is permanent Unlike tickets (trash + restore), deleting a problem is final and takes its links, notes and history with it โ€” exactly like the UI's delete.

๐Ÿš€ Quick start

Raise a problem from a monitoring correlation, link the incidents, and record the RCA:

B="https://your-server/api/v1"; K="Authorization: Bearer fitsm_โ€ฆ"

# 1. Create the problem
PRB=$(curl -s -X POST "$B/problems" -H "$K" -H "Content-Type: application/json" -d '{
  "title": "Recurring VPN drops on London office link",
  "description": "Multiple users disconnected since 28 June.",
  "priority": "High"}' | jq -r '.data.id')

# 2. Link the incidents behind it
curl -s -X POST "$B/problems/$PRB/tickets" -H "$K" -H "Content-Type: application/json" -d '{"ticket_id": 140}'

# 3. Later: record the root cause and flag the known error
curl -s -X PATCH "$B/problems/$PRB" -H "$K" -H "Content-Type: application/json" -d '{
  "status": "Root Cause Identified",
  "root_cause": "Faulty SFP on the primary switch uplink.",
  "workaround": "Failover to the secondary link.",
  "is_known_error": true}'

Every one of those steps writes the same audit entries the UI writes. ๐Ÿงพ


๐Ÿ”ด Problems

๐ŸŸข GET /problems โ€” list / search ย  ๐Ÿ”‘ problems.read

Results are limited to the key's company scope.

Parameter Description
state open | closed | all (default all)
status / status_id Filter by problem status name (e.g. Investigating) or id
priority / priority_id Filter by problem priority name or id
assigned_analyst_id Filter by assignee
is_known_error true / false โ€” the known-error database filter
company_id One company (must be in the key's scope)
q Search title and problem number (PRB-โ€ฆ)
created_since / updated_since ISO 8601 date-time bounds
sort created_at (default, desc), updated_at, closed_at, id, title, problem_number, priority, status โ€” prefix - for descending
page / per_page Pagination โ€” default 1 / 25, max per_page 100

The problem shape:

{ "id": 5, "problem_number": "PRB-00005",
  "title": "Recurring VPN drops on London office link",
  "description": "Multiple users disconnected since 28 June.",
  "status":   { "id": 3, "name": "Root Cause Identified", "is_closed": false },
  "priority": { "id": 3, "name": "High" },
  "assigned_analyst": { "id": 1, "name": "Administrator" },
  "is_known_error": true,
  "root_cause": "Faulty SFP on the primary switch uplink.",
  "workaround": "Failover to the secondary link.",
  "company": { "id": 1, "name": "Default" },
  "created_by": { "id": 1, "name": "Administrator" },
  "linked_tickets_count": 3,
  "created_at": "2026-07-02T23:14:34Z", "updated_at": "2026-07-02T23:14:54Z", "closed_at": null }

๐Ÿ”ต POST /problems โ€” create ย  ๐Ÿ”‘ problems.create

Creates a problem exactly like the UI: the PRB-##### number is stamped automatically, the module's default status applies if none is given, and a created entry is written to the audit trail. Files under the key's default company unless company_id says otherwise. Returns 201.

Field Required Description
title โœ… Problem title
description What's the problem?
status / status_id By name or id (default: the module's default status, usually New)
priority / priority_id By name or id
assigned_analyst_id Assign on creation
root_cause / workaround RCA fields
is_known_error Boolean
company_id File under a specific company (must be in the key's scope)

๐ŸŸข GET /problems/{id} โ€” get one ย  ๐Ÿ”‘ problems.read

The full problem plus its linked incidents and changes inline:

"linked_tickets": [ { "id": 140, "ticket_number": "MJI-729-47540",
                      "subject": "VPN drop โ€” J.Smith", "status": "Open",
                      "linked_at": "2026-07-02T23:15:18Z" } ],
"linked_changes": [ { "id": 42, "title": "Replace SFP on core switch",
                      "status": "Scheduled", "relation_type": "fixes" } ]

๐ŸŸ  PATCH /problems/{id} โ€” update ย  ๐Ÿ”‘ problems.update

Send only what changes; null clears nullable fields; identical PATCHes are idempotent. Every change is written to the audit trail with the same field keys the UI writes (title, status, priority, assigned_to, root_cause, workaround, known_error as Yes/No) using display names for lookups. Moving into a closed-type status sets closed_at; moving out clears it.

Field Notes
title Cannot be blanked
description null clears
status / status_id Drives closed_at via the status's is_closed flag
priority / priority_id null clears
assigned_analyst_id null unassigns
root_cause / workaround RCA fields, null clears
is_known_error Boolean

๐Ÿ”ด DELETE /problems/{id} โ€” delete ย  ๐Ÿ”‘ problems.delete

[!WARNING] Permanent. Deletes the problem and cascades its links, journal and audit trail โ€” the same as the UI's delete. There is no trash and no restore.


๐Ÿ“’ Journal & history

๐ŸŸข GET /problems/{id}/notes ย  ๐Ÿ”‘ problem_notes.read

The append-only journal, newest first.

๐Ÿ”ต POST /problems/{id}/notes ย  ๐Ÿ”‘ problem_notes.create

Field Required Description
note โœ… The note text

Attributed to the analyst the key acts as. Immutable once written โ€” no edit, no delete (parity with the UI). Returns 201.

๐ŸŸข GET /problems/{id}/audit ย  ๐Ÿ”‘ problem_audit.read

The system-generated change trail (created / modified rows), newest first:

{ "data": [ { "id": 18, "action": "modified", "field": "status",
              "old_value": "New", "new_value": "Root Cause Identified",
              "analyst": { "id": 1, "name": "Administrator" },
              "created_at": "2026-07-02T23:14:54Z" } ] }

๐Ÿ”— Linking incidents & changes

Problems sit behind incidents (the tickets reporting the symptom) and in front of changes (the fix).

๐Ÿ”ต POST /problems/{id}/tickets โ€” link an incident ย  ๐Ÿ”‘ problem_links.create

Body: {"ticket_id": 140}. Rules, all mirroring the UI:

  • The ticket must be visible to the key (its company scope) โ€” otherwise 404.
  • Same-company rule: on multi-company installs the ticket and problem must belong to the same company โ€” otherwise 422 "That incident belongs to a different company than this problem."
  • Already linked โ†’ 409.
  • Writes a linked_incident audit entry carrying the ticket number.

๐Ÿ”ด DELETE /problems/{id}/tickets/{ticket_id} โ€” unlink ย  ๐Ÿ”‘ problem_links.delete

Removes the link (no audit entry โ€” parity with the UI).

๐Ÿ”ต POST /problems/{id}/changes โ€” link a change ย  ๐Ÿ”‘ problem_links.create

Body: {"change_id": 42}. Links via the shared change-relations mechanism (relation type fixes) and writes a linked_change audit entry. Unknown change โ†’ 422; already linked โ†’ 409; installs without Change Management get a clean 422.

๐Ÿ”ด DELETE /problems/{id}/changes/{change_id} โ€” unlink ย  ๐Ÿ”‘ problem_links.delete

Removes the change link.


๐Ÿ“š Reference data

Under the shared ๐Ÿ”‘ reference.read permission:

Endpoint Returns
๐ŸŸข GET /problem-statuses Problem statuses with is_closed, is_default, colour, is_active (seeded: New, Investigating, Root Cause Identified, Known Error, Resolved, Closed)
๐ŸŸข GET /problem-priorities Problem priorities (seeded: Low, Medium, High, Critical)

๐Ÿงช Worked example: known-error database export

A read-only key (problems: read) feeds a status page or client report:

B="https://your-server/api/v1"; K="Authorization: Bearer fitsm_โ€ฆ"

# All current known errors with their workarounds
curl -s -H "$K" "$B/problems?is_known_error=true&state=open&per_page=100" \
  | jq -r '.data[] | "\(.problem_number)  \(.title)\n  Workaround: \(.workaround // "none documented")\n"'

And the monitoring direction โ€” auto-linking a new alert ticket to its open problem:

# Find the open problem for this symptom, then link the fresh incident to it
PRB=$(curl -s -H "$K" "$B/problems?q=VPN+drops&state=open" | jq -r '.data[0].id')
curl -s -X POST "$B/problems/$PRB/tickets" -H "$K" -H "Content-Type: application/json" \
  -d "{\"ticket_id\": $NEW_TICKET_ID}"

Under the hood: REST API โ€” How It Works ยท Other modules: Tickets ยท Assets ยท Keys & permissions: System โ†’ API (System module) ยท Module docs: Problem Management.