Skip to content

REST API Problems

Ed Mozley edited this page Jul 2, 2026 · 1 revision

πŸ”΄ 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.

FreeITSM

Getting Started

Modules

Multi-tenancy (planned)

Blue sky thinking

Bugs resolved

Links

Clone this wiki locally