REST API Software - edmozley/freeitsm GitHub Wiki

๐Ÿ’ฟ REST API: Software

The complete usage guide for the Software module of the REST API โ€” the agent-collected application inventory and the licence register, with computed compliance numbers the UI doesn't have. 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 Software:

๐Ÿค– Inventory is read-only The application catalogue and per-machine installs are 100% agent-owned (the inventory agent full-syncs each host) โ€” analysts can't edit them in the UI and neither can the API. Licences are the writable half.
๐Ÿงฎ Compliance is computed for you Every licence carries app_installs (distinct non-system-component machines) next to its seat quantity, and app detail returns installs vs summed Active seats with seats_available โ€” the seats-vs-installs comparison the UI never makes. Over-deployed software is one call away.
โณ Renewal logic server-side The licence screen colours renewals client-side; the API computes renewal_status (ok / due_soon / overdue โ€” due_soon = within each licence's own notice period, default 30 days) and offers matching list filters.
๐Ÿ”‘ Legacy keys stay out This module's settings screen manages the old plaintext keys for the inventory agent/extension โ€” that's a separate, older mechanism. The REST API uses its own fitsm_โ€ฆ keys.

๐Ÿš€ Quick start

The licence-compliance question, answered in one call:

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

curl -s -H "$K" "$B/software/apps/227" | jq '.data.compliance'
# { "installs": 368, "licensed_seats": 100, "unmetered_licences": false, "seats_available": -268 }
#                                                     โ†‘ over-deployed by 268 machines

๐Ÿ’ฟ Applications (inventory โ€” read-only)

๐ŸŸข GET /software/apps ย  ๐Ÿ”‘ software_inventory.read

The application catalogue with install counts (distinct machines) and licence counts.

Parameter Description
q Search name and publisher
filter apps (non-components โ€” the UI's default tab), components, or all (default)
sort name (default), publisher, install_count, id โ€” prefix - for descending
page / per_page Pagination โ€” default 1 / 25, max 100
{ "id": 227, "name": "Microsoft Intune Management Extension", "publisher": null,
  "install_count": 368, "system_component": false, "licence_count": 1,
  "first_detected": "2026-05-10T09:12:44Z" }

๐ŸŸข GET /software/apps/{id} โ€” app + compliance ย  ๐Ÿ”‘ software_inventory.read

The app with its licences and the computed compliance block: installs (distinct non-component machines), licensed_seats (sum of Active licence quantities), seats_available (negative = over-deployed ๐Ÿ”ฅ), and unmetered_licences: true when an Active licence has no seat count (e.g. a site licence) โ€” in which case seats_available is null rather than misleading.

๐ŸŸข GET /software/apps/{id}/machines ย  ๐Ÿ”‘ software_inventory.read

Every machine it's installed on โ€” hostname, version, install date, last seen โ€” with asset_id so you can join straight to /assets/{id}.


๐Ÿ”‘ Licences

๐ŸŸข GET /software/licences ย  ๐Ÿ”‘ software_licences.read

Parameter Description
app_id Licences for one application
status e.g. Active
q Search app name, licence type and vendor contact
renewal_within_days Renewal date within N days
due_soon true = within each licence's own notice period, not yet overdue
renewal_overdue true = renewal already passed ๐Ÿ”ด
sort renewal_date (default), app, cost, created_at, id โ€” prefix - for descending
page / per_page Pagination

The licence shape:

{ "id": 19,
  "app": { "id": 227, "name": "Microsoft Intune Management Extension", "publisher": null },
  "licence_type": "Per-seat subscription", "licence_key": null,
  "quantity": 100, "app_installs": 368,
  "renewal_date": "2026-07-23", "renewal_status": "due_soon", "notice_period_days": 30,
  "portal_url": null, "cost": 2400.0, "currency": "GBP", "purchase_date": null,
  "vendor_contact": null, "notes": null, "status": "Active",
  "created_by": { "id": 1, "name": "Administrator" },
  "created_at": "2026-07-03T17:26:11Z", "updated_at": "2026-07-03T17:26:11Z" }

quantity: 100 vs app_installs: 368 โ€” your compliance report writes itself.

๐Ÿ”ต POST /software/licences ย  ๐Ÿ”‘ software_licences.create

Field Required Description
app_id โœ… The application (validated โ€” 422 on unknown)
licence_type โœ… Free text, e.g. "Per-seat subscription"
quantity Seat count โ€” omit for site/unmetered licences
renewal_date / purchase_date YYYY-MM-DD
notice_period_days Drives due_soon (default 30)
cost / currency Amount + currency (default GBP)
licence_key / portal_url / vendor_contact / notes / status Admin fields (status defaults Active)

created_by is stamped as the analyst the key acts as. Returns 201.

๐ŸŸข GET ยท ๐ŸŸ  PATCH ยท ๐Ÿ”ด DELETE /software/licences/{id} ย  ๐Ÿ”‘ software_licences.read/update/delete

Everything creatable is patchable (created_by is never touched โ€” UI parity). Delete is a clean leaf-table removal.


๐Ÿงช Worked example: monthly true-up report

A read-only key (software_inventory: read + software_licences: read):

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

# Every licensed app where installs exceed Active seats
curl -s -H "$K" "$B/software/licences?status=Active&per_page=100" \
  | jq -r '.data[] | select(.quantity != null and .app_installs > .quantity)
           | "๐Ÿ”ฅ \(.app.name): \(.app_installs) installs vs \(.quantity) seats (\(.app_installs - .quantity) over)"'

# Renewals needing action (each licence's own notice window)
curl -s -H "$K" "$B/software/licences?due_soon=true&sort=renewal_date" \
  | jq -r '.data[] | "\(.renewal_date)  \(.app.name)  \(.cost // 0) \(.currency)"'

And the procurement direction โ€” recording the true-up you just bought:

curl -s -X PATCH "$B/software/licences/19" -H "$K" -H "Content-Type: application/json" \
  -d '{"quantity": 400, "cost": 9600, "notes": "True-up July 2026 (PO-1042)."}'

Under the hood: REST API โ€” How It Works ยท Other modules: Tickets ยท Assets ยท Problems ยท Changes ยท Knowledge ยท Tasks ยท CMDB ยท Contracts ยท Calendar ยท Keys & permissions: System โ†’ API (System module) ยท Module docs: Software.